/**
 * 农历日期计算工具
 * 基于寿星万年历算法
 */

// 农历数据表
export const LUNAR_INFO = [
  0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
  0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
  0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
  0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
  0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
  0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
  0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
  0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, // 1970-1979
  0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
  0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
  0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
  0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
  0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029 (2023年闰二月)
  0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
  0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
  0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
  0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
  0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
  0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
  0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
];

// 天干
const CELESTIAL_STEMS = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];

// 地支
const TERRESTRIAL_BRANCHES = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'];

// 生肖
const ZODIAC = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];

// 农历月份
const LUNAR_MONTHS = [
  '正月', '二月', '三月', '四月', '五月', '六月',
  '七月', '八月', '九月', '十月', '冬月', '腊月'
];

// 农历日期
const LUNAR_DAYS = [
  '初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十',
  '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十',
  '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十'
];

// 农历节日
const LUNAR_FESTIVALS: Record<string, string> = {
  '正月初一': '春节',
  '正月十五': '元宵节',
  '二月初二': '龙抬头',
  '五月初五': '端午节',
  '七月初七': '七夕',
  '七月十五': '中元节',
  '八月十五': '中秋节',
  '九月初九': '重阳节',
  '腊月初八': '腊八节',
  '腊月廿三': '小年',
  '腊月三十': '除夕'
};

// 公历节日
const SOLAR_FESTIVALS: Record<string, string> = {
  '01-01': '元旦',
  '02-14': '情人节',
  '03-08': '妇女节',
  '03-12': '植树节',
  '04-01': '愚人节',
  '04-05': '清明节',
  '05-01': '劳动节',
  '05-04': '青年节',
  '06-01': '儿童节',
  '07-01': '建党节',
  '08-01': '建军节',
  '09-10': '教师节',
  '10-01': '国庆节',
  '12-24': '平安夜',
  '12-25': '圣诞节'
};

// 节气
const SOLAR_TERMS = [
  '小寒', '大寒', '立春', '雨水', '惊蛰', '春分',
  '清明', '谷雨', '立夏', '小满', '芒种', '夏至',
  '小暑', '大暑', '立秋', '处暑', '白露', '秋分',
  '寒露', '霜降', '立冬', '小雪', '大雪', '冬至'
];

// 节气对应的公历日期（从1900年开始，每年的节气日期）
const SOLAR_TERM_INFO = [
  '0106', '0120', '0204', '0219', '0306', '0321', '0405', '0420', '0506', '0521', '0606', '0621',
  '0707', '0723', '0807', '0823', '0908', '0923', '1008', '1023', '1107', '1122', '1207', '1222'
];

/**
 * 计算二十四节气
 * @param date 公历日期
 * @returns 节气名称，如果不是节气日则返回空字符串
 */
function getSolarTerm(date: Date): string {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  
  // 简化处理：使用固定的节气日期（实际上节气日期每年略有不同，这里使用近似值）
  // 实际应用中可以使用更精确的天文算法或查表法
  const monthDay = `${month.toString().padStart(2, '0')}${day.toString().padStart(2, '0')}`;
  
  // 查找当前日期是否为节气
  const termIndex = SOLAR_TERM_INFO.findIndex(term => term === monthDay);
  
  if (termIndex !== -1) {
    // 计算节气对应的月份（每个月有两个节气）
    const expectedMonth = Math.floor(termIndex / 2) + 1;
    
    // 只有当节气对应的月份与当前月份匹配时，才返回节气名称
    // 这样可以确保在闰月情况下，节气仍然正确对应到公历月份
    if (expectedMonth === month) {
      return SOLAR_TERMS[termIndex];
    }
  }
  
  return '';
}

/**
 * 获取农历年的总天数
 * @param year 农历年
 * @returns 总天数
 */
function getLunarYearDays(year: number): number {
  let sum = 348;
  for (let i = 0x8000; i > 0x8; i >>= 1) {
    sum += (LUNAR_INFO[year - 1900] & i) ? 1 : 0;
  }
  return sum + getLeapMonthDays(year);
}

/**
 * 获取农历年闰月的天数
 * @param year 农历年
 * @returns 闰月天数（没有闰月返回0）
 */
