// Socket.IO 客户端管理
import type { Socket } from 'socket.io-client';
import { io } from 'socket.io-client';

import type {
  ClientToServerEvents,
  ServerToClientEvents,
  WatchRoomConfig,
} from '@/types/watch-room';

export type WatchRoomSocket = Socket<ServerToClientEvents, ClientToServerEvents>;

class WatchRoomSocketManager {
  private socket: WatchRoomSocket | null = null;
  private config: WatchRoomConfig | null = null;
  private heartbeatInterval: NodeJS.Timeout | null = null;
  private heartbeatTimeoutCheck: NodeJS.Timeout | null = null;
  private lastHeartbeatResponse: number = Date.now();
  private visibilityChangeHandler: (() => void) | null = null;
  private reconnectFailedCallback: (() => void) | null = null;
  private reconnectSuccessCallback: (() => void) | null = null;

  async connect(config: WatchRoomConfig): Promise<WatchRoomSocket> {
    if (this.socket?.connected) {
      return this.socket;
    }

    this.config = config;

    const socketOptions = {
      transports: ['websocket', 'polling'] as ('websocket' | 'polling')[],
      reconnection: true,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
      reconnectionAttempts: 5,
    };

    if (config.serverType === 'internal') {
      // 内部服务器 - 连接到同一个域名的Socket.IO服务器
      this.socket = io({
        ...socketOptions,
        path: '/socket.io', // 使用服务器配置的path
      });
    } else {
      // 外部服务器
      if (!config.externalServerUrl) {
        throw new Error('External server URL is required');
      }

      this.socket = io(config.externalServerUrl, {
        ...socketOptions,
        auth: {
          token: config.externalServerAuth,
        },
        extraHeaders: config.externalServerAuth
          ? {
              Authorization: `Bearer ${config.externalServerAuth}`,
            }
          : undefined,
      });
    }

    // 设置事件监听（包括 heartbeat:pong）
    this.setupEventListeners();

    // 开始心跳
    this.startHeartbeat();

    // 启动心跳超时检查
    this.startHeartbeatTimeoutCheck();

    // 设置浏览器可见性监听
    this.setupVisibilityListener();

    return new Promise((resolve, reject) => {
      if (!this.socket) {
        reject(new Error('Socket not initialized'));
        return;
      }

      // 使用 once 而不是 on，避免重复注册
      this.socket.once('connect', () => {
        // eslint-disable-next-line no-console
        console.log('[WatchRoom] Connected to server');
        if (this.socket) {
          resolve(this.socket);
        }
      });

      this.socket.once('connect_error', (error) => {
        // eslint-disable-next-line no-console
        console.error('[WatchRoom] Connection error:', error);
        reject(error);
      });
    });
  }

