import { Injectable } from '@angular/core';
import { EthiopianDate, GregorianDate } from './models/calendar.model';

@Injectable({
  providedIn: 'root'
})
export class EthiopianCalendarService {
  // Ethiopian calendar constants
  private readonly ETHIOPIAN_MONTHS = 13;
  private readonly ETHIOPIAN_DAYS_IN_MONTH = 30;
  private readonly ETHIOPIAN_PAGUME_DAYS = 5; // 6 in leap year

  private isEthiopianLeapYear(year: number): boolean {
    return (year + 1) % 4 === 0;
  }

  private isGregorianLeapYear(year: number): boolean {
    return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
  }

  private validateEthiopianDate(date: EthiopianDate): boolean {
    if (date.month < 1 || date.month > this.ETHIOPIAN_MONTHS) return false;
    if (date.month === this.ETHIOPIAN_MONTHS) {
      const maxDays = this.isEthiopianLeapYear(date.year) ? 
        this.ETHIOPIAN_PAGUME_DAYS + 1 : 
        this.ETHIOPIAN_PAGUME_DAYS;
      return date.day >= 1 && date.day <= maxDays;
    }
    return date.day >= 1 && date.day <= this.ETHIOPIAN_DAYS_IN_MONTH;
  }

  toGregorian(ethiopianDate: EthiopianDate): GregorianDate {
    if (!this.validateEthiopianDate(ethiopianDate)) {
      throw new Error('Invalid Ethiopian date');
    }

    let { year, month, day } = ethiopianDate;
    
    // Calculate the number of days from Ethiopian new year to the given date
    let daysDiff = (month - 1) * this.ETHIOPIAN_DAYS_IN_MONTH + day;
    
    // Basic conversion (Ethiopian new year is typically September 11/12)
    let gregorianYear = year + 7;
    let gregorianMonth = 9; // September
    let gregorianDay = 10; // Start from September 10

    // Adjust for Ethiopian leap year
    if (this.isEthiopianLeapYear(year)) {
      gregorianDay += 1;
    }

    // Add the difference in days
    gregorianDay += daysDiff;

    // Adjust the Gregorian date
    const gregorianMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (this.isGregorianLeapYear(gregorianYear)) {
      gregorianMonthDays[1] = 29;
    }

    // Adjust month and day
    while (gregorianDay > gregorianMonthDays[gregorianMonth - 1]) {
      gregorianDay -= gregorianMonthDays[gregorianMonth - 1];
      gregorianMonth++;
      if (gregorianMonth > 12) {
        gregorianMonth = 1;
        gregorianYear++;
        if (this.isGregorianLeapYear(gregorianYear)) {
          gregorianMonthDays[1] = 29;
        } else {
          gregorianMonthDays[1] = 28;
        }
      }
    }

    return {
      year: gregorianYear,
      month: gregorianMonth,
      day: gregorianDay
    };
  }

  toEthiopian(gregorianDate: GregorianDate): EthiopianDate {
    let { year, month, day } = gregorianDate;
    
    // Find the Ethiopian year
    let ethiopianYear = year - 8;
    
    // Calculate days from Ethiopian new year (September 11/12)
    const gregorianMonthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (this.isGregorianLeapYear(year)) {
      gregorianMonthDays[1] = 29;
    }

    // Calculate the Ethiopian date
    let ethiopianMonth = 1;
    let ethiopianDay = 1;
    
    // Adjust based on the Gregorian date
    if (month > 9 || (month === 9 && day > 11)) {
      ethiopianYear++;
    }

    // Calculate days from Ethiopian new year
    let daysDiff = 0;
    if (month > 9) {
      // Add days from September to current month
      for (let m = 9; m < month; m++) {
        daysDiff += gregorianMonthDays[m - 1];
      }
      daysDiff += day - 11;
    } else if (month < 9) {
      // Add remaining days from September to December
      for (let m = 9; m <= 12; m++) {
        daysDiff += gregorianMonthDays[m - 1];
      }
      // Add days from January to current month
      for (let m = 1; m < month; m++) {
        daysDiff += gregorianMonthDays[m - 1];
      }
      daysDiff += day - 11;
    } else {
      // September
      daysDiff = day - 11;
    }

    // Convert days difference to Ethiopian date
    ethiopianMonth = Math.floor(daysDiff / 30) + 1;
    ethiopianDay = (daysDiff % 30) + 1;

    return {
      year: ethiopianYear,
      month: ethiopianMonth,
      day: ethiopianDay
    };
  }

  // Helper method to format dates
  formatDate(date: EthiopianDate | GregorianDate, isEthiopian: boolean = true): string {
    const { year, month, day } = date;
    return `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}${
      isEthiopian ? ' (Ethiopian)' : ' (Gregorian)'
    }`;
  }
} 