function getLeapMonthDays(year: number): number {
  if (getLeapMonth(year)) {
    return (LUNAR_INFO[year - 1900] & 0x10000) ? 30 : 29;
  }
  return 0;
}

/**
 * 获取农历年闰月月份
 * @param year 农历年
 * @returns 闰月月份（没有闰月返回0）
 */
function getLeapMonth(year: number): number {
  return LUNAR_INFO[year - 1900] & 0xf;
}

/**
 * 获取农历年某月的天数
 * @param year 农历年
 * @param month 农历月
 * @returns 该月天数
 */
function getLunarMonthDays(year: number, month: number): number {
  return (LUNAR_INFO[year - 1900] & (0x10000 >> month)) ? 30 : 29;
}

/**
 * 公历日期转农历日期
 * @param date 公历日期
 * @returns 农历日期信息
 */
export function solarToLunar(date: Date): {
  lunarYear: string;
  lunarMonth: string;
  lunarDay: string;
  lunarFestival?: string;
  solarFestival?: string;
  solarTerm?: string;
} {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  
  // 参数检查
  if (year < 1900 || year > 2100) {
    return {
      lunarYear: '',
      lunarMonth: '',
      lunarDay: '',
    };
  }
  
  // 计算距离1900年1月31日的天数
  const baseDate = new Date(1900, 0, 31);
  let offset = Math.floor((date.getTime() - baseDate.getTime()) / 86400000);
  
  // 计算农历年
  let lunarYear = 1900;
  let temp = 0;
  for (let i = 1900; i < 2100 && offset > 0; i++) {
    temp = getLunarYearDays(i);
    offset -= temp;
    lunarYear++;
  }
  
  if (offset < 0) {
    offset += temp;
    lunarYear--;
  }
  
  // 计算农历月
  let isLeap = false;
  let lunarMonth = 1;
  const leapMonth = getLeapMonth(lunarYear);
  
  // 重新计算月份和日期
  // 先计算当年正常月份的天数和闰月天数
  const monthDays = [];
  let leapDays = 0;
  
  for (let i = 1; i <= 12; i++) {
    monthDays.push(getLunarMonthDays(lunarYear, i));
  }
  
  if (leapMonth > 0) {
    leapDays = getLeapMonthDays(lunarYear);
  }
  
  // 计算当前日期是农历哪一天
  let days = offset + 1;
  let currentMonth = 1;
  let isLeapMonth = false;
  
  // 遍历月份，找到对应的农历月和日
  for (let i = 1; i <= 12; i++) {
    // 处理正常月份
    let monthDay = monthDays[i - 1];
    if (days <= monthDay) {
      currentMonth = i;
      break;
    }
    days -= monthDay;
    
    // 处理闰月
    if (i === leapMonth) {
      if (days <= leapDays) {
        currentMonth = i;
        isLeapMonth = true;
        break;
      }
      days -= leapDays;
    }
  }
  
  // 更新月份和闰月标志
  lunarMonth = currentMonth;
  isLeap = isLeapMonth;
  
  // 计算农历日
  const lunarDay = days;
  
  // 生成农历年份（干支纪年）
  const cyclicalYear = (lunarYear - 1900 + 36) % 60;
  const cyclicalYearStr = CELESTIAL_STEMS[cyclicalYear % 10] + TERRESTRIAL_BRANCHES[cyclicalYear % 12];
  
  // 生成农历月份
  let lunarMonthStr = LUNAR_MONTHS[lunarMonth - 1];
  // 如果是闰月，在月份前加上"闰"字
  if (isLeap) {
    lunarMonthStr = '闰' + LUNAR_MONTHS[lunarMonth - 1];
  }
  
  // 生成农历日期
  const lunarDayStr = LUNAR_DAYS[lunarDay - 1];
 
  
  // 获取农历节日
  // 对于闰月，需要去掉"闰"字再查找节日
  const festivalKey = `${LUNAR_MONTHS[lunarMonth - 1]}${lunarDayStr}`;
  const lunarFestival = LUNAR_FESTIVALS[festivalKey];

  // 获取公历节日
  const monthDayStr = `${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
  const solarFestival = SOLAR_FESTIVALS[monthDayStr];
  
  // 获取节气
  const solarTerm = getSolarTerm(date);  
  return {
    lunarYear: `${cyclicalYearStr}年 ${ZODIAC[(lunarYear - 4) % 12]}年`,
    lunarMonth: lunarMonthStr,
    lunarDay: lunarDayStr,
    lunarFestival,
    solarFestival,
    solarTerm,
  };
}

/**
 * 获取节假日信息
 * @param date 公历日期
 * @returns 节假日信息
 */
// 节假日数据接口（模拟数据）
export interface HolidayPeriod {
  name: string;
  startDate: string; // YYYY-MM-DD
  endDate: string;   // YYYY-MM-DD
  isRestDay: boolean;
}

// 模拟节假日数据
const HOLIDAY_PERIODS: HolidayPeriod[] = [
  // 2024年节假日
  { name: '春节', startDate: '2024-02-10', endDate: '2024-02-17', isRestDay: true },
  { name: '清明节', startDate: '2024-04-04', endDate: '2024-04-06', isRestDay: true },
  { name: '劳动节', startDate: '2024-05-01', endDate: '2024-05-05', isRestDay: true },
  { name: '端午节', startDate: '2024-06-08', endDate: '2024-06-10', isRestDay: true },
  { name: '中秋节', startDate: '2024-09-15', endDate: '2024-09-17', isRestDay: true },
  { name: '国庆节', startDate: '2024-10-01', endDate: '2024-10-07', isRestDay: true },
  
  // 2024年调班工作日
  { name: '春节调班', startDate: '2024-02-04', endDate: '2024-02-04', isRestDay: false },
  { name: '春节调班', startDate: '2024-02-18', endDate: '2024-02-18', isRestDay: false },
  { name: '清明调班', startDate: '2024-04-07', endDate: '2024-04-07', isRestDay: false },
  { name: '劳动节调班', startDate: '2024-04-28', endDate: '2024-04-28', isRestDay: false },
  { name: '劳动节调班', startDate: '2024-05-11', endDate: '2024-05-11', isRestDay: false },
  { name: '中秋调班', startDate: '2024-09-14', endDate: '2024-09-14', isRestDay: false },
  { name: '国庆调班', startDate: '2024-09-29', endDate: '2024-09-29', isRestDay: false },
  { name: '国庆调班', startDate: '2024-10-12', endDate: '2024-10-12', isRestDay: false },
  
  // 2025年节假日
  { name: '元旦', startDate: '2025-01-01', endDate: '2025-01-01', isRestDay: true },
  { name: '春节', startDate: '2025-01-28', endDate: '2025-02-04', isRestDay: true },
  { name: '清明节', startDate: '2025-04-04', endDate: '2025-04-06', isRestDay: true },
  { name: '劳动节', startDate: '2025-05-01', endDate: '2025-05-05', isRestDay: true },
  { name: '端午节', startDate: '2025-05-31', endDate: '2025-06-02', isRestDay: true },
  { name: '中秋节、国庆节', startDate: '2025-10-01', endDate: '2025-10-08', isRestDay: true },
  
  // 2025年调班工作日
  { name: '春节调班', startDate: '2025-01-26', endDate: '2025-01-26', isRestDay: false },
  { name: '春节调班', startDate: '2025-02-08', endDate: '2025-02-08', isRestDay: false },
  { name: '劳动节调班', startDate: '2025-04-27', endDate: '2025-04-27', isRestDay: false },
  { name: '国庆、中秋调班', startDate: '2025-09-28', endDate: '2025-09-28', isRestDay: false },
  { name: '国庆、中秋调班', startDate: '2025-10-11', endDate: '2025-10-11', isRestDay: false },
];

/**
 * 判断日期是否在指定范围内
 * @param date 日期
 * @param startDate 开始日期
 * @param endDate 结束日期
 * @returns 是否在范围内
 */
function isDateInRange(date: Date, startDate: string, endDate: string): boolean {
  const dateStr = `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
  return dateStr >= startDate && dateStr <= endDate;
}

