import { useEffect, useState } from "react"; type Status = "idle" | "ok" | "error" | "disabled"; const HEALTH_CACHE_TTL_MS = 15_000; let cachedStatus: Status = "idle"; let cachedAt = 0; let inflightCheck: Promise | null = null; const listeners = new Set<(status: Status) => void>(); function publishStatus(status: Status) { cachedStatus = status; cachedAt = Date.now(); listeners.forEach((listener) => listener(status)); } async function requestBackendHealth(): Promise { const controller = new AbortController(); try { const response = await fetch("/api/backend/health", { signal: controller.signal }); const payload = (await response.json().catch(() => null)) as { status?: Status } | null; return payload?.status ?? "error"; } catch { return "error"; } finally { controller.abort(); } } async function ensureBackendHealthFresh(force = false): Promise { const now = Date.now(); if (!force && cachedStatus !== "idle" && now - cachedAt < HEALTH_CACHE_TTL_MS) { return cachedStatus; } if (!inflightCheck) { inflightCheck = requestBackendHealth() .then((status) => { publishStatus(status); return status; }) .finally(() => { inflightCheck = null; }); } return inflightCheck; } export function useBackendHealth() { const [status, setStatus] = useState(() => cachedStatus); useEffect(() => { let destroyed = false; const listener = (nextStatus: Status) => { if (!destroyed) { setStatus(nextStatus); } }; listeners.add(listener); void ensureBackendHealthFresh().then((nextStatus) => { if (!destroyed) { setStatus(nextStatus); } }); return () => { destroyed = true; listeners.delete(listener); }; }, []); return status; }