// 设置
import { useLoadingStore } from "@/stores/loadingStore";
import { io, Socket as SocketIOClient } from "socket.io-client";

interface SocketOptions {
  reconnectionAttempts?: number;  // 最大重连次数
  reconnectionDelay?: number;     // 重连延迟时间(ms)
  timeout?: number;               // 连接超时时间(ms)
  autoConnect?: boolean;          // 是否自动连接
  forceNew?: boolean;             // 是否强制创建新连接
  transports?: string[];          // 传输方式
}

class Socket {
  url: string;
  socket: SocketIOClient | null = null;
  listeners: { [key: string]: Function[] } = {};
  private messageQueue: any[] = []; // 断连时暂存消息的简化队列

  constructor(url: string) {
    this.url = url;
    this.init();
    this.setupVisibilityListener();
  }

  init() {
    if (this.socket) {
      return;
    }
    console.log("Socket initialized with URL:", this.url);
    this.socket = io(this.url, {
      randomizationFactor: 0.5,
    });

    // 连接事件处理
    this.socket.on('connect', () => {
      this.flushMessageQueue(); // 连接后发送排队消息
      this.emit('open', { type: 'open' });
    });

    // 消息接收
    this.socket.on('message', (data) => {
      this.emit('message', data);
    });

    // 连接错误
    this.socket.on('connect_error', (error) => {
      this.emit('error', error);
    });

    // 断开连接
    this.socket.on('disconnect', (reason) => {
      this.emit('close', { reason });
    });

    // 重连尝试
    this.socket.on('reconnect_attempt', (attemptNumber) => {
      this.emit('reconnect_attempt', attemptNumber);
    });

    // 重连成功
    this.socket.on('reconnect', (attemptNumber) => {
      this.emit('reconnect', attemptNumber);
    });

    // 重连失败
    this.socket.on('reconnect_failed', () => {
      useLoadingStore().setLoading(false); // 重连失败时关闭加载状态
      this.emit('reconnect_failed', { type: 'reconnect_failed' });
    });

    // 处理所有其他事件
    this.socket.onAny((eventName, ...args) => {
      if (!['connect', 'disconnect', 'error', 'reconnect_attempt',
        'reconnect', 'reconnect_failed', 'message'].includes(eventName)) {
        this.emit(eventName, args);
      }
    });
  }

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

  async send(data: string) {
    try {
      const payload = JSON.parse(data);
      const event = payload.event || 'message';

      // 添加时间戳
      const messageData = {
        ...payload,
        timestamp: payload.timestamp || Date.now()
      };

      if (this.isConnected()) {
        this.socket?.emit("message", JSON.stringify(messageData));
      } else {
        // 未连接时，将消息加入队列
        this.messageQueue.push({ event, data: messageData });
        this.reconnectIfNeeded();
      }
    } catch (error) {
      console.error("Invalid message format. Must be a valid JSON string.", error);
    }
  }

  flushMessageQueue() {
    if (this.messageQueue.length > 0 && this.socket?.connected) {
      this.messageQueue.forEach(msg => {
        this.socket?.emit("message", JSON.stringify(msg));
      });
      this.messageQueue = [];
    }
  }

  reconnectIfNeeded() {
    if (!this.isConnected() && this.socket) {
      this.socket.connect();
    }
  }

  on(event: string, callback: Function) {
    // 直接处理的事件
    if (['open', 'close', 'error', 'reconnect', 'reconnect_attempt', 'reconnect_failed'].includes(event)) {
      if (!this.listeners[event]) {
        this.listeners[event] = [];
      }
      this.listeners[event].push(callback);
    } else {
      // Socket.IO 事件
      this.socket?.on(event, (...args) => callback(...args));
    }
  }

  off(event: string) {
    if (this.listeners[event]) {
      delete this.listeners[event];
    }
    this.socket?.off(event);
  }

  emit(event: string, data: any) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(callback => callback(data));
    }
  }

  setupVisibilityListener() {
    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible" && !this.isConnected() && this.socket) {
        this.socket.connect();
      }
    };

    document.addEventListener("visibilitychange", handleVisibilityChange);
  }

  disconnect() {
    this.socket?.disconnect();
  }
}

function useSocketIo(url: string) {
  const socket = new Socket(url);

  return {
    socket,
    send: socket.send.bind(socket),
    on: socket.on.bind(socket),
    off: socket.off.bind(socket),
    disconnect: socket.disconnect.bind(socket),
  };
}

export { useSocketIo, Socket };