/**
 * WebSocket 工具 - 支持 H5 和小程序
 */

import { getServerBaseUrl } from './config';

export type WebSocketEventHandler = (data: any) => void;

interface WebSocketMessage {
  event: string;
  data: any;
}

// WebSocket 连接管理器
class WebSocketManager {
  private socket: any = null;
  private listeners: Map<string, Set<WebSocketEventHandler>> = new Map();
  private subscriptions: Set<string> = new Set(); // 跟踪已订阅的事件，用于重连后重新订阅
  private isConnected = false;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 3;
  private reconnectDelay = 3000;
  private url = '';

  // 连接 WebSocket
  connect(url?: string): Promise<void> {
    if (this.socket && this.isConnected) {
      return Promise.resolve();
    }

    const baseUrl = getServerBaseUrl().replace('https://', 'wss://').replace('http://', 'ws://');
    this.url = url || `${baseUrl}/ws`;

    return new Promise((resolve, reject) => {
      try {
        this.socket = uni.connectSocket({
          url: this.url,
          success: () => {
            console.log('[WebSocket] 连接成功');
          },
          fail: (err) => {
            console.error('[WebSocket] 连接失败:', err);
            reject(err);
          }
        });

        // 监听连接打开
        this.socket.onOpen(() => {
          console.log('[WebSocket] 已打开');
          this.isConnected = true;
          this.reconnectAttempts = 0;
          resolve();
        });

        // 监听消息
        this.socket.onMessage((res: { data: string }) => {
          try {
            const message: WebSocketMessage = JSON.parse(res.data);
            this.emit(message.event, message.data);
          } catch (e) {
            console.error('[WebSocket] 解析消息失败:', e);
          }
        });

        // 监听错误
        this.socket.onError((err: any) => {
          console.error('[WebSocket] 错误:', err);
          this.isConnected = false;
        });

        // 监听关闭
        this.socket.onClose(() => {
          console.log('[WebSocket] 已关闭');
          this.isConnected = false;
          this.handleReconnect();
        });
      } catch (e) {
        console.error('[WebSocket] 创建连接失败:', e);
        reject(e);
      }
    });
  }

  // 发送消息
  send(event: string, data?: any): void {
    if (!this.socket || !this.isConnected) {
      console.warn('[WebSocket] 未连接，无法发送消息');
      return;
    }

    const message: WebSocketMessage = { event, data };
    this.socket.send({
      data: JSON.stringify(message),
      fail: (err: any) => {
        console.error('[WebSocket] 发送消息失败:', err);
      }
    });
  }

  // 订阅事件
  on(event: string, handler: WebSocketEventHandler): () => void {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, new Set());
    }
    this.listeners.get(event)!.add(handler);
    this.subscriptions.add(event); // 记录已订阅的事件

    // 如果已连接，发送订阅消息到服务器
    if (this.isConnected) {
      this.send('_subscribe', { event });
    }

    // 返回取消订阅的函数
    return () => {
      const handlers = this.listeners.get(event);
      if (handlers) {
        handlers.delete(handler);
      }
    };
  }

  // 取消订阅事件
  off(event: string, handler: WebSocketEventHandler): void {
    const handlers = this.listeners.get(event);
    if (handlers) {
      handlers.delete(handler);
      // 如果没有更多处理器了，从订阅列表中移除
      if (handlers.size === 0) {
        this.subscriptions.delete(event);
      }
    }
  }

  // 触发事件
  private emit(event: string, data: any): void {
    const handlers = this.listeners.get(event);
    if (handlers) {
      handlers.forEach(handler => {
        try {
          handler(data);
        } catch (e) {
          console.error(`[WebSocket] 事件 ${event} 处理失败:`, e);
        }
      });
    }
  }

  // 关闭连接
  close(): void {
    if (this.socket) {
      this.reconnectAttempts = this.maxReconnectAttempts; // 阻止重连
      this.socket.close({
        success: () => {
          console.log('[WebSocket] 主动关闭连接');
        }
      });
      this.socket = null;
      this.isConnected = false;
    }
  }

  // 重连处理
  private handleReconnect(): void {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      console.log(`[WebSocket] ${this.reconnectDelay}ms 后尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
      setTimeout(() => {
        if (!this.isConnected) {
          this.connect(this.url).then(() => {
            // 重连成功后重新订阅之前的事件
            this.resubscribe();
          }).catch(() => {
            // 重连失败会在 onClose 中再次触发
          });
        }
      }, this.reconnectDelay);
    }
  }

  // 重新订阅之前注册的事件
  private resubscribe(): void {
    console.log(`[WebSocket] 重新订阅 ${this.subscriptions.size} 个事件`);
    this.subscriptions.forEach(event => {
      // 重新发送订阅消息到服务器
      if (this.isConnected) {
        this.send('_subscribe', { event });
        console.log(`[WebSocket] 重新订阅事件: ${event}`);
      }
    });
  }

  // 是否已连接
  isOpen(): boolean {
    return this.isConnected;
  }
}

// 导出单例
export const wsManager = new WebSocketManager();

// 便捷方法：连接并订阅事件
export function connectAndSubscribe(
  events: string[],
  handlers: Record<string, WebSocketEventHandler>
): Promise<void> {
  return wsManager.connect().then(() => {
    events.forEach(event => {
      wsManager.on(event, handlers[event]);
    });
  });
}