import { DateInfo } from '../types';
import { solarToLunar, getHolidayInfo } from './lunar';

// 日期选项接口
export interface DateOptions {
  firstDayOfWeek?: number;
  selectedDate?: Date | null;
  rangeStart?: Date | null;
  rangeEnd?: Date | null;
  priceData?: Record<string, number>;
  checkInData?: Record<string, boolean>;
  disabledDate?: ((date: Date) => boolean) | null;
}

/**
 * 格式化日期为字符串
 * @param date 日期对象
 * @param format 格式字符串
 * @returns 格式化后的日期字符串
 */
export function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to formatDate');
    return '';
  }

  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();
  const hours = date.getHours();
  const minutes = date.getMinutes();
  const seconds = date.getSeconds();

  return format
    .replace(/YYYY/g, year.toString())
    .replace(/YY/g, (year % 100).toString().padStart(2, '0'))
    .replace(/MM/g, month.toString().padStart(2, '0'))
    .replace(/M/g, month.toString())
    .replace(/DD/g, day.toString().padStart(2, '0'))
    .replace(/D/g, day.toString())
    .replace(/HH/g, hours.toString().padStart(2, '0'))
    .replace(/H/g, hours.toString())
    .replace(/mm/g, minutes.toString().padStart(2, '0'))
    .replace(/m/g, minutes.toString())
    .replace(/ss/g, seconds.toString().padStart(2, '0'))
    .replace(/s/g, seconds.toString());
}

/**
 * 解析日期字符串为Date对象
 * @param dateStr 日期字符串
 * @returns Date对象
 */
export function parseDate(dateStr: string): Date {
  if (!dateStr) {
    console.warn('Empty date string provided to parseDate');
    return new Date();
  }

  // 尝试解析多种格式的日期字符串
  const date = new Date(dateStr);
  if (!isNaN(date.getTime())) {
    return date;
  }
  
  // 尝试解析 YYYY-MM-DD 格式
  const parts = dateStr.split(/[-\/]/);
  if (parts.length === 3) {
    const year = parseInt(parts[0], 10);
    const month = parseInt(parts[1], 10) - 1;
    const day = parseInt(parts[2], 10);
    const newDate = new Date(year, month, day);
    if (!isNaN(newDate.getTime())) {
      return newDate;
    }
  }
  
  // 无法解析，返回当前日期
  console.warn(`Unable to parse date string: ${dateStr}, returning current date`);
  return new Date();
}

/**
 * 获取两个日期之间的天数
 * @param start 开始日期
 * @param end 结束日期
 * @returns 天数
 */
export function getDaysBetween(start: Date, end: Date): number {
  if (!start || !end || !(start instanceof Date) || !(end instanceof Date) || 
      isNaN(start.getTime()) || isNaN(end.getTime())) {
    console.warn('Invalid date(s) provided to getDaysBetween');
    return 0;
  }

  const startDate = new Date(start.getFullYear(), start.getMonth(), start.getDate());
  const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
  const diff = endDate.getTime() - startDate.getTime();
  return Math.round(diff / (1000 * 60 * 60 * 24));
}

/**
 * 判断两个日期是否是同一天
 * @param date1 日期1
 * @param date2 日期2
 * @returns 是否同一天
 */
export function isSameDay(date1: Date | null, date2: Date | null): boolean {
  if (!date1 || !date2 || !(date1 instanceof Date) || !(date2 instanceof Date) || 
      isNaN(date1.getTime()) || isNaN(date2.getTime())) {
    return false;
  }

  return (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth() &&
    date1.getDate() === date2.getDate()
  );
}

/**
 * 判断两个日期是否是同一个月
 * @param date1 日期1
 * @param date2 日期2
 * @returns 是否同一个月
 */
export function isSameMonth(date1: Date | null, date2: Date | null): boolean {
  if (!date1 || !date2 || !(date1 instanceof Date) || !(date2 instanceof Date) || 
      isNaN(date1.getTime()) || isNaN(date2.getTime())) {
    return false;
  }

  return (
    date1.getFullYear() === date2.getFullYear() &&
    date1.getMonth() === date2.getMonth()
  );
}

