import { EthDateTime } from "ethiopian-calendar-date-converter";

export interface HabeshaDate {
  year: number;
  month: number;
  day: number;
  monthName: string;
  dayName: string;
  formatted: string;
}

export class HabeshaCalendarUtils {
  // Ethiopian month names in Amharic
  static readonly MONTH_NAMES_AM = [
    "መስከረም",
    "ጥቅምት",
    "ኅዳር",
    "ታኅሣሥ",
    "ጥር",
    "የካቲት",
    "መጋቢት",
    "ሚያዝያ",
    "ግንቦት",
    "ሰኔ",
    "ሐምሌ",
    "ነሃሴ",
    "ጳጉሜ",
  ];

  // Ethiopian month names in English
  static readonly MONTH_NAMES_EN = [
    "Meskerem",
    "Tikimt",
    "Hidar",
    "Tahsas",
    "Tir",
    "Yekatit",
    "Megabit",
    "Miazia",
    "Ginbot",
    "Sene",
    "Hamle",
    "Nehase",
    "Pagume",
  ];

  // Day names in Amharic
  static readonly DAY_NAMES_AM = [
    "እሁድ",
    "ሰኞ",
    "ማክሰኞ",
    "ረቡዕ",
    "ሐሙስ",
    "ዓርብ",
    "ቅዳሜ",
  ];

  // Day names in English
  static readonly DAY_NAMES_EN = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
  ];

  /**
   * Convert Gregorian date to Habesha date
   */
  static gregorianToHabesha(
    gregorianDate: Date | string | null | undefined
  ): HabeshaDate {
    // Handle null/undefined cases
    if (!gregorianDate) {
      gregorianDate = new Date();
    }

    // Convert string to Date if needed
    if (typeof gregorianDate === "string") {
      gregorianDate = new Date(gregorianDate);
    }

    // Validate that we have a valid Date object
    if (!(gregorianDate instanceof Date) || isNaN(gregorianDate.getTime())) {
      gregorianDate = new Date();
    }

    const ethDateTime = EthDateTime.fromEuropeanDate(gregorianDate);
    const dayOfWeek = gregorianDate.getDay();

    return {
      year: ethDateTime.year,
      month: ethDateTime.month,
      day: ethDateTime.date,
      monthName: this.MONTH_NAMES_AM[ethDateTime.month - 1],
      dayName: this.DAY_NAMES_AM[dayOfWeek],
      formatted: this.formatHabeshaDate(ethDateTime, dayOfWeek),
    };
  }

  /**
   * Convert Habesha date to Gregorian date
   */
  static habeshaToGregorian(year: number, month: number, day: number): Date {
    const ethDateTime = new EthDateTime(year, month, day);
    return ethDateTime.toEuropeanDate();
  }

  /**
   * Format Habesha date as string
   */
  static formatHabeshaDate(
    ethDateTime: { year: number; month: number; date: number },
    dayOfWeek: number,
    includeDay: boolean = true
  ): string {
    const dayName = includeDay ? `${this.DAY_NAMES_AM[dayOfWeek]} ` : "";
    const monthName = this.MONTH_NAMES_AM[ethDateTime.month - 1];

    return `${dayName}${monthName} ${ethDateTime.date}, ${ethDateTime.year}`;
  }

  /**
   * Get current Habesha date
   */
  static getCurrentHabeshaDate(): HabeshaDate {
    return this.gregorianToHabesha(new Date());
  }

  /**
   * Generate year options for dropdowns (Habesha years)
   */
  static generateHabeshaYearOptions(
    yearsBack: number = 5,
    yearsAhead: number = 5
  ): Array<{ label: string; value: string }> {
    const currentHabesha = this.getCurrentHabeshaDate();
    const startYear = currentHabesha.year - yearsBack;
    const endYear = currentHabesha.year + yearsAhead;

    const years = [];
    for (let year = startYear; year <= endYear; year++) {
      years.push({
        label: year.toString(),
        value: year.toString(),
      });
    }

    return years.reverse(); // Most recent first
  }

  /**
   * Generate month options for dropdowns
   */
  static getMonthOptions(
    language: "am" | "en" = "am"
  ): Array<{ label: string; value: string }> {
    const monthNames =
      language === "am" ? this.MONTH_NAMES_AM : this.MONTH_NAMES_EN;

    return monthNames.map((name, index) => ({
      label: name,
      value: (index + 1).toString(),
    }));
  }

  /**
   * Get days in a Habesha month
   */
  static getDaysInHabeshaMonth(year: number, month: number): number {
    // Most months have 30 days, Pagume (13th month) has 5 or 6 days
    if (month === 13) {
      // Leap year calculation for Ethiopian calendar
      return this.isHabeshaLeapYear(year) ? 6 : 5;
    }
    return 30;
  }

  /**
   * Check if a Habesha year is a leap year
   */
  static isHabeshaLeapYear(year: number): boolean {
    // Ethiopian leap year calculation
    return year % 4 === 3;
  }

  /**
   * Parse date string in various formats to Habesha date
   */
  static parseHabeshaDate(dateString: string): HabeshaDate | null {
    try {
      // Try to parse as ISO string first, then convert
      const gregorianDate = new Date(dateString);
      if (!isNaN(gregorianDate.getTime())) {
        return this.gregorianToHabesha(gregorianDate);
      }
      return null;
    } catch {
      return null;
    }
  }

  /**
   * Format date for display in forms
   */
  static formatForDisplay(
    date: Date | string | null | undefined,
    language: "am" | "en" = "am"
  ): string {
    // Handle null/undefined cases
    if (!date) {
      date = new Date();
    }

    // Convert string to Date if needed
    let gregorianDate: Date;
    if (typeof date === "string") {
      gregorianDate = new Date(date);
    } else {
      gregorianDate = date;
    }

    // Validate that we have a valid Date object
    if (!(gregorianDate instanceof Date) || isNaN(gregorianDate.getTime())) {
      gregorianDate = new Date();
    }

    const habeshaDate = this.gregorianToHabesha(gregorianDate);

    if (language === "en") {
      const monthName = this.MONTH_NAMES_EN[habeshaDate.month - 1];
      const dayName = this.DAY_NAMES_EN[gregorianDate.getDay()];
      return `${dayName} ${monthName} ${habeshaDate.day}, ${habeshaDate.year}`;
    }

    return habeshaDate.formatted;
  }

  /**
   * Get date range in Habesha calendar
   */
  static getHabeshaDateRange(
    startDate: Date,
    endDate: Date
  ): {
    start: HabeshaDate;
    end: HabeshaDate;
    formatted: string;
  } {
    const start = this.gregorianToHabesha(startDate);
    const end = this.gregorianToHabesha(endDate);

    return {
      start,
      end,
      formatted: `${start.formatted} - ${end.formatted}`,
    };
  }
}

export default HabeshaCalendarUtils;
