"use client";

import { useEffect, useState } from "react";
import type { CSSProperties } from "react";
import axiosInstance from "@/lib/axiosInstance";

// year -> { "YYYY-MM-DD": "Holiday name" }, shared by every calendar on the page
const yearCache = new Map<number, Record<string, string>>();
const inflight = new Map<number, Promise<void>>();

async function loadYears(years: number[]): Promise<Record<string, string>> {
  // Up to 2 passes: if another calendar is already fetching some of these years,
  // wait for it, then fetch whatever is still missing.
  for (let pass = 0; pass < 2; pass++) {
    const missing = years.filter((y) => !yearCache.has(y));
    if (!missing.length) break;

    const pending = missing.map((y) => inflight.get(y)).find(Boolean);
    if (pending) {
      await pending;
      continue;
    }

    // failures are NOT cached, so a later render can retry
    const request = axiosInstance
      .get(`/us-holidays?years=${missing.join(",")}`)
      .then((res) => {
        const byYear: Record<number, Record<string, string>> = {};
        for (const y of missing) byYear[y] = {};
        for (const h of res.data.data as { date: string; name: string }[]) {
          const y = Number(h.date.slice(0, 4));
          (byYear[y] ??= {})[h.date] = h.name;
        }
        for (const y of missing) yearCache.set(y, byYear[y]);
      })
      .catch(() => undefined)
      .finally(() => missing.forEach((y) => inflight.delete(y)));

    missing.forEach((y) => inflight.set(y, request));
    await request;
    break;
  }

  const merged: Record<string, string> = {};
  for (const y of years) Object.assign(merged, yearCache.get(y) ?? {});
  return merged;
}

// Returns { "YYYY-MM-DD": "Holiday name" } for every requested year.
export function useUSHolidays(years: number[]): Record<string, string> {
  const [holidays, setHolidays] = useState<Record<string, string>>({});
  const yearsKey = Array.from(new Set(years)).sort().join(",");

  useEffect(() => {
    let cancelled = false;
    const list = yearsKey ? yearsKey.split(",").map(Number) : [];
    loadYears(list).then((map) => {
      if (!cancelled) setHolidays(map);
    });
    return () => {
      cancelled = true;
    };
  }, [yearsKey]);

  return holidays;
}

// ---- shared look for holidays (inline so no existing CSS class is touched) ----
export const HOLIDAY_CELL_STYLE: CSSProperties = {
  background: "#fff4e0",
  color: "#9a5b00",
};

export const HOLIDAY_LABEL_STYLE: CSSProperties = {
  display: "inline-flex",
  justifyContent: "center",
  textAlign: "center",
  padding: "2px 4px",
  fontSize: 10,
  lineHeight: 1.15,
  fontWeight: 500,
  borderRadius: 10,
  background: "#fff4e0",
  color: "#9a5b00",
  border: "1px solid #f0c36d",
};

// [["2026-07-04", "Independence Day"], ...] for one visible month, sorted by date.
export function holidaysInMonth(holidays: Record<string, string>, year: number, monthIndex: number) {
  const prefix = `${year}-${String(monthIndex + 1).padStart(2, "0")}-`;
  return Object.entries(holidays)
    .filter(([date]) => date.startsWith(prefix))
    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
}

// "2026-07-04" -> "Jul 4"
export function formatHolidayDate(dateKey: string) {
  const [y, m, d] = dateKey.split("-").map(Number);
  return new Date(Date.UTC(y, m - 1, d)).toLocaleDateString(undefined, {
    month: "short",
    day: "numeric",
    timeZone: "UTC",
  });
}