/**
 * 判断日期是否在日期范围内
 * @param date 日期
 * @param start 开始日期
 * @param end 结束日期
 * @returns 是否在范围内
 */
export function isDateInRange(date: Date, start: Date, end: Date): boolean {
  if (!date || !start || !end || 
      !(date instanceof Date) || !(start instanceof Date) || !(end instanceof Date) || 
      isNaN(date.getTime()) || isNaN(start.getTime()) || isNaN(end.getTime())) {
    return false;
  }

  const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
  const startDate = new Date(start.getFullYear(), start.getMonth(), start.getDate()).getTime();
  const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate()).getTime();
  
  return targetDate >= startDate && targetDate <= endDate;
}

/**
 * 获取某月的第一天
 * @param year 年
 * @param month 月（0-11）
 * @returns 第一天的Date对象
 */
export function getFirstDayOfMonth(year: number, month: number): Date {
  return new Date(year, month, 1);
}

/**
 * 获取某月的最后一天
 * @param year 年
 * @param month 月（0-11）
 * @returns 最后一天的Date对象
 */
export function getLastDayOfMonth(year: number, month: number): Date {
  return new Date(year, month + 1, 0);
}

/**
 * 获取某月的天数
 * @param year 年
 * @param month 月（0-11）
 * @returns 天数
 */
export function getDaysInMonth(year: number, month: number): number {
  return new Date(year, month + 1, 0).getDate();
}

/**
 * 获取星期几的名称数组
 * @param firstDayOfWeek 一周的第一天（0表示周日，1表示周一）
 * @param abbreviated 是否使用缩写
 * @returns 星期几的名称数组
 */
export function getWeekDayNames(firstDayOfWeek: number = 0, abbreviated: boolean = true): string[] {
  const weekDays = abbreviated 
    ? ['日', '一', '二', '三', '四', '五', '六']
    : ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
  
  const result = [...weekDays];
  for (let i = 0; i < firstDayOfWeek; i++) {
    result.push(result.shift()!);
  }
  
  return result;
}

/**
 * 获取某个日期的详细信息
 * @param date 日期
 * @param options 选项
 * @returns 日期信息
 */
export function getDayInfo(date: Date, options: DateOptions = {}): DateInfo {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to getDayInfo');
    return {} as DateInfo;
  }

  const {
    selectedDate = null,
    priceData = {},
    checkInData = {},
    disabledDate = null
  } = options;

  const today = new Date();
  const dateStr = formatDate(date, 'YYYY-MM-DD');
  const lunarInfo = solarToLunar(date);
  const holidayInfo = getHolidayInfo(date);
  
  return {
    date,
    day: date.getDate(),
    month: date.getMonth(),
    year: date.getFullYear(),
    isCurrentMonth: true, // 默认为当前月
    isToday: isSameDay(date, today),
    isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
    isInRange: false, // 默认不在范围内
    isRangeStart: false,
    isRangeEnd: false,
    isWeekend: date.getDay() === 0 || date.getDay() === 6,
    isHoliday: holidayInfo.isHoliday !== undefined ? holidayInfo.isHoliday : !!holidayInfo.name,
    isRestDay: !!holidayInfo.isRestDay,
    isHolidayPeriod: !!holidayInfo.isHolidayPeriod,
    isCheckedIn: !!checkInData[dateStr],
    isDisabled: disabledDate ? disabledDate(date) : false,
    price: priceData[dateStr],
    lunarDay: lunarInfo?.lunarDay,
    lunarMonth: lunarInfo?.lunarMonth,
    lunarYear: lunarInfo?.lunarYear,
    lunarFestival: lunarInfo?.lunarFestival,
    solarFestival: lunarInfo?.solarFestival,
    solarTerm: lunarInfo?.solarTerm,
  };
}

/**
 * 获取某月的所有日期信息
 * @param year 年
 * @param month 月（0-11）
 * @param options 选项
 * @returns 日期信息数组
 */
