"use client";

import { useCallback, useEffect, useRef, useState } from "react";

import { getDrawCurrent } from "@/api/draw";
import { isHallAwaitingDrawProcessing, isHallSealedCountdownUi } from "@/features/draw/draw-status-meta";
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
import { getLotteryEcho } from "@/lib/lottery-echo";
import { startWalletRefreshBurst } from "@/lib/wallet-refresh-burst";
import { PLAYER_CURRENCY_CHANGE_EVENT } from "@/lib/player-currency-preference";
import { useNetworkConnectionStore } from "@/stores/network-connection-store";
import type { DrawCurrentPayload } from "@/types/api/draw-current";

/** 大厅共享的当期快照（由 {@link useHallDrawLive} 产出，供期号条与下注表共用）。 */
export type HallDrawLiveSnapshot = {
  raw: DrawCurrentPayload | null | undefined;
  display: DrawCurrentPayload | null | undefined;
  serverNowMs: number;
  /** 与 display 漂移推演一致的本地「当前」毫秒时间戳 */
  nowMs: number;
  error: string | null;
  reload: () => Promise<void>;
  isBettable: boolean;
};

/** 界面文档 §2.1：`draw.countdown` / `draw.status_change` / `result.published` 载荷 */
export type HallWsEnvelope = {
  data: DrawCurrentPayload | null;
  emitted_at_ms?: number;
};

function secondsUntilIso(iso: string | null | undefined, effectiveNowMs: number): number {
  if (iso == null || iso === "") {
    return 0;
  }
  const targetMs = Date.parse(iso);
  if (Number.isNaN(targetMs)) {
    return 0;
  }
  return Math.max(0, Math.ceil((targetMs - effectiveNowMs) / 1000));
}

/**
 * 以服务端 `server_now_ms` 为锚、本地时钟仅负责推进，倒计时与 ISO 时刻一致。
 */
function mergeJackpotForCurrency(
  incoming: DrawCurrentPayload | null,
  previous: DrawCurrentPayload | null | undefined,
  activeCurrency: string,
): DrawCurrentPayload | null {
  if (incoming === null) {
    return null;
  }

  const incomingCode = (
    incoming.jackpot_currency_code ?? incoming.jackpot?.currency_code ?? ""
  )
    .trim()
    .toUpperCase();
  const wanted = activeCurrency.trim().toUpperCase();

  if (incomingCode !== "" && incomingCode !== wanted && previous?.jackpot) {
    return {
      ...incoming,
      jackpot_currency_code: wanted,
      jackpot: previous.jackpot,
    };
  }

  return incoming;
}

function applySnapshotDrift(
  payload: DrawCurrentPayload,
  emittedAtMs: number,
  clientNowMs: number,
  serverNowMs: number,
): DrawCurrentPayload {
  const effectiveNowMs = serverNowMs + (clientNowMs - emittedAtMs);
  return {
    ...payload,
    seconds_to_close: secondsUntilIso(payload.close_time, effectiveNowMs),
    seconds_to_start: secondsUntilIso(payload.start_time, effectiveNowMs),
    seconds_to_draw: secondsUntilIso(payload.draw_time, effectiveNowMs),
    seconds_remaining_in_cooldown:
      payload.cooling_end_time == null
        ? null
        : secondsUntilIso(payload.cooling_end_time, effectiveNowMs),
  };
}

/**
 * 大厅期号：WebSocket `lottery-hall` + 轮询降级；由 {@link HallScreen} 调用一次，注入 {@link HallDrawPanel} 与 {@link HallBettingGrid}。
 * 已集成网络连接管理，WebSocket断开时自动切换到轮询模式。
 */
