"use client";

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

import {
  disconnectLotteryEcho,
  getLotteryEcho,
  isLotteryReverbConfigured,
} from "@/lib/lottery-echo";
import {
  refreshWalletNow,
  startLimitedWalletPolling,
  startPersistentWalletPolling,
  stopWalletPolling as stopWalletPollingUtil,
} from "@/lib/wallet-polling-utils";
import {
  useNetworkConnectionStore,
  type NetworkMode,
} from "@/stores/network-connection-store";

const RECONNECT_INTERVAL_MS = 5_000; // 5秒重连间隔
const MAX_RECONNECT_ATTEMPTS = 10; // 最大重连次数

/** Pusher 尚未连上前的中间态，不应立刻切降级 */
const PUSHER_PENDING_STATES = new Set([
  "initialized",
  "connecting",
  "reconnecting",
]);

type PusherConnection = {
  state?: string;
  bind: (event: string, callback: () => void) => void;
  unbind: (event: string, callback: () => void) => void;
};

export type UseWebSocketManagerReturn = {
  /** 当前网络模式 */
  mode: NetworkMode;
  /** 是否显示降级模式横幅 */
  showDegradedBanner: boolean;
  /** 手动触发重连 */
  reconnect: () => void;
  /** 开始钱包轮询（用于下注后或开奖后） */
  startWalletPolling: (options?: { limitedDuration?: boolean }) => void;
  /** 停止钱包轮询 */
  stopWalletPolling: () => void;
  /** 手动刷新画作数据 */
  refreshDraw: () => Promise<void>;
  /** 手动刷新钱包余额 */
  refreshWallet: () => Promise<void>;
};

/**
 * WebSocket 连接管理器 Hook
 * 负责：
 * 1. 监控 WebSocket 连接状态
 * 2. WebSocket 断开时自动切换到轮询模式
 * 3. 定期尝试重连 WebSocket
 * 4. 期号 HTTP 轮询由 {@link useHallDrawLive} 统一管理
 * 5. 可选钱包余额轮询（`startWalletPolling`，下注等场景）
 */
