import Taro from '@tarojs/taro';
import { getStorage } from './tools';
import { _UID } from '../constants/api';
import { safeParse } from './Robotaxi-public-method';

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

enum SocketState {
  IDLE = 'idle',
  CONNECTING = 'connecting',
  CONNECTED = 'connected',
}

class WebSocketManager {
  private static instance: WebSocketManager;
  private socketTask: Taro.SocketTask | null = null; // 当前生效的 socketTask
  private url: string = ''; // 当前连接地址
  private socketState: SocketState = SocketState.IDLE; // 当前连接状态
  private isConnected: boolean = false; // 对外兼容的连接态
  private isConnecting: boolean = false; // 对外兼容的连接中标记
  private isManualClose: boolean = false; // 是否手动关闭
  private isAppActive: boolean = true; // 应用是否处于前台
  private shouldReconnectWhenActive: boolean = false; // 回前台后是否需要补重连
  private reconnectAttempts: number = 0; // 当前连续重连次数
  private reconnectTimer: any = null; // 重连定时器
  private heartbeatTimer: any = null; // 心跳发送定时器
  private heartbeatTimeoutTimer: any = null; // 单次等待 pong 的超时定时器
  private heartbeatInterval: number = 15000; // 心跳间隔
  private heartbeatTimeout: number = 10000; // 单次心跳等待 pong 的超时时间
  private maxHeartbeatMisses: number = 2; // 连续丢失 pong 的最大次数
  private locationReportTimer: any = null; // 位置上报定时器
  private locationReportInterval: number = 35000; // 35 秒上报一次位置
  private listeners: Map<string, MessageCallback[]> = new Map(); // 事件监听器
  private globalEventsBound: boolean = false; // 全局事件是否已绑定
  private connectionSeed: number = 0; // 连接代次种子
  private activeConnectionId: number = 0; // 当前生效连接代次
  private heartbeatSeq: number = 0; // 心跳序号
  private pendingHeartbeatSeq: number | null = null; // 当前等待 pong 的心跳序号
  private missedHeartbeatCount: number = 0; // 连续未收到 pong 的次数

  private constructor() { }

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

  /**
   * 应用回到前台时恢复心跳或补发重连。
   */
  public onAppShow() {
    this.isAppActive = true;
    this.shouldReconnectWhenActive = false;
    if (this.isConnected && this.activeConnectionId > 0) {
      this.startHeartbeat(this.activeConnectionId);
      this.startLocationReport(this.activeConnectionId);
      return;
    }
    if (!this.isManualClose && this.url) {
      this.connect(this.url);
    }
  }

