/**
 * Ethiopian Calendar Utilities
 * Converts between Gregorian and Ethiopian calendars
 */

export interface EthiopianDate {
  year: number;
  month: number;
  day: number;
}

export const ETHIOPIAN_MONTHS = [
  'መስከረም',
  'ጥቅምት',
  'ኅዳር',
  'ታኅሣሥ',
  'ጥር',
  'የካቲት',
  'መጋቢት',
  'ሚያዝያ',
  'ግንቦት',
  'ሰኔ',
  'ሐምሌ',
  'ነሐሴ',
  'ጳጉሜ',
];

/**
 * Convert Gregorian date to Ethiopian date
 * Ethiopian calendar is 7-8 years behind Gregorian
 * Ethiopian New Year is September 11 (or 12 in leap years)
 */
export function gregorianToEthiopian(date: Date): EthiopianDate {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();

  // Calculate JDN for Gregorian date
  const a = Math.floor((14 - month) / 12);
  const y = year + 4800 - a;
  const m = month + 12 * a - 3;
  const jdn = day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;

  // Convert JDN to Ethiopian calendar
  // Ethiopian epoch: August 29, 8 CE (Gregorian) = Meskerem 1, 1 (Ethiopian)
  const ethEpoch = 1723856;
  const ethElapsed = jdn - ethEpoch;
  
  // Calculate the 4-year cycle (1461 days)
  const quadYear = Math.floor(ethElapsed / 1461);
  const quadRemainder = ethElapsed % 1461;
  
  // Calculate year within the 4-year cycle
  const yearInCycle = Math.floor(quadRemainder / 365);
  const dayInYear = quadRemainder % 365;
  
  // Calculate Ethiopian year (subtract 1 to correct the offset)
  const ethYear = quadYear * 4 + yearInCycle;
  
  // Calculate month and day (12 months of 30 days + Pagume)
  const ethMonth = Math.floor(dayInYear / 30) + 1;
  const ethDay = (dayInYear % 30) + 1;

  return { year: ethYear, month: ethMonth, day: ethDay };
}

/**
 * Convert Ethiopian date to Gregorian date
 */
export function ethiopianToGregorian(ethDate: EthiopianDate): Date {
  const { year: ethYear, month: ethMonth, day: ethDay } = ethDate;

  // Ethiopian calendar epoch
  const ethEpoch = 1723856;
  
  // Calculate days since epoch
  const quadYear = Math.floor(ethYear / 4);
  const yearInCycle = ethYear % 4;
  const dayInYear = (ethMonth - 1) * 30 + (ethDay - 1);
  
  // Calculate JDN from Ethiopian date
  const jdn = ethEpoch + quadYear * 1461 + yearInCycle * 365 + dayInYear;

  // Convert JDN to Gregorian date
  const a = jdn + 32044;
  const b = Math.floor((4 * a + 3) / 146097);
  const c = a - Math.floor((146097 * b) / 4);
  const d = Math.floor((4 * c + 3) / 1461);
  const e = c - Math.floor((1461 * d) / 4);
  const m = Math.floor((5 * e + 2) / 153);
  
  const day = e - Math.floor((153 * m + 2) / 5) + 1;
  const month = m + 3 - 12 * Math.floor(m / 10);
  const year = 100 * b + d - 4800 + Math.floor(m / 10);

  return new Date(year, month - 1, day);
}

/**
 * Get day of year from date (1-366)
 */
export function getDayOfYear(date: Date): number {
  const start = new Date(date.getFullYear(), 0, 0);
  const diff = date.getTime() - start.getTime();
  const oneDay = 1000 * 60 * 60 * 24;
  return Math.floor(diff / oneDay);
}

/**
 * Convert day of year to Date object
 */
export function dayOfYearToDate(year: number, dayOfYear: number): Date {
  const date = new Date(year, 0);
  date.setDate(dayOfYear);
  return date;
}

/**
 * Format Ethiopian date as string
 */
export function formatEthiopianDate(ethDate: EthiopianDate): string {
  const monthName = ETHIOPIAN_MONTHS[ethDate.month - 1] || 'Unknown';
  return `${monthName} ${ethDate.day}, ${ethDate.year}`;
}

/**
 * Get days in Ethiopian month
 */
export function getDaysInEthiopianMonth(year: number, month: number): number {
  if (month <= 12) {
    return 30;
  } else {
    // Pagume has 5 days normally, 6 days on Ethiopian leap year
    return isEthiopianLeapYear(year) ? 6 : 5;
  }
}

/**
 * Check if Ethiopian year is leap year
 * Ethiopian leap year: the year where Pagume has 6 days
 * This occurs when (year % 4) === 3
 */
export function isEthiopianLeapYear(year: number): boolean {
  // Ethiopian leap years: 3, 7, 11, 15, 19, 23, etc.
  return (year % 4) === 3;
}