export function useWebSocketManager(): UseWebSocketManagerReturn {
  // 使用 selector 避免整 store 订阅导致无谓重渲染
  const mode = useNetworkConnectionStore((s) => s.mode);
  const reconnectAttempts = useNetworkConnectionStore((s) => s.reconnectAttempts);
  const setWebSocketConnected = useNetworkConnectionStore((s) => s.setWebSocketConnected);
  const setReconnecting = useNetworkConnectionStore((s) => s.setReconnecting);
  const incrementReconnectAttempts = useNetworkConnectionStore((s) => s.incrementReconnectAttempts);
  const resetReconnectAttempts = useNetworkConnectionStore((s) => s.resetReconnectAttempts);
  const setLastDisconnectedAt = useNetworkConnectionStore((s) => s.setLastDisconnectedAt);
  const switchToPollingMode = useNetworkConnectionStore((s) => s.switchToPollingMode);
  const switchToWebSocketMode = useNetworkConnectionStore((s) => s.switchToWebSocketMode);

  const reconnectTimerRef = useRef<number | null>(null);
  const attemptReconnectRef = useRef<() => void>(() => {});
  /** 递增后重新创建 Echo 并绑定连接事件（供「恢复」与重连使用） */
  const [echoSession, setEchoSession] = useState(0);

  // 刷新画作数据
  const refreshDraw = useCallback(async () => {
    // 由 useHallDrawLive 监听并拉取，避免与大厅重复请求 draw/current
    window.dispatchEvent(new Event("lottery-hall-refresh"));
  }, []);

  // 钱包轮询（委托给共享工具函数，消除与 useWalletPolling 的重复逻辑）
  const startWalletPolling = useCallback(
    (options?: { limitedDuration?: boolean }) => {
      const { limitedDuration = false } = options ?? {};
      if (limitedDuration) {
        startLimitedWalletPolling();
      } else {
        startPersistentWalletPolling();
      }
    },
    [],
  );

  // 停止钱包轮询
  const stopWalletPolling = useCallback(() => {
    stopWalletPollingUtil();
  }, []);

  // 检测 Pusher 是否已真正 connected（非仅订阅频道）
  const isPusherConnected = useCallback((): boolean => {
    const echo = getLotteryEcho();
    const state = echo?.connector?.pusher?.connection?.state;
    return state === "connected";
  }, []);

  // 处理连接断开
  const handleDisconnect = useCallback(() => {
    setWebSocketConnected(false);
    setLastDisconnectedAt(Date.now());
    switchToPollingMode();

    // 启动重连计时器
    if (reconnectTimerRef.current) {
      window.clearTimeout(reconnectTimerRef.current);
    }

    setReconnecting(true);
    attemptReconnectRef.current();
  }, [
    setWebSocketConnected,
    setLastDisconnectedAt,
    switchToPollingMode,
    setReconnecting,
  ]);

  // 处理连接成功
  const handleConnect = useCallback(() => {
    setWebSocketConnected(true);
    resetReconnectAttempts();
    switchToWebSocketMode();
    setReconnecting(false);

    // 清除重连计时器
    if (reconnectTimerRef.current) {
      window.clearTimeout(reconnectTimerRef.current);
      reconnectTimerRef.current = null;
    }
  }, [
    setWebSocketConnected,
    resetReconnectAttempts,
    switchToWebSocketMode,
    setReconnecting,
  ]);

  // 重连逻辑
  const attemptReconnect = useCallback(() => {
    if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
      // 达到最大重连次数，停止尝试
      setReconnecting(false);
      return;
    }

    incrementReconnectAttempts();

    if (isPusherConnected()) {
      handleConnect();
      return;
    }

    reconnectTimerRef.current = window.setTimeout(
      () => attemptReconnectRef.current(),
      RECONNECT_INTERVAL_MS,
    );
  }, [
    reconnectAttempts,
    incrementReconnectAttempts,
    isPusherConnected,
    handleConnect,
    setReconnecting,
  ]);

  useEffect(() => {
    attemptReconnectRef.current = attemptReconnect;
  }, [attemptReconnect]);

  // 手动重连：断开旧 Echo、重建连接（仅 reset 计数无法修复 failed 状态）
  const reconnect = useCallback(() => {
    disconnectLotteryEcho();
    resetReconnectAttempts();
    setReconnecting(true);
    if (reconnectTimerRef.current !== null) {
      window.clearTimeout(reconnectTimerRef.current);
      reconnectTimerRef.current = null;
    }
    setEchoSession((n) => n + 1);
  }, [resetReconnectAttempts, setReconnecting]);

  // 监听网络状态变化
  useEffect(() => {
    const handleOnline = () => {
      // 网络恢复时尝试重连 WebSocket
      if (mode === "polling" || mode === "offline") {
        reconnect();
      }
    };

    const handleOffline = () => {
      // 网络断开
      useNetworkConnectionStore.getState().setMode("offline");
    };

    window.addEventListener("online", handleOnline);
    window.addEventListener("offline", handleOffline);

    return () => {
      window.removeEventListener("online", handleOnline);
      window.removeEventListener("offline", handleOffline);
    };
  }, [mode, reconnect]);

  // 初始化：绑定 Pusher 真实连接事件（勿仅凭 channel 对象存在判定已连接）
  useEffect(() => {
    const echo = getLotteryEcho();
    if (!echo) {
      switchToPollingMode();
      return;
    }

    echo.channel("lottery-hall");

    let connection = echo.connector?.pusher?.connection as
      | PusherConnection
      | undefined;
    let pendingTimer: number | null = null;

    const syncConnectionState = () => {
      const state = connection?.state;
      if (state === "connected") {
        handleConnect();
      } else if (state && PUSHER_PENDING_STATES.has(state)) {
        setReconnecting(true);
      } else if (
        state === "disconnected" ||
        state === "unavailable" ||
        state === "failed"
      ) {
        handleDisconnect();
      }
    };

    const bindConnectionEvents = (conn: PusherConnection) => {
      conn.bind("connected", handleConnect);
      conn.bind("disconnected", handleDisconnect);
      conn.bind("unavailable", handleDisconnect);
      conn.bind("failed", handleDisconnect);
      conn.bind("state_change", syncConnectionState);
      syncConnectionState();
    };

    if (connection) {
      bindConnectionEvents(connection);
    } else {
      // connector 可能下一 tick 才就绪；勿立刻切降级
      pendingTimer = window.setTimeout(() => {
        connection = echo.connector?.pusher?.connection as
          | PusherConnection
          | undefined;
        if (connection) {
          bindConnectionEvents(connection);
        } else if (isPusherConnected()) {
          handleConnect();
        } else {
          handleDisconnect();
        }
      }, 0);
    }

    return () => {
      if (pendingTimer !== null) {
        window.clearTimeout(pendingTimer);
      }
      if (connection) {
        connection.unbind("connected", handleConnect);
        connection.unbind("disconnected", handleDisconnect);
        connection.unbind("unavailable", handleDisconnect);
        connection.unbind("failed", handleDisconnect);
        connection.unbind("state_change", syncConnectionState);
      }
      if (reconnectTimerRef.current) {
        window.clearTimeout(reconnectTimerRef.current);
      }
    };
  }, [
    echoSession,
    isPusherConnected,
    handleConnect,
    handleDisconnect,
    switchToPollingMode,
    setReconnecting,
  ]);

  // 仅挂载卸载时清理；勿依赖 stop*（否则每次 setInterval id 变化都会触发清理 → setState → 无线循环）
  useEffect(() => {
    return () => {
      useNetworkConnectionStore.getState().clearAllPollingIntervals();
      if (reconnectTimerRef.current !== null) {
        window.clearTimeout(reconnectTimerRef.current);
      }
    };
  }, []);

  const reverbConfigured = isLotteryReverbConfigured();

  return {
    mode,
    /** 仅当配置了 Reverb 却连不上时提示；本地未配 WS 时静默走 HTTP 轮询 */
    showDegradedBanner:
      reverbConfigured && (mode === "polling" || mode === "offline"),
    reconnect,
    startWalletPolling,
    stopWalletPolling,
    refreshDraw,
    refreshWallet: refreshWalletNow,
  };
}
