import { useEffect, useRef, useState } from "react";
import { getDeltaWs, type ConnectionState, type TickerUpdate } from "@/lib/delta-ws";

export interface TickerState {
  symbol: string;
  price: number;
  bid?: number;
  ask?: number;
  spread_bps?: number;
  mark_price?: number;
  last_price?: number;
  change24h?: number;
  volume24h?: number;
  flash?: "up" | "down";
  lastUpdate: number;
  stale?: boolean;
  source?: "ticker" | "l1" | "mark" | "rest";
}


/**
 * Subscribes to Delta public tickers for the given symbols and returns a
 * `{symbol: TickerState}` map that updates in place. Also exposes the
 * connection state so the UI can render a health indicator.
 */
export function useDeltaTickers(symbols: string[]) {
  const [tickers, setTickers] = useState<Record<string, TickerState>>({});
  const [connection, setConnection] = useState<{ state: ConnectionState; attempt: number; lastMessageAt: number | null }>({
    state: "idle",
    attempt: 0,
    lastMessageAt: null,
  });
  const flashTimers = useRef<Record<string, number>>({});

  const key = symbols.join(",");

  // REST seed + adaptive poll from Delta public /v2/tickers. When the WS is
  // delivering fresh data we back off the REST poll aggressively — REST is a
  // fallback / 24h-stats top-up, not a data source competing with the stream.
  const lastWsMessageAtRef = useRef<number>(0);
  useEffect(() => {
    let cancelled = false;
    let timer: number | null = null;
    const wanted = new Set(symbols);
    const endpoints = [
      "https://api.india.delta.exchange/v2/tickers",
      "https://api.delta.exchange/v2/tickers",
    ];
    async function pull() {
      for (const url of endpoints) {
        try {
          const r = await fetch(url, { cache: "no-store" });
          if (!r.ok) continue;
          const j = await r.json();
          const list: any[] = Array.isArray(j?.result) ? j.result : [];
          if (cancelled || !list.length) return;
          const now = Date.now();
          const wsFresh = now - lastWsMessageAtRef.current < 3_000;
          setTickers((prev) => {
            const next = { ...prev };
            for (const row of list) {
              const symbol: string = row?.symbol;
              if (!symbol || !wanted.has(symbol)) continue;
              const mark = Number(row.mark_price);
              const last = Number(row.close ?? row.last_price);
              const restPrice = Number.isFinite(mark) ? mark : Number.isFinite(last) ? last : Number(row.spot_price);
              if (!Number.isFinite(restPrice)) continue;
              const open = Number(row.open ?? row.open_price ?? restPrice);
              const change24h =
                row.change_24h != null
                  ? Number(row.change_24h)
                  : open
                    ? ((restPrice - open) / open) * 100
                    : undefined;
              const volume24h = Number(row.volume ?? row.turnover_usd ?? row.turnover ?? 0) || undefined;
              const prevRow = next[symbol];
              // If WS is fresh, keep the streamed price; only refresh 24h stats + mark.
              const price = wsFresh && prevRow ? prevRow.price : restPrice;
              next[symbol] = {
                ...prevRow,
                symbol,
                price,
                mark_price: Number.isFinite(mark) ? mark : prevRow?.mark_price,
                last_price: Number.isFinite(last) ? last : prevRow?.last_price,
                change24h: change24h ?? prevRow?.change24h,
                volume24h: volume24h ?? prevRow?.volume24h,
                flash: prevRow && !wsFresh
                  ? price > prevRow.price ? "up" : price < prevRow.price ? "down" : prevRow.flash
                  : prevRow?.flash,
                lastUpdate: wsFresh && prevRow ? prevRow.lastUpdate : now,
                stale: false,
                source: wsFresh && prevRow ? prevRow.source : "rest",
              };
            }
            return next;
          });
          return;
        } catch {
          /* try next endpoint */
        }
      }
    }
    const schedule = () => {
      if (cancelled) return;
      const wsFresh = Date.now() - lastWsMessageAtRef.current < 3_000;
      // WS live → poll every 30s (only to top up 24h stats). WS quiet → 5s.
      const delay = wsFresh ? 30_000 : 5_000;
      timer = window.setTimeout(async () => {
        await pull();
        schedule();
      }, delay);
    };
    pull().then(schedule);
    return () => {
      cancelled = true;
      if (timer) window.clearTimeout(timer);
    };
  }, [key]); // eslint-disable-line react-hooks/exhaustive-deps

  // Staleness watchdog — mark symbols stale if no update in >10s so the UI
  // can visually indicate "the exchange stopped sending us data for this one".
  useEffect(() => {
    const iv = window.setInterval(() => {
      const now = Date.now();
      setTickers((prev) => {
        let changed = false;
        const next = { ...prev };
        for (const s in prev) {
          const t = prev[s];
          const isStale = now - t.lastUpdate > 10_000;
          if (Boolean(t.stale) !== isStale) {
            next[s] = { ...t, stale: isStale };
            changed = true;
          }
        }
        return changed ? next : prev;
      });
    }, 2_000);
    return () => window.clearInterval(iv);
  }, []);

  useEffect(() => {
    const ws = getDeltaWs();
    const pending: Record<string, TickerUpdate> = {};
    let raf = 0;
    const flush = () => {
      raf = 0;
      const batch = pending;
      for (const k in pending) delete pending[k];
      setTickers((prev) => {
        const next = { ...prev };
        for (const symbol in batch) {
          const u = batch[symbol];
          const previous = next[symbol];
          const flash: "up" | "down" | undefined = previous
            ? u.price > previous.price
              ? "up"
              : u.price < previous.price
                ? "down"
                : previous.flash
            : undefined;
          next[symbol] = {
            ...previous,
            symbol: u.symbol,
            price: u.price,
            bid: u.bid ?? previous?.bid,
            ask: u.ask ?? previous?.ask,
            spread_bps: u.spread_bps ?? previous?.spread_bps,
            mark_price: u.mark_price ?? previous?.mark_price,
            last_price: u.last_price ?? previous?.last_price,
            change24h: u.change24h ?? previous?.change24h,
            volume24h: u.volume24h ?? previous?.volume24h,
            flash,
            lastUpdate: u.timestamp,
            stale: false,
            source: u.source,
          };
          window.clearTimeout(flashTimers.current[symbol]);
          flashTimers.current[symbol] = window.setTimeout(() => {
            setTickers((p) => (p[symbol] ? { ...p, [symbol]: { ...p[symbol], flash: undefined } } : p));
          }, 600);
        }
        return next;
      });
    };
    const offTick = ws.onTick((u: TickerUpdate) => {
      lastWsMessageAtRef.current = Date.now();
      pending[u.symbol] = u;
      if (!raf) raf = requestAnimationFrame(flush);
    });
    const offState = ws.onState(setConnection);
    ws.subscribe(symbols);
    return () => {
      if (raf) cancelAnimationFrame(raf);
      for (const s in flashTimers.current) window.clearTimeout(flashTimers.current[s]);
      flashTimers.current = {};
      offTick();
      offState();
      ws.unsubscribe(symbols);
    };
  }, [key]); // eslint-disable-line react-hooks/exhaustive-deps

  return { tickers, connection };

}
