import dayjs, { Dayjs, type ConfigType } from '../utils/dayjs';
import { wrapDate } from '../utils';
import {
  SOLAR_TERMS_C_NUMS,
  SOLAR_TERMS_DELTA,
  SOLAR_TERMS_MONTH,
  SOLAR_TERMS,
  type SolarTermKey,
} from './constants';

/* 获取节气日期 */
const getSolarTermDate = (
  year: number,
  month: number,
  term: SolarTermKey
): string => {
  const century = year >= 2000 ? 21 : 20;
  const Y = year % 100;
  const D = 0.2422;
  const C = SOLAR_TERMS_C_NUMS[term][century === 21 ? 1 : 0];
  let L = Math.floor(Y / 4);

  if (
    [
      'lesser_cold',
      'greater_cold',
      'the_beginning_of_spring',
      'rain_water',
    ].includes(term)
  ) {
    L = Math.floor((Y - 1) / 4);
  }

  let day = Math.floor(Y * D + C) - L;
  const delta =
    SOLAR_TERMS_DELTA[`${year}_${term}` as keyof typeof SOLAR_TERMS_DELTA];
  if (delta) {
    day += delta;
  }

  return dayjs(`${year}-${month}-${day}`).format('YYYY-MM-DD');
};

export interface SolarTerm {
  date: string;
  term: SolarTermKey;
  name: string;
  index?: number;
}

/**
 * 获取指定日期范围内的节气（仅节气当日）
 * @param start 开始日期
 * @param end 不传只查当天
 * @returns Array of solar terms => 节气开始日数组
 */
const getSolarTerms = (start?: ConfigType, end?: ConfigType): SolarTerm[] => {
  const result: SolarTerm[] = [];
  let current = wrapDate(start);
  const endDate = wrapDate(end || start);

  while (current.isBefore(endDate) || current.isSame(endDate)) {
    const year = current.year();
    const month = current.month() + 1;

    SOLAR_TERMS_MONTH[month].forEach((term: SolarTermKey) => {
      const solarTermDate = dayjs(getSolarTermDate(year, month, term));
      if (
        (solarTermDate?.isBefore(endDate) || solarTermDate?.isSame(endDate)) &&
        (solarTermDate?.isAfter(current) || solarTermDate?.isSame(current))
      ) {
        result.push({
          date: solarTermDate.format('YYYY-MM-DD'),
          term,
          name: SOLAR_TERMS[term],
          index: 1,
        });
      }
    });

    /* 处理下个日期 */
    current =
      month === 12
        ? current.add(1, 'year').startOf('year')
        : current.add(1, 'month').startOf('month');
  }

  return result;
};

/**
 * 获取指定日期范围内的所有每日节气信息
 * @param start 开始日期
 * @param end 不传只查当天
 * @returns Array of solar terms => 节气日数组
 */
const getSolarTermsInRange = (
  start?: ConfigType,
  end?: ConfigType
): SolarTerm[] => {
  // 从开始日减一个月 - 结束日下一个月 计算所有节气
  let current = wrapDate(start).subtract(1, 'month');
  const endDate = wrapDate(end || start).add(1, 'month');
  const allTerms: { term: SolarTermKey; date: Dayjs }[] = [];
  while (current.isBefore(endDate) || current.isSame(endDate)) {
    const year = current.year();
    const month = current.month() + 1;
    SOLAR_TERMS_MONTH[month].forEach((term: SolarTermKey) => {
      const solarTermDate = dayjs(getSolarTermDate(year, month, term));
      allTerms.push({ term, date: solarTermDate });
    });
    if (current.month() === 11) {
      current = current.add(1, 'year').startOf('year');
    } else {
      current = current.add(1, 'month').startOf('month');
    }
  }

  // 计算中间的所有日期
  const deltaDays: (Omit<SolarTerm, 'date'> & { day: Dayjs })[] = [];
  allTerms.forEach((term, index) => {
    for (
      let date = term.date;
      allTerms[index + 1] && date.isBefore(allTerms[index + 1].date);
      date = date.add(1, 'day')
    ) {
      deltaDays.push({
        day: date,
        term: term.term,
        name: SOLAR_TERMS[term.term],
        index: date.diff(term.date, 'day') + 1,
      });
    }
  });

  if (!end) end = start;
  return deltaDays
    .filter(trem => trem.day.isBetween(start, end, 'day'))
    .map(trem => ({
      date: trem.day.format('YYYY-MM-DD'),
      term: trem.term,
      name: trem.name,
      index: trem.index,
    }));
};

export { getSolarTermDate, getSolarTerms, getSolarTermsInRange };
