import { EthDateTime } from "ethiopian-calendar-date-converter"; // Ethiopian date library
import { getEnvUrl } from "@/shared/config/env";

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

/**
 * Format a UTC ISO timestamp as an Amharic-locale Ethiopian-calendar string
 * in the same shape the backend emits for `amharicCreatedAt` /
 * `amharicStartDate` (e.g. `"ግንቦት 08/2018 - 11:24 ቀን"`).
 *
 * Returns an empty string for empty input and the original string for
 * unparsable input so callers can use it as a safe fallback.
 */
export function formatAmharicDateTime(input?: string | Date | null): string {
  if (!input) return "";
  const date = input instanceof Date ? input : new Date(input);
  if (Number.isNaN(date.getTime())) {
    return typeof input === "string" ? input : "";
  }

  const eth = EthDateTime.fromEuropeanDate(date);

  // Shift UTC into Ethiopian wall-clock time (UTC+3) so we can read the
  // local hour without depending on the browser's time zone.
  const eat = new Date(date.getTime() + 3 * 60 * 60 * 1000);
  const eatHour = eat.getUTCHours();
  const eatMin = eat.getUTCMinutes();

  // 12-hour Ethiopian clock: starts at 6am = 0 (00) and counts up.
  let ethHour = (eatHour + 6) % 12;
  if (ethHour === 0) ethHour = 12;

  // Period (ጠዋት / ቀን / ምሽት / ለሊት) by local hour bucket.
  let period: string;
  if (eatHour < 6) period = "ለሊት";
  else if (eatHour < 12) period = "ጠዋት";
  else if (eatHour < 18) period = "ቀን";
  else period = "ምሽት";

  const dayStr = String(eth.date).padStart(2, "0");
  const hourStr = String(ethHour).padStart(2, "0");
  const minStr = String(eatMin).padStart(2, "0");
  const monthName = AMHARIC_MONTHS[eth.month - 1] ?? "";

  return `${monthName} ${dayStr}/${eth.year} - ${hourStr}:${minStr} ${period}`;
}

class DateService {
  static async fetchCurrentDate(): Promise<{
    formattedGregorianDate: string;
    formattedAmharicDate: string;
  }> {
    const primaryAPI = getEnvUrl("VITE_TIME_API_URL", false);
    const fallbackAPI = getEnvUrl("VITE_TIME_FALLBACK_API_URL", false);

    try {
      if (!primaryAPI) {
        throw new Error("Missing VITE_TIME_API_URL");
      }
      const data = await this.simpleFetch(primaryAPI, 5000); // 5s timeout
      return this.processDate(data);
    } catch (error: any) {
      try {
        if (!fallbackAPI) {
          throw new Error("Missing VITE_TIME_FALLBACK_API_URL");
        }
        const fallbackData = await this.simpleFetch(fallbackAPI, 5000);
        return this.processDate(fallbackData);
      } catch (fallbackError) {
        return this.processLocalDate();
      }
    }
  }

  static async simpleFetch(url: string, timeout: number): Promise<any> {
    let isTimeout = false;

    // Start a timeout
    const timeoutId = setTimeout(() => {
      isTimeout = true;
    }, timeout);

    try {
      const response = await fetch(url);
      clearTimeout(timeoutId); // Clear timeout if request succeeds

      if (isTimeout) throw new Error("Request timeout");

      if (!response.ok)
        throw new Error(`Failed to fetch: ${response.statusText}`);

      return await response.json();
    } catch (error: any) {
      throw new Error(isTimeout ? "Request timeout" : error.message);
    }
  }

  static processDate(data: any): {
    formattedGregorianDate: string;
    formattedAmharicDate: string;
  } {
    let { day, month, year, hour, minute } = data;

    // Handle fallback API response format
    if (!day && data.datetime) {
      const date = new Date(data.datetime);
      day = date.getDate();
      month = date.getMonth() + 1;
      year = date.getFullYear();
      hour = date.getHours();
      minute = date.getMinutes();
    }

    const gregorianDate = new Date(year, month - 1, day, hour, minute);
    const ethDateTime = EthDateTime.fromEuropeanDate(gregorianDate);

    return {
      formattedGregorianDate: this.formatGregorianDate(gregorianDate),
      formattedAmharicDate: this.formatAmharicDate({
        ethDateTime,
        dayOfWeek: gregorianDate.getDay(),
        ethiopianTime: this.convertToEthiopianTime(gregorianDate),
      }),
    };
  }

  static processLocalDate(): {
    formattedGregorianDate: string;
    formattedAmharicDate: string;
  } {
    const now = new Date();
    const ethDateTime = EthDateTime.fromEuropeanDate(now);

    return {
      formattedGregorianDate: this.formatGregorianDate(now),
      formattedAmharicDate: this.formatAmharicDate({
        ethDateTime,
        dayOfWeek: now.getDay(),
        ethiopianTime: this.convertToEthiopianTime(now),
      }),
    };
  }

  static convertToEthiopianTime(gregorianDate: Date): string {
    let hour = gregorianDate.getHours();
    let minute = gregorianDate.getMinutes();

    hour = (hour + 6) % 12 || 12; // Correctly convert to Ethiopian time

    const ethHour = hour.toString().padStart(2, "0");
    const ethMinute = minute.toString().padStart(2, "0");
    const isMorning =
      gregorianDate.getHours() >= 6 && gregorianDate.getHours() < 18;
    const period = isMorning ? "AM" : "PM";

    return `${ethHour}:${ethMinute} ${period}`;
  }

  static formatGregorianDate(gregorianDate: Date): string {
    return new Intl.DateTimeFormat("en-US", {
      weekday: "short",
      year: "numeric",
      month: "short",
      day: "numeric",
      hour: "numeric",
      minute: "numeric",
      hour12: true,
    }).format(gregorianDate);
  }

  static formatAmharicDate({
    ethDateTime,
    dayOfWeek,
    ethiopianTime,
  }: {
    ethDateTime: { month: number; date: number; year: number };
    dayOfWeek: number;
    ethiopianTime: string;
  }): string {
    const dayOfWeekAmharic = ["እሁድ", "ሰኞ", "ማክሰኞ", "ረቡዕ", "ሐሙስ", "ዓርብ", "ቅዳሜ"];
    const monthAmharic = [
      "መስከረም",
      "ጥቅምት",
      "ኅዳር",
      "ታኅሣሥ",
      "ጥር",
      "የካቲት",
      "መጋቢት",
      "ሚያዝያ",
      "ግንቦት",
      "ሰኔ",
      "ሐምሌ",
      "ነሃሴ",
    ];

    return `${dayOfWeekAmharic[dayOfWeek]} ${
      monthAmharic[ethDateTime.month - 1]
    } ${ethDateTime.date} ${ethDateTime.year} ${ethiopianTime} ቀን`;
  }
}

export default DateService;