/**
 * 从本地缓存获取节假日数据
 * @returns 节假日数据数组
 */
export function getHolidayPeriodsFromCache(): HolidayPeriod[] {
  try {
    const cachedData = localStorage.getItem('holidayPeriods');
    if (cachedData) {
      return JSON.parse(cachedData);
    }
  } catch (error) {
    console.error('Failed to get holiday periods from cache:', error);
  }
  return HOLIDAY_PERIODS; // 如果没有缓存或解析失败，返回默认数据
}

/**
 * 保存节假日数据到本地缓存
 * @param periods 节假日数据数组
 */
export function saveHolidayPeriodsToCache(periods: HolidayPeriod[]): void {
  try {
    localStorage.setItem('holidayPeriods', JSON.stringify(periods));
  } catch (error) {
    console.error('Failed to save holiday periods to cache:', error);
  }
}

/**
 * 从外部API更新节假日数据
 * @param apiUrl API地址
 * @returns 是否更新成功的Promise
 */
export async function updateHolidayPeriodsFromApi(apiUrl: string): Promise<boolean> {
  try {
    const response = await fetch(apiUrl);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    const data = await response.json();
    
    // 验证数据格式
    if (!Array.isArray(data)) {
      throw new Error('Invalid data format: expected an array');
    }
    
    // 验证每个节假日对象的格式
    const isValidHolidayPeriod = (item: any): item is HolidayPeriod => {
      return typeof item.name === 'string' &&
             typeof item.startDate === 'string' &&
             typeof item.endDate === 'string' &&
             typeof item.isRestDay === 'boolean';
    };
    
    if (!data.every(isValidHolidayPeriod)) {
      throw new Error('Invalid data format: some items do not match the HolidayPeriod interface');
    }
    
    // 保存到缓存
    saveHolidayPeriodsToCache(data);
    return true;
  } catch (error) {
    console.error('Failed to update holiday periods from API:', error);
    return false;
  }
}

