'use client';

/**
 * useSentinelData — the single data entry point for every Executive screen.
 *
 * Today it serves the typed mock (USE_MOCK). When the `/api/reports/executive`
 * route is normalized to the SentinelData shape (see the redesign plan), flip
 * USE_MOCK to false — nothing in the screens changes, because they only ever
 * see `SentinelData`. `cycle` is bumped on every successful load so screens can
 * use it as a React key to replay count-up / draw-in entrance animations
 * (mirrors the prototype's "cycle" bump on refresh).
 */
import { useCallback, useEffect, useRef, useState } from 'react';
import type { SentinelData } from './types';
import { MOCK_SENTINEL_DATA } from './mock-data';
import { fetchJsonWithTimeout } from './fetch-with-timeout';

const USE_MOCK = false;

// A wedged /api/reports/executive build must reject (→ error state) rather
// than leave the NOC/executive screens blank indefinitely. 30s (not 15s)
// because the report's 30/60/365-day aggregate scans currently run against a
// raw Heartbeat table that has grown well past its ~7-day retention window
// (retention/rollup prune not running), so a COLD build can take ~15s over a
// WAN DB link. The 60s server-side cache + 30s auto-refresh keep it warm after
// the first load, so this ceiling only bites the initial cold fetch. The real
// fix is running retention so raw shrinks and cold builds drop to ~1-2s.
const FETCH_TIMEOUT_MS = 30000;

async function fetchSentinelData(): Promise<SentinelData> {
    if (USE_MOCK) {
        return { ...MOCK_SENTINEL_DATA, lastUpdated: new Date().toISOString() };
    }
    return fetchJsonWithTimeout<SentinelData>('/api/reports/executive', FETCH_TIMEOUT_MS);
}

export interface UseSentinelData {
    data: SentinelData | null;
    loading: boolean;
    refreshing: boolean;
    error: string | null;
    lastUpdated: string | null;
    /** Incremented on each successful load; use as a key to replay animations. */
    cycle: number;
    refresh: () => void;
}

export function useSentinelData(options?: { autoRefreshMs?: number }): UseSentinelData {
    const [data, setData] = useState<SentinelData | null>(USE_MOCK ? MOCK_SENTINEL_DATA : null);
    const [loading, setLoading] = useState(!USE_MOCK);
    const [refreshing, setRefreshing] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const [cycle, setCycle] = useState(0);
    const mounted = useRef(true);

    const load = useCallback(async (manual: boolean) => {
        if (manual) setRefreshing(true);
        try {
            const next = await fetchSentinelData();
            if (!mounted.current) return;
            setData(next);
            setError(null);
            setCycle((c) => c + 1);
        } catch (e) {
            if (!mounted.current) return;
            setError(e instanceof Error ? e.message : 'Failed to load');
        } finally {
            if (!mounted.current) return;
            setLoading(false);
            setRefreshing(false);
        }
    }, []);

    useEffect(() => {
        mounted.current = true;
        load(false);
        return () => {
            mounted.current = false;
        };
    }, [load]);

    useEffect(() => {
        const ms = options?.autoRefreshMs;
        if (!ms) return;
        const id = setInterval(() => load(true), ms);
        return () => clearInterval(id);
    }, [options?.autoRefreshMs, load]);

    const refresh = useCallback(() => {
        load(true);
    }, [load]);

    return {
        data,
        loading,
        refreshing,
        error,
        lastUpdated: data?.lastUpdated ?? null,
        cycle,
        refresh,
    };
}