  /**
   * 应用进入后台时暂停心跳，避免后台定时器抖动误判掉线。
   */
  public onAppHide() {
    this.isAppActive = false;
    this.stopHeartbeat();
    this.stopLocationReport();
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
      this.shouldReconnectWhenActive = true;
    }
  }

  /**
   * 初始化连接。
   * @param url WebSocket 地址
   */
  public async connect(url: string) {
    if (!url) {
      return;
    }
    if (this.isConnected && this.url === url) {
      return;
    }
    if (this.isConnecting && this.url === url) {
      return;
    }

    this.url = url;
    this.isManualClose = false;
    this.shouldReconnectWhenActive = false;
    this.isConnecting = true;
    this.socketState = SocketState.CONNECTING;
    this.clearReconnectTimer();

    const connectionId = this.createConnectionId();
    console.log(`正在连接 WebSocket: ${url}，连接代次：${connectionId}`);

    try {
      const uid = await this.getValidUid();
      if (!this.isCurrentConnection(connectionId)) {
        return;
      }
      if (!uid) {
        console.warn('WebSocket 连接已取消，UID 无效');
        this.markConnectionClosed(connectionId);
        return;
      }

      const task = Taro.connectSocket({
        header: {
          'XP-Uid': uid,
        },
        url: this.url,
        success: () => { },
        fail: (err) => {
          if (!this.isCurrentConnection(connectionId)) {
            return;
          }
          console.error('WebSocket 连接失败:', err);
          this.markConnectionClosed(connectionId);
          this.scheduleReconnect(connectionId, 'connect_fail');
        }
      });

      const maybeTask: any = task as any;
      if (maybeTask && typeof maybeTask.onOpen === 'function') {
        this.attachTask(connectionId, maybeTask);
        return;
      }

      if (maybeTask && typeof maybeTask.then === 'function') {
        maybeTask
          .then((resolvedTask: Taro.SocketTask) => {
            if (!this.isCurrentConnection(connectionId)) {
              this.closeTaskSilently(resolvedTask, '过期连接任务关闭');
              return;
            }
            this.attachTask(connectionId, resolvedTask);
          })
          .catch((err: any) => {
            if (!this.isCurrentConnection(connectionId)) {
              return;
            }
            console.error('WebSocket 连接失败:', err);
            this.markConnectionClosed(connectionId);
            this.scheduleReconnect(connectionId, 'connect_promise_fail');
          });
        return;
      }

      this.bindGlobalEventListeners();
    } catch (error) {
      if (!this.isCurrentConnection(connectionId)) {
        return;
      }
      console.error('初始化 WebSocket 连接失败:', error);
      this.markConnectionClosed(connectionId);
      this.scheduleReconnect(connectionId, 'connect_exception');
    }
  }

  /**
   * 对外暴露当前连接状态。
   */
  public isConnectedStatus() {
    return this.isConnected;
  }

  /**
   * 发送消息。
   * @param data 消息内容
   */
  public send(data: any) {
    this.sendInternal(data, { silentWhenDisconnected: false });
  }

  /**
   * 主动关闭连接。
   */
  public close() {
    const closedConnectionId = this.activeConnectionId;
    this.isManualClose = true;
    this.shouldReconnectWhenActive = false;
    this.clearReconnectTimer();
    this.stopHeartbeat();
    this.stopLocationReport();
    this.invalidateCurrentConnection();
    this.closeTaskSilently(this.socketTask, '用户主动关闭连接');
    this.socketTask = null;
    this.markConnectionClosed(closedConnectionId);
  }

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

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

  /**
   * 创建新的连接代次，并让旧连接回调全部失效。
   */
  private createConnectionId() {
    this.connectionSeed += 1;
    this.activeConnectionId = this.connectionSeed;
    return this.activeConnectionId;
  }

  /**
   * 当前连接失效后让旧回调不再影响全局状态。
   */
  private invalidateCurrentConnection() {
    this.connectionSeed += 1;
    this.activeConnectionId = this.connectionSeed;
    this.pendingHeartbeatSeq = null;
  }

  /**
   * 判断回调是否仍然属于当前连接代次。
   */
  private isCurrentConnection(connectionId: number) {
    return connectionId > 0 && connectionId === this.activeConnectionId;
  }

  /**
   * 绑定当前 socketTask，并注册基于连接代次的回调。
   */
  private attachTask(connectionId: number, task: Taro.SocketTask) {
    if (!this.isCurrentConnection(connectionId)) {
      this.closeTaskSilently(task, '过期连接任务关闭');
      return;
    }
    this.socketTask = task;
    this.bindTaskEventListeners(connectionId, task);
  }

  /**
   * 绑定 task 级别事件，确保旧连接回调不会污染新连接。
   */
  private bindTaskEventListeners(connectionId: number, task: Taro.SocketTask) {
    task.onOpen(() => {
      this.handleSocketOpen(connectionId);
    });

    task.onMessage((res) => {
      this.handleSocketMessage(connectionId, res.data);
    });

    task.onClose((res) => {
      this.handleSocketClose(connectionId, res);
    });

    task.onError((err) => {
      this.handleSocketError(connectionId, err);
    });
  }

  /**
   * 兼容无 task 级事件的运行环境。
   */
  private bindGlobalEventListeners() {
    if (this.globalEventsBound) return;
    this.globalEventsBound = true;

    Taro.onSocketOpen(() => {
      this.handleSocketOpen(this.activeConnectionId);
    });

    Taro.onSocketMessage((res) => {
      this.handleSocketMessage(this.activeConnectionId, res.data);
    });

    Taro.onSocketClose((res) => {
      this.handleSocketClose(this.activeConnectionId, res);
    });

    Taro.onSocketError((err) => {
      this.handleSocketError(this.activeConnectionId, err);
    });
  }

  /**
   * 处理连接建立成功。
   */
  private async handleSocketOpen(connectionId: number) {
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }
    console.log(`WebSocket 连接已打开，连接代次：${connectionId}`);
    this.isConnected = true;
    this.isConnecting = false;
    this.socketState = SocketState.CONNECTED;
    this.reconnectAttempts = 0;
    this.resetHeartbeatState();
    if (this.isAppActive) {
      this.startHeartbeat(connectionId);
      this.startLocationReport(connectionId);
    }

    const uid = await this.getValidUid();
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }
    if (!uid) {
      console.warn('WebSocket 鉴权已取消，UID 无效');
      const expiredTask = this.socketTask;
      this.stopHeartbeat();
      this.invalidateCurrentConnection();
      this.socketTask = null;
      this.closeTaskSilently(expiredTask, 'UID 无效，关闭未鉴权连接');
      this.markConnectionClosed(connectionId);
      return;
    }
    this.sendInternal(
      { type: 'auth', appUserId: uid, timestamp: Date.now() },
      { silentWhenDisconnected: true }
    );
    this.notifyListeners('open', { status: 'connected' });
  }

  /**
   * 处理服务端消息。
   */
  private handleSocketMessage(connectionId: number, rawData: any) {
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }

    // console.log('收到 WebSocket 消息:', rawData);
    const data = this.normalizeIncomingMessage(rawData);
    if (this.isPongMessage(data)) {
      this.handlePong(connectionId);
    }

    const content = safeParse(data?.content || '{}', {});

    try {
      this.handleIncomingMessage(data, content);
      if (data?.type) {
        this.notifyListeners(data.type, data);
      }
      this.notifyListeners('message', data);
    } catch (error) {
      console.error('处理 WebSocket 消息出错:', error);
    }
  }

  /**
   * 处理连接关闭。
   */
  private handleSocketClose(connectionId: number, res: any) {
    if (!this.isCurrentConnection(connectionId)) {
      console.log('忽略过期连接关闭回调', res);
      return;
    }
    console.log('WebSocket 连接已关闭', res);
    this.markConnectionClosed(connectionId);
    this.notifyListeners('close', res);
    if (!this.isManualClose) {
      this.scheduleReconnect(connectionId, 'socket_close');
    }
  }

  /**
   * 处理连接异常。
   */
  private handleSocketError(connectionId: number, err: any) {
    if (!this.isCurrentConnection(connectionId)) {
      console.log('忽略过期连接错误回调', err);
      return;
    }
    console.error('WebSocket 错误:', err);
    this.markConnectionClosed(connectionId);
    this.notifyListeners('error', err);
    if (!this.isManualClose) {
      this.scheduleReconnect(connectionId, 'socket_error');
    }
  }

  /**
   * 标准化消息结构，兼容纯字符串 pong。
   */
  private normalizeIncomingMessage(rawData: any) {
    const parsedData = safeParse(rawData, rawData);
    if (typeof parsedData === 'string') {
      return {
        type: parsedData,
        raw: rawData,
      };
    }
    return parsedData || {};
  }

  /**
   * 获取有效 UID，约束连接头和鉴权消息都不能使用 -1 等无效值。
   */
  private async getValidUid() {
    const uid = await getStorage(_UID);
    return this.normalizeValidUid(uid);
  }

  /**
   * 标准化并校验 UID。
   */
  private normalizeValidUid(uid: any) {
    const normalizedUid = String(uid ?? '').trim();
    if (!normalizedUid || normalizedUid === '-1' || normalizedUid === 'undefined' || normalizedUid === 'null') {
      return null;
    }
    return normalizedUid;
  }

  /**
   * 判断消息是否为服务端 pong。
   */
  private isPongMessage(data: any) {
    const type = String(data?.type || '').toLowerCase();
    return type === 'pong';
  }

  /**
   * 根据 pong 清理等待状态，并恢复心跳健康计数。
   */
  private handlePong(connectionId: number) {
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }
    this.pendingHeartbeatSeq = null;
    this.missedHeartbeatCount = 0;
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
  }

  /**
   * 启动心跳轮询。
   */
  private startHeartbeat(connectionId: number) {
    this.stopHeartbeat();
    if (!this.isCurrentConnection(connectionId) || !this.isAppActive) {
      return;
    }
    this.heartbeatTimer = setInterval(() => {
      if (!this.isCurrentConnection(connectionId)) {
        return;
      }
      if (!this.isConnected || this.socketState !== SocketState.CONNECTED || !this.isAppActive) {
        return;
      }
      if (this.pendingHeartbeatSeq !== null) {
        return;
      }
      void this.sendHeartbeat(connectionId);
    }, this.heartbeatInterval);
  }

  /**
   * 发送一轮 ping，并等待服务端回 pong。
   */
  private async sendHeartbeat(connectionId: number) {
    if (!this.isCurrentConnection(connectionId) || !this.isAppActive) {
      return;
    }
    const appUserId = await this.getValidUid();
    if (!this.isCurrentConnection(connectionId) || !this.isAppActive) {
      return;
    }
    const currentHeartbeatSeq = ++this.heartbeatSeq;
    this.pendingHeartbeatSeq = currentHeartbeatSeq;
    const hasSent = this.sendInternal(
      { type: 'ping', appUserId, timestamp: Date.now(), seq: currentHeartbeatSeq },
      { silentWhenDisconnected: true }
    );

    if (!hasSent) {
      this.handleHeartbeatMiss(connectionId, currentHeartbeatSeq, 'ping_send_fail');
      return;
    }

    this.heartbeatTimeoutTimer = setTimeout(() => {
      this.handleHeartbeatMiss(connectionId, currentHeartbeatSeq, 'pong_timeout');
    }, this.heartbeatTimeout);
  }

  /**
   * 处理单轮心跳未收到 pong 的场景。
   */
  private handleHeartbeatMiss(connectionId: number, heartbeatSeq: number, reason: string) {
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }
    if (!this.isAppActive) {
      this.pendingHeartbeatSeq = null;
      return;
    }
    if (this.pendingHeartbeatSeq !== heartbeatSeq) {
      return;
    }

    this.pendingHeartbeatSeq = null;
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
    this.missedHeartbeatCount += 1;
    console.warn(`WebSocket 心跳未收到 pong，原因：${reason}，连续失败 ${this.missedHeartbeatCount} 次`);

    if (this.missedHeartbeatCount < this.maxHeartbeatMisses) {
      return;
    }

    this.safeReconnect(connectionId, reason);
  }

  /**
   * 安全关闭当前连接并发起重连，不让旧连接回调影响新连接。
   */
  private safeReconnect(connectionId: number, reason: string) {
    if (!this.isCurrentConnection(connectionId)) {
      return;
    }

    console.warn(`WebSocket 准备重连，原因：${reason}，连接代次：${connectionId}`);
    const expiredTask = this.socketTask;
    this.stopHeartbeat();
    this.markConnectionClosed(connectionId);
    this.invalidateCurrentConnection();
    this.socketTask = null;
    this.closeTaskSilently(expiredTask, `重连前关闭旧连接:${reason}`);
    this.scheduleReconnect(this.activeConnectionId, reason);
  }

  /**
   * 停止心跳及其超时检测。
   */
  private stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
    this.pendingHeartbeatSeq = null;
  }

  /**
   * 启动位置上报轮询。
   */
  private startLocationReport(connectionId: number) {
    this.stopLocationReport();
    if (!this.isCurrentConnection(connectionId) || !this.isAppActive || !this.isConnected) {
      return;
    }
    this.sendLocationMessage(connectionId);
    this.locationReportTimer = setInterval(() => {
      if (!this.isCurrentConnection(connectionId) || !this.isAppActive || !this.isConnected) {
        return;
      }
      this.sendLocationMessage(connectionId);
    }, this.locationReportInterval);
  }

  /**
   * 停止位置上报轮询。
   */
  private stopLocationReport() {
    if (this.locationReportTimer) {
      clearInterval(this.locationReportTimer);
      this.locationReportTimer = null;
    }
  }

  /**
   * 上报当前位置，失败时静默处理。
   */
  private async sendLocationMessage(connectionId: number) {
    if (!this.isCurrentConnection(connectionId) || !this.isConnected || !this.isAppActive) {
      return;
    }
    const userId = await this.getValidUid();
    if (!userId) {
      return;
    }
    try {
      const locationRes = await Taro.getLocation({
        type: 'gcj02',
        isHighAccuracy: true,
        highAccuracyExpireTime: 3000,
      } as any);
      if (!this.isCurrentConnection(connectionId) || !this.isConnected || !this.isAppActive) {
        return;
      }
      const longitude = Number(locationRes?.longitude);
      const latitude = Number(locationRes?.latitude);
      if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) {
        return;
      }
      this.sendInternal(
        {
          type: 'location',
          longitude,
          latitude,
          userId,
          timestamp: Date.now() * 1000,
        },
        { silentWhenDisconnected: true }
      );
    } catch (error) {
      // 定时定位失败静默处理，避免干扰业务流程
    }
  }

  /**
   * 重置心跳健康状态。
   */
  private resetHeartbeatState() {
    this.pendingHeartbeatSeq = null;
    this.missedHeartbeatCount = 0;
    if (this.heartbeatTimeoutTimer) {
      clearTimeout(this.heartbeatTimeoutTimer);
      this.heartbeatTimeoutTimer = null;
    }
  }

  /**
   * 调度下一次重连，后台期间延后到前台再处理。
   */
  private scheduleReconnect(connectionId: number, reason: string) {
    if (!this.isCurrentConnection(connectionId) || this.isManualClose || !this.url) {
      return;
    }
    if (!this.isAppActive) {
      this.shouldReconnectWhenActive = true;
      return;
    }
    if (this.reconnectTimer) {
      return;
    }

    const delay = this.getReconnectDelay();
    console.log(`正在尝试重连，原因：${reason}，延迟 ${delay}ms... (第 ${this.reconnectAttempts + 1} 次尝试)`);

    this.reconnectTimer = setTimeout(() => {
      this.reconnectTimer = null;
      if (this.isManualClose || !this.isAppActive || !this.url) {
        return;
      }
      this.reconnectAttempts += 1;
      this.connect(this.url);
    }, delay);
  }

  /**
   * 获取退避后的重连延迟。
   */
  private getReconnectDelay() {
    const retryLevel = Math.min(this.reconnectAttempts, 4);
    const baseDelay = Math.min(1000 * Math.pow(2, retryLevel), 15000);
    const jitter = Math.floor(Math.random() * 500);
    return baseDelay + jitter;
  }

  /**
   * 清理已有重连任务。
   */
  private clearReconnectTimer() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
  }

  /**
   * 发送消息的底层实现。
   */
  private sendInternal(data: any, options: { silentWhenDisconnected: boolean }) {
    if (!this.isConnected || this.socketState !== SocketState.CONNECTED) {
      if (!options.silentWhenDisconnected) {
        console.warn('WebSocket 未连接，消息未发送:', data);
      }
      return false;
    }

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

    Taro.sendSocketMessage({
      data: message,
      fail: (err) => {
        console.error('发送消息失败:', err);
      }
    });
    return true;
  }

  /**
   * 关闭指定 task，不影响当前代次判断。
   */
  private closeTaskSilently(task: Taro.SocketTask | null | undefined, reason: string) {
    if (!task) {
      return;
    }
    try {
      task.close({
        code: 1000,
        reason,
      });
    } catch (error) {
      console.error('关闭 SocketTask 失败:', error);
    }
  }

  /**
   * 统一更新关闭态。
   */
  private markConnectionClosed(connectionId: number) {
    if (this.isCurrentConnection(connectionId)) {
      this.socketTask = null;
    }
    this.isConnected = false;
    this.isConnecting = false;
    this.socketState = SocketState.IDLE;
    this.stopHeartbeat();
    this.stopLocationReport();
  }

  /**
   * 通知监听器。
   * @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) {
    const rawType = String(data?.type || '');
    const normalizedType = rawType.toLowerCase();
    if (normalizedType === 'auth_success' && rawType !== 'auth_success') {
      this.notifyListeners('auth_success', data);
    }
    if (data?.type === 'ORDER_STATUS') {
      const status = content?.status;
       const orderId = content?.orderId ?? data?.orderId;
      if (typeof status === 'number') {
        const mapped = this.mapOrderStatusToTripStatus(status);
        if (typeof mapped.tripStatus === 'number') {
          Taro.setStorageSync('tripStatus', mapped.tripStatus);
          if (orderId) {
            Taro.setStorageSync('orderId', orderId);
          }
        }
        this.notifyListeners('order_status', { status, orderId, ...mapped, data, content });
      }
    }
    if (data?.type === 'ORDER_ROUTE' || data?.type === 'ORDER_UPDATE_LINE') {
      const routeType = content?.routeType;
      const routeObj = safeParse(content?.route ?? '{}', {});
      const rawDirection = content?.direction;
      const direction = rawDirection == null ? NaN : (Number.isFinite(Number(rawDirection)) ? ((Number(rawDirection) % 360) + 360) % 360 : NaN);
      const duration = Number(routeObj?.duration ?? '0');
      const distance = Number(routeObj?.distance ?? '0');
      const points = this.normalizeRoutePoints(content);
      const servedPoints = this.normalizeServedPoints(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,
        servedPoints,
        data,
        content,
        forceFullRedraw: data?.type === 'ORDER_UPDATE_LINE'
      });
    }
    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 === 'ORDER_ERROR_REASSIGN') {
      const orderId = content?.orderId ?? data?.orderId;
      this.notifyListeners('order_error_reassign', { orderId, data, content });
    }
    if (data?.type === 'OPEN_TRUNK') {
      const isOpen = content?.isOpen ?? content?.open;
      this.notifyListeners('open_trunk', { isOpen, data, content });
    }
    if (data?.type === 'USER_OPEN_DOOR') {
      const orderId = content?.orderId ?? data?.orderId;
      this.notifyListeners('user_open_door', { orderId, data, content });
    }
    if (data?.type === 'UPDATE_END_ADDRESS_STATUS') {
      const status = Number(content?.status);
      this.notifyListeners('update_end_address_status', { status, data, content });
    }
  }

  /**
   * 归一化路线点。
   */
  private normalizeRoutePoints(content: any) {
    return this.normalizeRoutePointsByKey(content, 'polyline');
  }

  /**
   * 归一化已行驶路线点。
   */
  private normalizeServedPoints(content: any) {
    return this.normalizeRoutePointsByKey(content, 'served');
  }

  /**
   * 根据指定 key 归一化路线点。
   */
  private normalizeRoutePointsByKey(content: any, key: 'polyline' | 'served') {
    const route = safeParse(content?.route ?? '{}', {});
    const rawPoints = route?.[key] ?? [];
    const arrPoint = safeParse(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: 6 };
      case 8:
        return { tripStatus: 8 };
      case 9:
      case 10:
        return { tripStatus: 9 };
      default:
        return { tripStatus: undefined };
    }
  }
}

export default WebSocketManager.getInstance();