export function getMonthDays(year: number, month: number, options: DateOptions = {}): DateInfo[] {
  const {
    firstDayOfWeek = 0,
    selectedDate = null,
    rangeStart = null,
    rangeEnd = null,
    priceData = {},
    checkInData = {},
    disabledDate = null
  } = options;

  const today = new Date();
  const firstDay = getFirstDayOfMonth(year, month);
  const lastDay = getLastDayOfMonth(year, month);
  const daysInMonth = getDaysInMonth(year, month);
  
  // 计算上个月需要显示的天数
  let prevMonthDays = firstDay.getDay() - firstDayOfWeek;
  if (prevMonthDays < 0) prevMonthDays += 7;
  
  // 计算下个月需要显示的天数
  const totalDaysToShow = Math.ceil((daysInMonth + prevMonthDays) / 7) * 7;
  const nextMonthDays = totalDaysToShow - daysInMonth - prevMonthDays;
  
  // 获取上个月的最后几天
  const prevMonth = month === 0 ? 11 : month - 1;
  const prevMonthYear = month === 0 ? year - 1 : year;
  const daysInPrevMonth = getDaysInMonth(prevMonthYear, prevMonth);
  
  // 获取下个月的前几天
  const nextMonth = month === 11 ? 0 : month + 1;
  const nextMonthYear = month === 11 ? year + 1 : year;
  
  const days: DateInfo[] = [];
  
  // 添加上个月的日期
  for (let i = 0; i < prevMonthDays; i++) {
    const day = daysInPrevMonth - prevMonthDays + i + 1;
    const date = new Date(prevMonthYear, prevMonth, day);
    const dateStr = formatDate(date, 'YYYY-MM-DD');
    const lunarInfo = solarToLunar(date);
    const holidayInfo = getHolidayInfo(date);
    
    days.push({
      date,
      day,
      month: prevMonth,
      year: prevMonthYear,
      isCurrentMonth: false,
      isToday: isSameDay(date, today),
      isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
      isInRange: rangeStart && rangeEnd ? isDateInRange(date, rangeStart, rangeEnd) : false,
      isRangeStart: rangeStart ? isSameDay(date, rangeStart) : false,
      isRangeEnd: rangeEnd ? isSameDay(date, rangeEnd) : false,
      isWeekend: date.getDay() === 0 || date.getDay() === 6,
      isHoliday: holidayInfo.isHoliday !== undefined ? holidayInfo.isHoliday : !!holidayInfo.name,
      isRestDay: !!holidayInfo.isRestDay,
      isHolidayPeriod: !!holidayInfo.isHolidayPeriod,
      isCheckedIn: !!checkInData[dateStr],
      isDisabled: disabledDate ? disabledDate(date) : false,
      price: priceData[dateStr],
      lunarDay: lunarInfo?.lunarDay,
      lunarMonth: lunarInfo?.lunarMonth,
      lunarYear: lunarInfo?.lunarYear,
      lunarFestival: lunarInfo?.lunarFestival,
      solarFestival: lunarInfo?.solarFestival,
      solarTerm: lunarInfo?.solarTerm,
    });
  }
  
  // 添加当前月的日期
  for (let i = 1; i <= daysInMonth; i++) {
    const date = new Date(year, month, i);
    const dateStr = formatDate(date, 'YYYY-MM-DD');
    const lunarInfo = solarToLunar(date);
    const holidayInfo = getHolidayInfo(date);
    
    days.push({
      date,
      day: i,
      month,
      year,
      isCurrentMonth: true,
      isToday: isSameDay(date, today),
      isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
      isInRange: rangeStart && rangeEnd ? isDateInRange(date, rangeStart, rangeEnd) : false,
      isRangeStart: rangeStart ? isSameDay(date, rangeStart) : false,
      isRangeEnd: rangeEnd ? isSameDay(date, rangeEnd) : false,
      isWeekend: date.getDay() === 0 || date.getDay() === 6,
      isHoliday: holidayInfo.isHoliday !== undefined ? holidayInfo.isHoliday : !!holidayInfo.name,
      isRestDay: !!holidayInfo.isRestDay,
      isHolidayPeriod: !!holidayInfo.isHolidayPeriod,
      isCheckedIn: !!checkInData[dateStr],
      isDisabled: disabledDate ? disabledDate(date) : false,
      price: priceData[dateStr],
      lunarDay: lunarInfo?.lunarDay,
      lunarMonth: lunarInfo?.lunarMonth,
      lunarYear: lunarInfo?.lunarYear,
      lunarFestival: lunarInfo?.lunarFestival,
      solarFestival: lunarInfo?.solarFestival,
      solarTerm: lunarInfo?.solarTerm,
    });
  }
  
  // 添加下个月的日期
  for (let i = 1; i <= nextMonthDays; i++) {
    const date = new Date(nextMonthYear, nextMonth, i);
    const dateStr = formatDate(date, 'YYYY-MM-DD');
    const lunarInfo = solarToLunar(date);
    const holidayInfo = getHolidayInfo(date);
    
    days.push({
      date,
      day: i,
      month: nextMonth,
      year: nextMonthYear,
      isCurrentMonth: false,
      isToday: isSameDay(date, today),
      isSelected: selectedDate ? isSameDay(date, selectedDate) : false,
      isInRange: rangeStart && rangeEnd ? isDateInRange(date, rangeStart, rangeEnd) : false,
      isRangeStart: rangeStart ? isSameDay(date, rangeStart) : false,
      isRangeEnd: rangeEnd ? isSameDay(date, rangeEnd) : false,
      isWeekend: date.getDay() === 0 || date.getDay() === 6,
      isHoliday: holidayInfo.isHoliday !== undefined ? holidayInfo.isHoliday : !!holidayInfo.name,
      isRestDay: !!holidayInfo.isRestDay,
      isHolidayPeriod: !!holidayInfo.isHolidayPeriod,
      isCheckedIn: !!checkInData[dateStr],
      isDisabled: disabledDate ? disabledDate(date) : false,
      price: priceData[dateStr],
      lunarDay: lunarInfo?.lunarDay,
      lunarMonth: lunarInfo?.lunarMonth,
      lunarYear: lunarInfo?.lunarYear,
      lunarFestival: lunarInfo?.lunarFestival,
      solarFestival: lunarInfo?.solarFestival,
      solarTerm: lunarInfo?.solarTerm,
    });
  }
  
  return days;
}

