import Taro from '@tarojs/taro';
import { getStorage } from './tools';
import { _UID } from '../constants/api';

type MessageCallback = (data: any) => void;

class WebSocketManager {
  private static instance: WebSocketManager;
  private socketTask: Taro.SocketTask | null = null;
  private url: string = '';
  private isConnected: boolean = false;
  private isConnecting: boolean = false;
  private isManualClose: boolean = false;
  private reconnectAttempts: number = 0;
  private maxReconnectAttempts: number = 5;
  private reconnectTimer: any = null;
  private heartbeatTimer: any = null;
  private heartbeatTimeoutTimer: any = null; // 用于检测心跳超时的定时器
  private heartbeatInterval: number = 10000; // 10秒心跳
  private heartbeatTimeout: number = 3000;   // 5秒收不到响应即视为掉线
  private listeners: Map<string, MessageCallback[]> = new Map();
  private globalEventsBound: boolean = false;

  private constructor() { }

  public static getInstance(): WebSocketManager {
    if (!WebSocketManager.instance) {
      WebSocketManager.instance = new WebSocketManager();
    }
    return WebSocketManager.instance;
  }

  /**
   * 初始化连接
   * @param url WebSocket地址
   */
  public async connect(url: string) {
    if (this.socketTask || this.isConnected || this.isConnecting) {
      console.log('WebSocket 已连接或正在连接中');
      return;
    }

    this.url = url;
    this.isConnecting = true;
    this.isManualClose = false;
    console.log(`正在连接 WebSocket: ${url}`);

    const uid = await getStorage(_UID) || '-1';
    const task = Taro.connectSocket({
      header: {
        'XP-Uid': uid.toString(),
      },
      url: this.url,
      success: () => { },
      fail: (err) => {
        console.error('WebSocket 连接失败:', err);
        this.isConnecting = false;
        this.handleReconnect();
      }
    });
    const maybeTask: any = task as any;
    if (maybeTask && typeof maybeTask.onOpen === 'function') {
      this.socketTask = maybeTask;
      this.isConnecting = false;
      this.initEventListeners();
      return;
    }
    if (maybeTask && typeof maybeTask.then === 'function') {
      maybeTask
        .then((resolvedTask) => {
          this.socketTask = resolvedTask;
          this.isConnecting = false;
          this.initEventListeners();
        })
        .catch((err) => {
          console.error('WebSocket 连接失败:', err);
          this.isConnecting = false;
          this.handleReconnect();
        });
      return;
    }
    this.socketTask = null;
    this.isConnecting = false;
    this.initEventListeners();
  }

  public isConnectedStatus() {
    return this.isConnected;
  }

  /**
   * 初始化事件监听
   */
  private initEventListeners() {
    if (this.socketTask && typeof this.socketTask.onOpen === 'function') {
      this.socketTask.onOpen(async () => {
        console.log('WebSocket 连接已打开');
        this.isConnected = true;
        this.isConnecting = false;
        this.reconnectAttempts = 0;
        this.startHeartbeat();
        const uid = await getStorage(_UID) || '-1';
        this.send({ type: 'auth', appUserId: uid.toString(), timestamp: Date.now() });
        this.notifyListeners('open', { status: 'connected' });
      });

      this.socketTask.onMessage((res) => {
        try {
          this.resetHeartbeatTimeout();
          const data = JSON.parse(res.data as string);
          console.log('收到 WebSocket 消息:', res.data);
          const content = JSON.parse(data.content || '{}');
          this.handleIncomingMessage(data, content);
          if (data.type) {
            this.notifyListeners(data.type, data);
          }
          this.notifyListeners('message', data);
        } catch (e) {
          console.warn('解析 WebSocket 消息失败:', res.data);
          this.notifyListeners('message', res.data);
        }
      });

      this.socketTask.onClose((res) => {
        console.log('WebSocket 连接已关闭', res);
        this.isConnected = false;
        this.isConnecting = false;
        this.stopHeartbeat();
        this.socketTask = null;

        if (!this.isManualClose) {
          this.handleReconnect();
        }
        this.notifyListeners('close', res);
      });

      this.socketTask.onError((err) => {
        console.error('WebSocket 错误:', err);
        this.isConnected = false;
        this.isConnecting = false;
        this.notifyListeners('error', err);
      });
      return;
    }

    if (this.globalEventsBound) return;
    this.globalEventsBound = true;

    Taro.onSocketOpen(async () => {
      console.log('WebSocket 连接已打开');
      this.isConnected = true;
      this.isConnecting = false;
      this.reconnectAttempts = 0;
      this.startHeartbeat();
      const uid = await getStorage(_UID) || '-1';
      this.send({ type: 'auth', appUserId: uid.toString(), timestamp: Date.now() });
      this.notifyListeners('open', { status: 'connected' });
    });

    Taro.onSocketMessage((res) => {
      try {
        this.resetHeartbeatTimeout();
        const data = JSON.parse(res.data as string);
        console.log('收到 WebSocket 消息:', res.data);
        const content = JSON.parse(data.content || '{}');
        this.handleIncomingMessage(data, content);
        if (data.type) {
          this.notifyListeners(data.type, data);
        }
        this.notifyListeners('message', data);
      } catch (e) {
        console.warn('解析 WebSocket 消息失败:', res.data);
        this.notifyListeners('message', res.data);
      }
    });

    Taro.onSocketClose((res) => {
      console.log('WebSocket 连接已关闭', res);
      this.isConnected = false;
      this.isConnecting = false;
      this.stopHeartbeat();
      this.socketTask = null;

      if (!this.isManualClose) {
        this.handleReconnect();
      }
      this.notifyListeners('close', res);
    });

    Taro.onSocketError((err) => {
      console.error('WebSocket 错误:', err);
      this.isConnected = false;
      this.isConnecting = false;
      this.notifyListeners('error', err);
    });
  }