export function useHallDrawLive(): HallDrawLiveSnapshot {
  const { activeCurrency } = useActivePlayerCurrency();
  const [raw, setRaw] = useState<DrawCurrentPayload | null | undefined>(undefined);
  const [serverNowMs, setServerNowMs] = useState(() => Date.now());
  const [emittedAtMs, setEmittedAtMs] = useState(() => Date.now());
  const [nowMs, setNowMs] = useState(() => Date.now());
  const [error, setError] = useState<string | null>(null);

  // 网络连接状态
  const mode = useNetworkConnectionStore((s) => s.mode);
  const isWebSocketConnected = useNetworkConnectionStore(
    (s) => s.isWebSocketConnected,
  );
  const setDrawPollingIntervalId = useNetworkConnectionStore(
    (s) => s.setDrawPollingIntervalId,
  );
  const clearDrawPolling = useNetworkConnectionStore((s) => s.clearDrawPolling);

  const latestSnapshotMsRef = useRef(0);

  const applySnapshot = useCallback(
    (anchorMs: number, data: DrawCurrentPayload | null) => {
      if (anchorMs < latestSnapshotMsRef.current) {
        return;
      }
      latestSnapshotMsRef.current = anchorMs;
      setServerNowMs(anchorMs);
      setRaw((prev) => mergeJackpotForCurrency(data, prev, activeCurrency));
      setEmittedAtMs(anchorMs);
    },
    [activeCurrency],
  );

  const mergeFromWs = useCallback(
    (evt: HallWsEnvelope) => {
      const anchor = evt.emitted_at_ms ?? Date.now();
      applySnapshot(anchor, evt.data);
    },
    [applySnapshot],
  );

  const mergeCountdownFromWs = useCallback(
    (evt: HallWsEnvelope) => {
      if (evt.data === null) return;
      const anchor = evt.emitted_at_ms ?? Date.now();
      applySnapshot(anchor, evt.data);
    },
    [applySnapshot],
  );

  const load = useCallback(async (options?: { force?: boolean }) => {
    try {
      setError(null);
      const d = await getDrawCurrent({ currency: activeCurrency });
      const wsConnected = useNetworkConnectionStore.getState().isWebSocketConnected;
      if (!options?.force && wsConnected && d.server_now_ms < latestSnapshotMsRef.current) {
        return;
      }
      applySnapshot(d.server_now_ms, d.data);
    } catch {
      setError("draw.loadFailedRefresh");
      setRaw(undefined);
    }
  }, [activeCurrency, applySnapshot]);

  useEffect(() => {
    const onCurrencyChange = () => {
      void load({ force: true });
    };
    window.addEventListener(PLAYER_CURRENCY_CHANGE_EVENT, onCurrencyChange);
    return () => window.removeEventListener(PLAYER_CURRENCY_CHANGE_EVENT, onCurrencyChange);
  }, [load]);

  // 爆池等场景：刷新大厅快照（含奖池余额）
  useEffect(() => {
    const onHallRefresh = () => {
      void load();
    };
    window.addEventListener("lottery-hall-refresh", onHallRefresh);
    return () => window.removeEventListener("lottery-hall-refresh", onHallRefresh);
  }, [load]);

  // 本地倒计时计时器（用于 UI 更新）
  useEffect(() => {
    const bump = () => setNowMs(Date.now());
    bump();
    const sid = window.setInterval(bump, 1000);
    const onVisibility = () => {
      if (document.visibilityState === "visible") bump();
    };
    document.addEventListener("visibilitychange", onVisibility);
    return () => {
      window.clearInterval(sid);
      document.removeEventListener("visibilitychange", onVisibility);
    };
  }, []);

  // WebSocket 订阅（期号 HTTP 轮询由下方单一 effect 负责）
  useEffect(() => {
    const echo = getLotteryEcho();
    if (!echo) return;

    const channel = echo.channel("lottery-hall");

    channel.listen(".draw.countdown", mergeCountdownFromWs);
    channel.listen(".draw.status_change", mergeFromWs);
    channel.listen(".result.published", (evt: HallWsEnvelope) => {
      mergeFromWs(evt);
      startWalletRefreshBurst();
    });

    return () => {
      channel.stopListening(".draw.countdown");
      channel.stopListening(".draw.status_change");
      channel.stopListening(".result.published");
    };
  }, [mergeCountdownFromWs, mergeFromWs]);

  const display: DrawCurrentPayload | null | undefined =
    raw === undefined || raw === null
      ? raw
      : applySnapshotDrift(raw, emittedAtMs, nowMs, serverNowMs);

  const isBettable = display != null && display.status === "open";

  const zeroRefreshKeyRef = useRef<string | null>(null);

  // 本地倒计时归零时主动拉取（冷静期结束、封盘切下一期等；避免只靠手动刷新）
  useEffect(() => {
    if (!display) return;

    const coolingEndMs = display.cooling_end_time
      ? Date.parse(display.cooling_end_time)
      : null;
    const coolingDone =
      display.status === "cooldown" &&
      ((display.seconds_remaining_in_cooldown ?? 1) === 0 ||
        (coolingEndMs !== null && !Number.isNaN(coolingEndMs) && coolingEndMs <= nowMs));

    const awaitingDraw = isHallAwaitingDrawProcessing(
      display.status,
      display.draw_time,
      display.seconds_to_draw,
      nowMs,
    );

    const sealedDone =
      isHallSealedCountdownUi(display.status) && (display.seconds_to_draw ?? 1) === 0;

    const closeDone =
      display.status === "open" && (display.seconds_to_close ?? 1) === 0;

    const trigger = coolingDone
      ? `${display.draw_no}:cooldown-end`
      : awaitingDraw
        ? `${display.draw_no}:awaiting-draw`
        : sealedDone
          ? `${display.draw_no}:sealed-end`
          : closeDone
            ? `${display.draw_no}:close-end`
            : null;

    if (trigger && zeroRefreshKeyRef.current !== trigger) {
      zeroRefreshKeyRef.current = trigger;
      void load({ force: true });
    }
  }, [display, nowMs, load]);

  useEffect(() => {
    if (display?.draw_no) {
      zeroRefreshKeyRef.current = null;
    }
  }, [display?.draw_no, display?.status]);

  const needsFastDrawPoll =
    display != null
    && isHallAwaitingDrawProcessing(
      display.status,
      display.draw_time,
      display.seconds_to_draw,
      nowMs,
    );

  // 单一期号 HTTP 轮询：降级 30s / 待开奖 3s / 常态保险 45s（避免多套 interval 叠加）
  useEffect(() => {
    const wsOk = isWebSocketConnected && mode === "websocket";
    const intervalMs = !wsOk ? 30_000 : needsFastDrawPoll ? 3_000 : 45_000;

    const initialTimer = window.setTimeout(() => {
      void load();
    }, 0);

    const intervalId = window.setInterval(() => {
      void load();
    }, intervalMs);
    setDrawPollingIntervalId(intervalId);

    return () => {
      window.clearTimeout(initialTimer);
      clearDrawPolling();
    };
  }, [
    isWebSocketConnected,
    mode,
    needsFastDrawPoll,
    load,
    setDrawPollingIntervalId,
    clearDrawPolling,
  ]);

  return { raw, display, serverNowMs, nowMs, error, reload: load, isBettable };
}