/**
 * 获取某周的所有日期信息
 * @param date 周内的某一天
 * @param options 选项
 * @returns 日期信息数组
 */
export function getWeekDays(date: Date, options: DateOptions = {}): DateInfo[] {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to getWeekDays');
    return [];
  }

  const {
    firstDayOfWeek = 0,
    selectedDate = null,
    rangeStart = null,
    rangeEnd = null,
    priceData = {},
    checkInData = {},
    disabledDate = null
  } = options;

  const today = new Date();
  const currentDay = date.getDay();
  const diff = currentDay - firstDayOfWeek;
  const adjustedDiff = diff < 0 ? diff + 7 : diff;
  const firstDayOfWeek_ = new Date(date);
  firstDayOfWeek_.setDate(date.getDate() - adjustedDiff);
  
  const days: DateInfo[] = [];
  
  for (let i = 0; i < 7; i++) {
    const currentDate = new Date(firstDayOfWeek_);
    currentDate.setDate(firstDayOfWeek_.getDate() + i);
    
    const year = currentDate.getFullYear();
    const month = currentDate.getMonth();
    const day = currentDate.getDate();
    const dateStr = formatDate(currentDate, 'YYYY-MM-DD');
    const lunarInfo = solarToLunar(currentDate);
    const holidayInfo = getHolidayInfo(currentDate);
    
    days.push({
      date: currentDate,
      day,
      month,
      year,
      isCurrentMonth: currentDate.getMonth() === date.getMonth(),
      isToday: isSameDay(currentDate, today),
      isSelected: selectedDate ? isSameDay(currentDate, selectedDate) : false,
      isInRange: rangeStart && rangeEnd ? isDateInRange(currentDate, rangeStart, rangeEnd) : false,
      isRangeStart: rangeStart ? isSameDay(currentDate, rangeStart) : false,
      isRangeEnd: rangeEnd ? isSameDay(currentDate, rangeEnd) : false,
      isWeekend: currentDate.getDay() === 0 || currentDate.getDay() === 6,
      isHoliday: holidayInfo.isHoliday !== undefined ? holidayInfo.isHoliday : !!holidayInfo.name,
      isRestDay: !!holidayInfo.isRestDay,
      isHolidayPeriod: !!holidayInfo.isHolidayPeriod,
      isCheckedIn: !!checkInData[dateStr],
      isDisabled: disabledDate ? disabledDate(currentDate) : false,
      price: priceData[dateStr],
      lunarDay: lunarInfo?.lunarDay,
      lunarMonth: lunarInfo?.lunarMonth,
      lunarYear: lunarInfo?.lunarYear,
      lunarFestival: lunarInfo?.lunarFestival,
      solarFestival: lunarInfo?.solarFestival,
      solarTerm: lunarInfo?.solarTerm,
    });
  }
  
  return days;
}

