import CryptoJS from 'crypto-js'

/** 从 Vuex 取直播间共享 WebSocket */
export function getLiveSocket(store, liveId) {
  if (!store || liveId == null) return null
  const key = String(liveId)
  return store.state.liveWs[key] || store.state.liveWs[liveId] || null
}

export class LiveWS {
  /**
   * @param {string} url - WebSocket 服务器地址
   * @param {number|string} liveId - 直播间ID
   * @param {number|string} userId - 用户ID
   * @param {number} checkInterval - 检查连接状态的时间间隔，单位毫秒
   * @param {number} reconnectDelay - 连接断开后重连的延迟，单位毫秒
   */
  constructor(url, liveId, userId, checkInterval = 5000, reconnectDelay = 3000) {
    this.baseUrl = url;
    this.liveId = liveId;
    this.userId = userId;
    this.checkInterval = checkInterval;
    this.reconnectDelay = reconnectDelay;
    this.ws = null;
    this.reconnectTimer = null;
    this.heartbeatTimer = null;
    this.isManualClose = false;
    this._messageHandlers = new Set();
    this.refreshSignedUrl();
    this.connect();
    this.startHeartbeat();
  }

  /** 每次建连/重连刷新 timestamp+signature，避免验签过期 */
  refreshSignedUrl() {
    const timestamp = new Date().getTime();
    const userType = 1;
    const signature = CryptoJS.HmacSHA256(
      CryptoJS.enc.Utf8.parse('' + this.liveId + this.userId + userType + timestamp),
      CryptoJS.enc.Utf8.parse(String(timestamp))).toString(CryptoJS.enc.Hex);
    this.url = this.baseUrl + `?liveId=${this.liveId}&userId=${this.userId}&userType=${userType}&timestamp=${timestamp}&signature=${signature}`;
  }

  connect() {
    // 如果已经有一个连接处于 OPEN 或 CONNECTING 状态，则不再创建新连接
    if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
      return;
    }

    this.refreshSignedUrl();
    this.ws = new WebSocket(this.url);

    // 绑定事件
    this.ws.onopen = () => {
      if (this.reconnectTimer) {
        clearTimeout(this.reconnectTimer);
        this.reconnectTimer = null;
      }
    };

    this.ws.onmessage = (event) => {
      this._dispatchMessage(event);
    };

    this.ws.onerror = () => {};

    this.ws.onclose = () => {
      // 如果不是主动关闭，则重连
      if (!this.isManualClose) {
        setTimeout(() => this.reconnect(), this.reconnectDelay);
      }
    };
  }

  /** @deprecated 兼容旧写法，请优先使用 addMessageListener */
  onmessage(event) {}

  _dispatchMessage(event) {
    if (this._messageHandlers.size > 0) {
      this._messageHandlers.forEach((handler) => {
        try {
          handler(event);
        } catch (e) {
          console.error('[LiveWS] message handler error', e);
        }
      });
      return;
    }
    // 兼容：外部直接赋值 socket.onmessage = fn
    if (typeof this.onmessage === 'function') {
      this.onmessage(event);
    }
  }

  addMessageListener(handler) {
    if (typeof handler === 'function') {
      this._messageHandlers.add(handler);
    }
  }

  removeMessageListener(handler) {
    if (handler) {
      this._messageHandlers.delete(handler);
    }
  }

  reconnect() {
    this.connect();
  }

  // 调度重连
  scheduleReconnect() {
    // 避免多次重连定时器同时存在
    if (this.reconnectTimer) return;
    this.reconnectTimer = setTimeout(() => {
      this.connect();
    }, this.reconnectDelay);
  }

  // 定时检查连接状态
  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
        this.scheduleReconnect();
      } else {
        // 发送信息
        this.ws.send(JSON.stringify({'cmd':'heartbeat','msg':'ping', 'liveId': this.liveId, 'userId': this.userId}));
      }
    }, this.checkInterval);
  }

  // 主动关闭 WebSocket 连接，并清除定时任务
  close() {
    this.isManualClose = true;
    this._messageHandlers.clear();
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }

  get readyState() {
    return this.ws ? this.ws.readyState : WebSocket.CLOSED;
  }

  // 发送消息方法
  send(message) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(message);
      return true;
    }
    console.error("WebSocket is not open. Message not sent.");
    return false;
  }
}
