import { solarToLunar } from 'chinese-lunar'
import memoize from 'lodash/memoize'

export const holidays = {
  // 新历假日
  gregorian: {
    '1-1': '元旦',
    '2-14': '情人节',
    '3-8': '妇女节',
    '5-1': '劳动节',
    '5-4': '青年节',
    '6-1': '儿童节',
    '7-1': '建党节',
    '8-1': '建军节',
    '9-10': '教师节',
    '10-1': '国庆节',
    // 动态节日(节气都是动态节日，暂时不展示)
    // '4-4': '清明节',
    // '12-22': '冬至',
    // '6-22': '夏至',
    '12-25': '圣诞节',
  },
  lunar: {
    '12-8': '腊八',
    '12-29-leap': '除夕',
    '12-30': '除夕',
    '1-1': '春节',
    '1-15': '元宵节',
    '5-5': '端午节',
    '7-7': '七夕',
    '8-15': '中秋节',
    '9-9': '重阳节',
  },
  byWeek: {
    '5-2-0': '母亲节',
    // 六月第三个星期日
    '6-3-0': '父亲节',
  },
}

/**
 * 获取节假日
 */
export default function getHoliday(date: Date) {
  const gregorian = `${date.getMonth() + 1}-${date.getDate()}`
  if (gregorian in holidays.gregorian) {
    return holidays.gregorian[gregorian]
  }

  // 动态节日
  const dynamicHolidays = getDynamicHoliday(date.getFullYear())
  if (gregorian in dynamicHolidays) {
    return dynamicHolidays[gregorian]
  }

  for (let key in holidays.byWeek) {
    const [month, week, day] = key.split('-').map(i => parseInt(i))
    if (month !== date.getMonth() + 1) {
      continue
    }

    if (day !== date.getDay()) {
      continue
    }

    const holiday = getNthWeek(date, week, day)
    if (holiday.getDate() === date.getDate()) {
      return holidays.byWeek[key]
    }
  }

  // 农历节假日
  const lunar = solarToLunar(date)
  let lunarKey = `${lunar.month}-${lunar.day}`
  if (lunar.leap && lunar.month === 12) {
    lunarKey += '-leap'
  }
  return holidays.lunar[lunarKey]
}

export const getDynamicHoliday = memoize((year: number) => {
  let result: { [key: string]: string } = {}
  try {
    // const dongzhi = getDongzhiForYear(year)
    // result[`12-${dongzhi}`] = '冬至'
    const qingming = getQingMingForYear(year)
    result[`4-${qingming}`] = '清明'
  } catch {
    // ignore
  }

  return result
})

export function getDongzhiForYear(year: number) {
  if (year == 2767) {
    return 23
  }
  if (year == 2227 || year == 3068) {
    return 22
  }
  if (year < 1700) {
    throw new TypeError('1700年以前暂时不支持')
  }
  if (year >= 3100) {
    throw new TypeError('3100年以后暂时不支持')
  }

  const coefficient = [
    22.11,
    22.39,
    22.66,
    21.9,
    22.18,
    22.472,
    22.72,
    21.995,
    22.27,
    22.51,
    22.75,
    22.02,
    22.27,
    22.519,
    22.8,
  ]
  const mod = year % 100
  const index = Math.trunc(year / 100 - 17)
  return Math.trunc(mod * 0.2422 + coefficient[index] - Math.trunc(mod / 4))
}

export function getQingMingForYear(year: number) {
  if (year == 2231) {
    return 23
  }
  if (year == 2227 || year == 3068) {
    return 22
  }
  if (year < 1700) {
    throw new TypeError('1700年以前暂时不支持')
  }
  if (year >= 3100) {
    throw new TypeError('3100年以后暂时不支持')
  }
  const coefficient = [
    5.15,
    5.37,
    5.59,
    4.82,
    5.02,
    5.26,
    5.48,
    4.7,
    4.92,
    5.135,
    5.36,
    4.6,
    4.81,
    5.04,
    5.26,
  ]

  const mod = year % 100
  const index = Math.trunc(year / 100 - 17)
  return Math.trunc(mod * 0.2422 + coefficient[index] - Math.trunc(mod / 4))
}

/**
 * 获取当月第N个星期*
 */
export function getNthWeek(date: Date, n: number, day: number) {
  const copy = new Date(date)
  copy.setDate(1)
  let firstDay = copy.getDay()
  // first week end
  if (firstDay > day) {
    copy.setDate(1 + 7 - (firstDay - day))
  } else {
    copy.setDate(1 + (day - firstDay))
  }

  copy.setDate(copy.getDate() + (n - 1) * 7)
  return copy
}