/**
 * 获取某年的所有月份信息
 * @param year 年份
 * @returns 月份信息数组
 */
export function getYearMonths(year: number): { year: number; month: number; name: string }[] {
  const months = [];
  for (let i = 0; i < 12; i++) {
    months.push({
      year,
      month: i,
      name: `${i + 1}月`
    });
  }
  return months;
}

/**
 * 获取日期范围内的所有日期
 * @param start 开始日期
 * @param end 结束日期
 * @returns 日期数组
 */
export function getDateRange(start: Date, end: Date): Date[] {
  if (!start || !end || !(start instanceof Date) || !(end instanceof Date) || 
      isNaN(start.getTime()) || isNaN(end.getTime())) {
    console.warn('Invalid date(s) provided to getDateRange');
    return [];
  }

  const dates: Date[] = [];
  const current = new Date(start);
  
  while (current <= end) {
    dates.push(new Date(current));
    current.setDate(current.getDate() + 1);
  }
  
  return dates;
}

/**
 * 添加天数到日期
 * @param date 日期
 * @param days 天数
 * @returns 新日期
 */
export function addDays(date: Date, days: number): Date {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to addDays');
    return new Date();
  }

  const result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
}

/**
 * 添加月数到日期
 * @param date 日期
 * @param months 月数
 * @returns 新日期
 */
export function addMonths(date: Date, months: number): Date {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to addMonths');
    return new Date();
  }

  const result = new Date(date);
  result.setMonth(result.getMonth() + months);
  return result;
}

/**
 * 添加年数到日期
 * @param date 日期
 * @param years 年数
 * @returns 新日期
 */
export function addYears(date: Date, years: number): Date {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to addYears');
    return new Date();
  }

  const result = new Date(date);
  result.setFullYear(result.getFullYear() + years);
  return result;
}

/**
 * 获取日期是一年中的第几周
 * @param date 日期
 * @param firstDayOfWeek 一周的第一天（0表示周日，1表示周一）
 * @returns 周数
 */
export function getWeekNumber(date: Date, firstDayOfWeek: number = 0): number {
  if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
    console.warn('Invalid date provided to getWeekNumber');
    return 0;
  }

  // 复制日期，避免修改原始日期
  const target = new Date(date.valueOf());
  const dayNr = (date.getDay() + 7 - firstDayOfWeek) % 7;
  
  // 设置为一周的第一天
  target.setDate(target.getDate() - dayNr);
  
  // 获取一月四日所在的周，这是ISO 8601标准定义的第一周
  const jan4 = new Date(target.getFullYear(), 0, 4);
  const dayDiff = (target.getTime() - jan4.getTime()) / 86400000;
  
  // 计算周数
  return Math.ceil((dayDiff + jan4.getDay() + 1) / 7);
}