/**
 * React hook for schedule calendar day availability.
 *
 * Calls `getScheduleCalendarDays` on param change, manages loading/days state.
 *
 * TZ §4.1.16.8 requires a 1-hour client cache for flight-operating-day
 * lookups. The calendar endpoint is the same conceptually (operating-day
 * bitmask for a route), so we wrap the client call with a 1h LRU cache
 * keyed on (date + departure + arrival + connections flag).
 *
 * @module
 */

import { useState, useEffect } from "react";
import { useApiClient } from "@/shared/api/provider.js";
import { ClientMemoryCache } from "@/shared/api/cache.js";
import type { ApiClient } from "@/shared/api/client.js";
import { getScheduleCalendarDays } from "../api.js";
import type { IScheduleCalendarParams } from "../types.js";

const ONE_HOUR_MS = 60 * 60 * 1000;
const daysCache = new ClientMemoryCache<string[]>({
  max: 200,
  defaultTtlMs: ONE_HOUR_MS,
});

function calendarCacheKey(p: IScheduleCalendarParams): string {
  return `${p.date}|${p.departure}|${p.arrival}|${p.connections ? 1 : 0}`;
}

async function getCachedScheduleCalendarDays(
  client: ApiClient,
  p: IScheduleCalendarParams,
): Promise<string[]> {
  const key = calendarCacheKey(p);
  const hit = daysCache.get(key);
  if (hit) return hit;
  const fresh = await getScheduleCalendarDays(client, p);
  daysCache.set(key, fresh);
  return fresh;
}

export interface UseScheduleCalendarResult {
  days: string[];
  loading: boolean;
  loaded: boolean;
}

/**
 * Hook for the calendar strip. Fetches available schedule days for the
 * given route context. Pass `null` to skip the fetch until the caller
 * has enough input to resolve a query (departure + arrival).
 */
export function useScheduleCalendar(
  params: IScheduleCalendarParams | null,
): UseScheduleCalendarResult {
  const client = useApiClient();
  const [days, setDays] = useState<string[]>([]);
  const [loading, setLoading] = useState(Boolean(params));
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    if (!params) {
      setDays([]);
      setLoading(false);
      setLoaded(false);
      return;
    }

    let cancelled = false;
    setLoading(true);
    setLoaded(false);

    getCachedScheduleCalendarDays(client, params)
      .then((result) => {
        if (!cancelled) {
          setDays(result);
          setLoading(false);
          setLoaded(true);
        }
      })
      .catch(() => {
        if (!cancelled) {
          setDays([]);
          setLoading(false);
          setLoaded(false);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [
    client,
    params?.date,
    params?.departure,
    params?.arrival,
    params?.connections,
  ]);

  return { days, loading, loaded };
}