/**
 * 获取节假日信息
 * @param date 日期
 * @returns 节假日信息
 */
export function getHolidayInfo(date: Date): { name?: string; isHoliday?: boolean; isRestDay: boolean; isHolidayPeriod?: boolean } {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const weekday = date.getDay();
  
  // 周末判断
  const isWeekend = weekday === 0 || weekday === 6;
  
  // 格式化日期字符串
  const monthDayStr = `${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
  const fullDateStr = `${year}-${monthDayStr}`;
  
  // 获取公历节日
  const solarFestival = SOLAR_FESTIVALS[monthDayStr];
  
  // 获取农历信息和节日
  const lunarInfo = solarToLunar(date);
  
  // 检查是否有农历节日、公历节日或节气
  const hasFestival = !!(lunarInfo.lunarFestival || lunarInfo.solarFestival || lunarInfo.solarTerm);

  // 从缓存获取节假日数据
  const holidayPeriods = getHolidayPeriodsFromCache();
  
  // 查找当前日期是否在节假日期间
  const holidayPeriod = holidayPeriods.find(period => isDateInRange(date, period.startDate, period.endDate));
  
  // 如果在节假日期间
  if (holidayPeriod) {
    // 只显示调班信息，不显示普通节日的名称
    if (holidayPeriod.name.includes('调班')) {
      return {
        name: holidayPeriod.name,
        isHoliday: true,
        isRestDay: holidayPeriod.isRestDay,
        isHolidayPeriod:true,
      };
    } else {
      // 对于普通节假日，返回空名称但保留isHoliday标记
      return {
        name: '', // 返回空字符串
        isHoliday: true, // 显式设置isHoliday为true
        isRestDay: holidayPeriod.isRestDay,
        isHolidayPeriod:true,
      };
    }
  }
  
  
  // 如果不在节假日期间，检查是否有农历节日或公历节日
  if (hasFestival) {
    return {
      name: lunarInfo.lunarFestival || lunarInfo.solarFestival || lunarInfo.solarTerm,
      isHoliday: true,
      isRestDay: isWeekend,
      isHolidayPeriod:false,
    };
  }
  
  // 如果既不是节假日也没有节日，按照周末判断
  return {
    isHoliday: false,
    isRestDay: isWeekend,
    isHolidayPeriod: false
  };
}