export type CalendarCell = {
  key: string
  date: Date
  day: number
  inMonth: boolean
  isCurrentDate: boolean
  lunarLabel: string
}

const WEEKDAY_LABELS = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']
const MONTH_LABELS = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
]

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

const LUNAR_FESTIVALS: Record<string, string> = {
  '01-01': '春节',
  '01-15': '元宵节',
  '05-05': '端午节',
  '07-07': '七夕节',
  '07-15': '中元节',
  '08-15': '中秋节',
  '09-09': '重阳节',
  '12-08': '腊八节'
}

const LUNAR_MONTH_NAMES = [
  '',
  '正月',
  '二月',
  '三月',
  '四月',
  '五月',
  '六月',
  '七月',
  '八月',
  '九月',
  '十月',
  '十一月',
  '腊月'
]

const LUNAR_DAY_NAMES = [
  '',
  '初一',
  '初二',
  '初三',
  '初四',
  '初五',
  '初六',
  '初七',
  '初八',
  '初九',
  '初十',
  '十一',
  '十二',
  '十三',
  '十四',
  '十五',
  '十六',
  '十七',
  '十八',
  '十九',
  '二十',
  '廿一',
  '廿二',
  '廿三',
  '廿四',
  '廿五',
  '廿六',
  '廿七',
  '廿八',
  '廿九',
  '三十'
]

const CURRENT_DATE_REG = /^(\d{4})-(\d{2})-(\d{2})$/
const DISPLAY_DATE_REG = /^(\d{4})-(\d{2})$/

export const getWeekdayLabels = () => WEEKDAY_LABELS

const pad = (value: number) => String(value).padStart(2, '0')

export const formatDateValue = (date: Date) =>
  `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`

export const formatDisplayValue = (date: Date) =>
  `${date.getFullYear()}-${pad(date.getMonth() + 1)}`

export const getTodayDefaults = () => {
  const today = new Date()
  return {
    currentDate: formatDateValue(today),
    displayDate: formatDisplayValue(today)
  }
}

const createDate = (year: number, month: number, day = 1) => new Date(year, month - 1, day)

export const resolveCurrentDate = (value?: string) => {
  const match = value?.match(CURRENT_DATE_REG)
  if (!match) {
    return new Date()
  }

  const year = Number(match[1])
  const month = Number(match[2])
  const day = Number(match[3])
  const date = createDate(year, month, day)

  if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
    return new Date()
  }

  return date
}

export const resolveDisplayDate = (value?: string, fallbackDate?: Date) => {
  const fallback = fallbackDate || new Date()
  const match = value?.match(DISPLAY_DATE_REG)
  if (!match) {
    return {
      year: fallback.getFullYear(),
      month: fallback.getMonth() + 1
    }
  }

  const year = Number(match[1])
  const month = Number(match[2])
  if (month < 1 || month > 12) {
    return {
      year: fallback.getFullYear(),
      month: fallback.getMonth() + 1
    }
  }

  return { year, month }
}

const getLunarMonthName = (value: string) => {
  if (!value) return ''
  if (value.includes('月')) return value
  const num = Number(value.replace(/[^\d]/g, ''))
  if (!num) return value
  return LUNAR_MONTH_NAMES[num] || value
}

const getLunarDayName = (value: string) => {
  if (!value) return ''
  if (!/^\d+$/.test(value)) return value
  const num = Number(value)
  return LUNAR_DAY_NAMES[num] || value
}

const getLunarInfo = (date: Date) => {
  try {
    const formatter = new Intl.DateTimeFormat('zh-Hans-CN-u-ca-chinese', {
      month: 'long',
      day: 'numeric'
    })
    const parts = formatter.formatToParts(date)
    const monthValue = getLunarMonthName(parts.find((item) => item.type === 'month')?.value || '')
    const dayValue = getLunarDayName(parts.find((item) => item.type === 'day')?.value || '')

    if (!monthValue || !dayValue) {
      const text = formatter.format(date)
      const match = text.match(/(闰?.+?月).*(初.|\d+)/)
      return {
        monthText: match?.[1] || '',
        dayText: getLunarDayName(match?.[2] || '')
      }
    }

    return {
      monthText: monthValue,
      dayText: dayValue
    }
  } catch {
    return {
      monthText: '',
      dayText: ''
    }
  }
}

export const getLunarLabel = (date: Date) => {
  const solarKey = `${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
  if (SOLAR_FESTIVALS[solarKey]) {
    return SOLAR_FESTIVALS[solarKey]
  }

  const lunarInfo = getLunarInfo(date)
  const nextDate = new Date(date)
  nextDate.setDate(date.getDate() + 1)
  const nextLunarInfo = getLunarInfo(nextDate)

  if (
    lunarInfo.monthText === '腊月' &&
    nextLunarInfo.monthText === '正月' &&
    nextLunarInfo.dayText === '初一'
  ) {
    return '除夕'
  }

  const monthIndex = LUNAR_MONTH_NAMES.findIndex((item) => item === lunarInfo.monthText)
  const dayIndex = LUNAR_DAY_NAMES.findIndex((item) => item === lunarInfo.dayText)
  const lunarKey = monthIndex > 0 && dayIndex > 0 ? `${pad(monthIndex)}-${pad(dayIndex)}` : ''

  if (lunarKey && LUNAR_FESTIVALS[lunarKey]) {
    return LUNAR_FESTIVALS[lunarKey]
  }

  if (lunarInfo.dayText === '初一') {
    return lunarInfo.monthText
  }

  return lunarInfo.dayText
}

export const buildCalendarCells = (displayDate?: string, currentDate?: string): CalendarCell[] => {
  const selectedDate = resolveCurrentDate(currentDate)
  const { year, month } = resolveDisplayDate(displayDate, selectedDate)

  const monthStart = createDate(year, month, 1)
  const start = new Date(monthStart)
  start.setDate(1 - monthStart.getDay())

  return Array.from({ length: 42 }).map((_, index) => {
    const date = new Date(start)
    date.setDate(start.getDate() + index)

    return {
      key: formatDateValue(date),
      date,
      day: date.getDate(),
      inMonth: date.getMonth() === monthStart.getMonth(),
      isCurrentDate: formatDateValue(date) === formatDateValue(selectedDate),
      lunarLabel: getLunarLabel(date)
    }
  })
}

export const formatTitle = (displayDate?: string, currentDate?: string) => {
  const selectedDate = resolveCurrentDate(currentDate)
  const { year, month } = resolveDisplayDate(displayDate, selectedDate)
  return `${year} ${MONTH_LABELS[month - 1]}`
}