  disconnect() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
      this.heartbeatInterval = null;
    }

    if (this.heartbeatTimeoutCheck) {
      clearInterval(this.heartbeatTimeoutCheck);
      this.heartbeatTimeoutCheck = null;
    }

    // 移除浏览器可见性监听
    this.removeVisibilityListener();

    if (this.socket) {
      // 移除所有事件监听器
      this.socket.off('connect');
      this.socket.off('disconnect');
      this.socket.off('error');
      this.socket.off('heartbeat:pong');
      this.socket.io.off('reconnect_attempt');
      this.socket.io.off('reconnect');
      this.socket.io.off('reconnect_failed');

      this.socket.disconnect();
      this.socket = null;
    }
  }

  getSocket(): WatchRoomSocket | null {
    return this.socket;
  }

  isConnected(): boolean {
    return this.socket?.connected ?? false;
  }

  private setupEventListeners() {
    if (!this.socket) return;

    this.socket.on('connect', () => {
      // eslint-disable-next-line no-console
      console.log('[WatchRoom] Socket connected');
      // 重置心跳响应时间
      this.lastHeartbeatResponse = Date.now();
    });

    this.socket.on('disconnect', (reason) => {
      // eslint-disable-next-line no-console
      console.log('[WatchRoom] Socket disconnected:', reason);
    });

    this.socket.on('error', (error) => {
      // eslint-disable-next-line no-console
      console.error('[WatchRoom] Socket error:', error);
    });

    // 监听心跳响应
    this.socket.on('heartbeat:pong', (_data: { timestamp: number }) => {
      this.lastHeartbeatResponse = Date.now();
    });

    // 监听重连尝试
    this.socket.io.on('reconnect_attempt', (attemptNumber) => {
      // eslint-disable-next-line no-console
      console.log('[WatchRoom] Reconnect attempt:', attemptNumber);
    });

    // 监听重连成功
    this.socket.io.on('reconnect', (attemptNumber) => {
      // eslint-disable-next-line no-console
      console.log('[WatchRoom] Reconnected after', attemptNumber, 'attempts');
      // 重置心跳响应时间
      this.lastHeartbeatResponse = Date.now();
      this.reconnectSuccessCallback?.();
    });

    // 监听重连失败
    this.socket.io.on('reconnect_failed', () => {
      // eslint-disable-next-line no-console
      console.error('[WatchRoom] Reconnect failed after all attempts');
      this.reconnectFailedCallback?.();
    });
  }

  private startHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval);
    }

    this.heartbeatInterval = setInterval(() => {
      if (this.socket?.connected) {
        this.socket.emit('heartbeat');
      }
    }, 5000); // 每5秒发送一次心跳
  }

  // 启动心跳超时检查
  private startHeartbeatTimeoutCheck() {
    if (this.heartbeatTimeoutCheck) {
      clearInterval(this.heartbeatTimeoutCheck);
    }

    // 每3秒检查一次心跳超时
    this.heartbeatTimeoutCheck = setInterval(() => {
      if (!this.socket?.connected) {
        return;
      }

      const now = Date.now();
      const timeSinceLastResponse = now - this.lastHeartbeatResponse;

      // 如果超过15秒没有收到心跳响应，认为连接可能有问题
      if (timeSinceLastResponse > 15000) {
        // eslint-disable-next-line no-console
        console.warn('[WatchRoom] Heartbeat timeout detected, last response was', timeSinceLastResponse, 'ms ago');

        // 不要强制断开连接，让 Socket.IO 的自动重连机制处理
        // Socket.IO 会自动检测连接问题并尝试重连
        // 只记录警告，不主动断开
        // eslint-disable-next-line no-console
        console.warn('[WatchRoom] Waiting for Socket.IO auto-reconnect mechanism');

        // 重置心跳响应时间，避免重复触发警告
        this.lastHeartbeatResponse = Date.now();
      }
    }, 3000);
  }

  // 设置浏览器可见性监听
  private setupVisibilityListener() {
    if (typeof document === 'undefined') return;

    this.visibilityChangeHandler = () => {
      if (document.visibilityState === 'visible') {
        // eslint-disable-next-line no-console
        console.log('[WatchRoom] Page became visible, checking connection...');

        // 页面可见时检查连接状态
        if (this.socket && !this.socket.connected) {
          // eslint-disable-next-line no-console
          console.log('[WatchRoom] Socket disconnected, attempting to reconnect...');
          this.socket.connect();
        }
      }
    };

    document.addEventListener('visibilitychange', this.visibilityChangeHandler);
  }

  // 移除浏览器可见性监听
  private removeVisibilityListener() {
    if (typeof document === 'undefined' || !this.visibilityChangeHandler) return;

    document.removeEventListener('visibilitychange', this.visibilityChangeHandler);
    this.visibilityChangeHandler = null;
  }

  // 设置重连失败回调
  setReconnectFailedCallback(callback: () => void) {
    this.reconnectFailedCallback = callback;
  }

  // 设置重连成功回调
  setReconnectSuccessCallback(callback: () => void) {
    this.reconnectSuccessCallback = callback;
  }

  // 手动重连
  async reconnect(): Promise<boolean> {
    if (!this.config) {
      console.error('[WatchRoom] No config available for reconnection');
      return false;
    }

    try {
      // eslint-disable-next-line no-console
      console.log('[WatchRoom] Manual reconnection initiated...');

      // 如果socket存在且未连接，尝试重新连接
      if (this.socket && !this.socket.connected) {
        this.socket.connect();

        // 等待连接结果
        return new Promise((resolve) => {
          const timeout = setTimeout(() => {
            resolve(false);
          }, 5000); // 5秒超时

          this.socket!.once('connect', () => {
            clearTimeout(timeout);
            resolve(true);
          });

          this.socket!.once('connect_error', () => {
            clearTimeout(timeout);
            resolve(false);
          });
        });
      }

      // 如果socket不存在，重新创建连接
      await this.connect(this.config);
      return true;
    } catch (error) {
      console.error('[WatchRoom] Manual reconnection failed:', error);
      return false;
    }
  }
}

// 单例实例
export const watchRoomSocketManager = new WatchRoomSocketManager();
