import { HolidayUtil, Solar } from 'lunar-typescript';

/**
 * 黄历信息计算工具（基于 lunar-typescript）
 * 设计说明：
 * - 中国传统节日（春节/端午/中秋等）由农历推算，公历节日（元旦/国庆等）按公历
 * - 农历文案与节日、节气三者并列返回互不覆盖：格子里农历始终显示，节日/节气展示在副行
 * - 公历节日走白名单只保留中国也在过的，纯国外节日暂时注释掉（见 SOLAR_FESTIVAL_WHITELIST）
 * - 法定节假日调休（休/班）数据由 HolidayUtil 内置，覆盖国务院历年放假安排
 * - 按「y-m-d」缓存计算结果：日历一屏 42 格、频繁切月，避免重复实例化 Solar/Lunar
 */

/** 节日条目：kind 用于差异化配色（传统农历节日红、公历现代节日橙），产品要求节日颜色不能都一样 */
export interface FestivalItem {
  kind: 'modern' | 'traditional';
  name: string;
}

/** 单日黄历信息（日历格子用） */
export interface DayAlmanac {
  /** 农历文案：初一显示月名（如「七月」），其余显示农历日（如「三十」），始终展示、不被节日覆盖 */
  lunarText: string;
  /** 当天节气（无则空串），与节日并列展示互不覆盖 */
  jieQi: string;
  /** 过滤后的节日列表：农历传统节日在前、公历现代节日在后，格子展示第一个、悬浮提示展示全部 */
  festivalItems: FestivalItem[];
  /** 完整农历日期，如「正月初一」，悬浮提示用 */
  lunarDate: string;
  /** 法定节假日安排：null=正常工作日/周末，否则含名称与是否补班 */
  holiday: null | { isWork: boolean; name: string };
}

/** 单日黄历详情（侧栏「选中日」卡片用，信息比格子更全） */
export interface DayAlmanacDetail {
  /** 星期文本，如「星期三」 */
  week: string;
  /** 完整农历日期，如「六月廿九」 */
  lunarDate: string;
  /** 干支纪年月日，如「丙午年 丙申月 庚辰日」 */
  ganZhi: string;
  /** 生肖，如「马」 */
  shengXiao: string;
  /** 黄历宜（民俗参考，侧栏氛围信息） */
  yi: string[];
  /** 黄历忌 */
  ji: string[];
}

/**
 * 公历节日白名单：只保留中国也在过的节日（法定/官方节日 + 已本土化的舶来节日）
 * 产品要求暂时屏蔽国内基本不过的国外节日，注释保留在这里，后续要恢复解开对应注释即可
 */
const SOLAR_FESTIVAL_WHITELIST = new Set([
  '元旦节',
  '情人节',
  '妇女节',
  '植树节',
  '消费者权益日',
  '劳动节',
  '青年节',
  '儿童节',
  '建党节',
  '建军节',
  '教师节',
  '国庆节',
  '母亲节',
  '父亲节',
  '平安夜',
  '圣诞节',
  // '愚人节',
  // '万圣节前夜',
  // '万圣节',
  // '感恩节',
]);

/** 计算结果缓存：跨月切换时同一天不重复计算 */
const cache = new Map<string, DayAlmanac>();

/** 详情缓存与格子缓存分开：详情仅选中日才算，字段更多没必要提前算 42 格 */
const detailCache = new Map<string, DayAlmanacDetail>();

/**
 * 获取某个公历日期的黄历信息（农历/节气/节日/法定调休）
 * @param year 公历年
 * @param month 公历月（1-12）
 * @param day 公历日
 */
export function getDayAlmanac(year: number, month: number, day: number): DayAlmanac {
  const key = `${year}-${month}-${day}`;
  const cached = cache.get(key);
  if (cached) return cached;

  const solar = Solar.fromYmd(year, month, day);
  const lunar = solar.getLunar();

  // 节日组装：农历传统节日（含除夕/下元节等民俗，都是中国节日全保留）在前，
  // 公历节日过白名单在后；solar.getOtherFestivals() 是「世界XX日」类国际纪念日，国内基本不过，整体不展示
  const festivalItems: FestivalItem[] = [
    ...[...lunar.getFestivals(), ...lunar.getOtherFestivals()].map((name) => ({
      kind: 'traditional' as const,
      name,
    })),
    ...solar
      .getFestivals()
      .filter((name) => SOLAR_FESTIVAL_WHITELIST.has(name))
      .map((name) => ({ kind: 'modern' as const, name })),
  ];

  // 初一显示月名（如「二月」），其余显示农历日（如「十五」）；农历始终展示，不再被节日/节气覆盖
  const lunarText =
    lunar.getDay() === 1 ? `${lunar.getMonthInChinese()}月` : lunar.getDayInChinese();

  const h = HolidayUtil.getHoliday(year, month, day);
  const result: DayAlmanac = {
    lunarText,
    jieQi: lunar.getJieQi(),
    festivalItems,
    lunarDate: `${lunar.getMonthInChinese()}月${lunar.getDayInChinese()}`,
    holiday: h ? { isWork: h.isWork(), name: h.getName() } : null,
  };
  cache.set(key, result);
  return result;
}

/**
 * 获取某个公历日期的黄历详情（星期/完整农历/干支/生肖/宜忌）
 * 供侧栏「选中日」卡片展示，走独立缓存避免与格子计算互相拖累
 * @param year 公历年
 * @param month 公历月（1-12）
 * @param day 公历日
 */
export function getDayAlmanacDetail(year: number, month: number, day: number): DayAlmanacDetail {
  const key = `${year}-${month}-${day}`;
  const cached = detailCache.get(key);
  if (cached) return cached;

  const solar = Solar.fromYmd(year, month, day);
  const lunar = solar.getLunar();
  const result: DayAlmanacDetail = {
    week: `星期${solar.getWeekInChinese()}`,
    lunarDate: `${lunar.getMonthInChinese()}月${lunar.getDayInChinese()}`,
    ganZhi: `${lunar.getYearInGanZhi()}年 ${lunar.getMonthInGanZhi()}月 ${lunar.getDayInGanZhi()}日`,
    shengXiao: lunar.getYearShengXiao(),
    yi: lunar.getDayYi(),
    ji: lunar.getDayJi(),
  };
  detailCache.set(key, result);
  return result;
}