  /**
   * 发送消息
   * @param data 消息内容
   */
  public send(data: any) {
    if (!this.isConnected) {
      console.warn('WebSocket 未连接，消息未发送:', data);
      return;
    }

    const message = typeof data === 'string' ? data : JSON.stringify(data);
    if (this.socketTask) {
      this.socketTask.send({
        data: message,
        fail: (err) => {
          console.error('发送消息失败:', err);
        }
      });
    } else {
      Taro.sendSocketMessage({
        data: message,
        fail: (err) => {
          console.error('发送消息失败:', err);
        }
      });
    }
  }

  /**
   * 关闭连接
   */
  public close() {
    this.isManualClose = true;
    this.stopHeartbeat();
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }

    if (this.socketTask) {
      this.socketTask.close({
        code: 1000,
        reason: '用户主动关闭连接'
      });
      this.socketTask = null;
    }
    this.isConnected = false;
    this.isConnecting = false;
  }

  /**
   * 处理重连
   */
  private handleReconnect() {
    if (this.reconnectTimer) return;

    // 固定约 3 秒重连一次，并加上 0~1 秒的随机抖动
    const delay = 3000 + Math.floor(Math.random() * 1000);
    console.log(`正在尝试重连，延迟 ${delay}ms... (第 ${this.reconnectAttempts + 1} 次尝试)`);

    this.reconnectTimer = setTimeout(() => {
      // 防止数字溢出（无限重试时）
      if (this.reconnectAttempts < 9999) {
        this.reconnectAttempts++;
      }
      this.reconnectTimer = null;
      this.connect(this.url);
    }, delay);
  }

  /**
   * 开启心跳
   */
  private startHeartbeat() {
    this.stopHeartbeat();
    this.heartbeatTimer = setInterval(() => {
      if (this.isConnected) {
        this.send({ type: 'ping', timestamp: Date.now() });
        // 发送 ping 后，启动一个超时检测
        // 如果在配置的时间内没有收到任何消息(pong 或业务消息)，则认为连接已假死
        if (this.heartbeatTimeoutTimer) {
          clearTimeout(this.heartbeatTimeoutTimer);
        }
        this.heartbeatTimeoutTimer = setTimeout(() => {
          console.warn('心跳超时，未收到服务器响应，主动断开 WebSocket 连接');
          this.closeAndReconnect();
        }, this.heartbeatTimeout);
      }
    }, this.heartbeatInterval);
  }

  /**
   * 停止心跳
   */
  private stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
  }

  /**
   * 收到消息时重置心跳超时检测
   */
  private resetHeartbeatTimeout() {
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
  }

  /**
   * 主动关闭并重连 (处理假死状态)
   */
  private closeAndReconnect() {
    // 强制关闭当前连接
    if (this.socketTask) {
      try {
        this.socketTask.close({
          code: 1000,
          reason: '心跳超时主动关闭'
        });
      } catch (e) {
        console.error('强制关闭 Socket 失败:', e);
      }
      this.socketTask = null;
    }
    this.isConnected = false;
    this.isConnecting = false;
    this.stopHeartbeat();
    
    // 立即触发重连
    if (!this.isManualClose) {
      this.handleReconnect();
    }
  }

  /**
   * 注册事件监听
   * @param event 事件名称
   * @param callback 回调函数
   */
  public on(event: string, callback: MessageCallback) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event)?.push(callback);
  }

  /**
   * 移除事件监听
   * @param event 事件名称
   * @param callback 回调函数
   */
  public off(event: string, callback: MessageCallback) {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      const index = callbacks.indexOf(callback);
      if (index !== -1) {
        callbacks.splice(index, 1);
      }
    }
  }

  /**
   * 通知监听器
   * @param event 事件名称
   * @param data 数据
   */
  private notifyListeners(event: string, data: any) {
    const callbacks = this.listeners.get(event);
    if (callbacks) {
      callbacks.forEach(callback => {
        try {
          callback(data);
        } catch (e) {
          console.error(`WebSocket 事件 ${event} 监听器执行出错:`, e);
        }
      });
    }
  }

  // 处理传入消息
  private handleIncomingMessage(data: any, content: any) {
    if (data?.type === 'ORDER_STATUS') {
      const status = content?.status;
      const orderId = content?.orderId;
      if (typeof status === 'number') {
        const mapped = this.mapOrderStatusToTripStatus(status);
        if (typeof mapped.tripStatus === 'number') {
          Taro.setStorageSync('tripStatus', mapped.tripStatus);
          Taro.setStorageSync('orderId', orderId);
        }
        this.notifyListeners('order_status', { status, ...mapped, data, content });
      }
    }
    if (data?.type === 'ORDER_ROUTE') {
      const routeType = content?.routeType;
      const direction = Number(content?.direction);
      // 2-12 新增
      const duration = Number(JSON.parse(content?.route ?? '{}')?.duration ?? '0');
      const distance = Number(JSON.parse(content?.route ?? '{}')?.distance ?? '0');
      // 2-12 新增
      const points = this.normalizeRoutePoints(content);
      if (!Number.isNaN(duration)) {
        Taro.setStorageSync('orderRouteDuration', Math.round(duration));
        Taro.setStorageSync('orderRouteDurationUnit', 's');
      }
      if (!Number.isNaN(distance)) {
        const distanceKm = Number((distance / 1000).toFixed(1));
        Taro.setStorageSync('orderRouteDistance', distanceKm);
        Taro.setStorageSync('orderRouteDistanceUnit', 'km');
      }
      if (points.length > 0) {
        const cached = Taro.getStorageSync('orderRoutePoints') || {};
        if (typeof routeType === 'number') {
          cached[String(routeType)] = points;
          Taro.setStorageSync('orderRouteLatestType', routeType);
        } else {
          cached.latest = points;
        }
        Taro.setStorageSync('orderRoutePoints', cached);
        this.notifyListeners('order_route', { routeType, direction, points, data, content });
      }
    }
    if (data?.type === 'ORDER_UPDATE_PRICE') {
      const orderId = content?.orderId ?? data?.orderId;
      this.notifyListeners('order_update_price', { orderId, data, content });
    }
    if (data?.type === 'ORDER_REASSIGN') {
      const orderId = content?.orderId ?? data?.orderId;
      this.notifyListeners('order_reassign', { orderId, data, content });
    }
    if (data?.type === 'OPEN_TRUNK') {
      const isOpen = content?.isOpen ?? content?.open;
      this.notifyListeners('open_trunk', { isOpen, data, content });
    }
  }

  // 归一化路线点
  private normalizeRoutePoints(content: any) {
    const route = JSON.parse(content?.route ?? '{}');
    const rawPoints = route?.polyline ?? [];
    const arrPoint = JSON.parse(rawPoints);
    if (!Array.isArray(arrPoint)) return [];
    return arrPoint.map((item: any) => {
      const latitude = item?.latitude;
      const longitude = item?.longitude;
      if (typeof latitude === 'number' && typeof longitude === 'number') {
        return { latitude, longitude };
      }
      return null;
    }).filter(Boolean);
  }

  // 映射订单状态到行程状态
  private mapOrderStatusToTripStatus(status: number) {
    switch (status) {
      case 0:
        return { tripStatus: 1, showCancelPopup: true };
      case 1:
        return { tripStatus: 3, showPassengerNotice: true };
      case 2:
      case 3:
        return { tripStatus: 4 };
      case 4:
        return { tripStatus: 5, showAnnouncementsPopup: true };
      case 5:
      case 6:
        return { tripStatus: 6 };
      case 7:
        return { tripStatus: 7 };
      case 8:
        return { tripStatus: 8 };
      case 9:
      case 10:
        return { tripStatus: 9 };
      default:
        return { tripStatus: undefined };
    }
  }
}

export default WebSocketManager.getInstance();
