// 信令客户端：对应 Android 端 WebSocketClient / Flutter signaling_client.dart。
// 连接成功后自动发送 REGISTER（deviceType=CONTROLLER），
// 负责 OFFER / ICE_CANDIDATE 的发送，以及 ANSWER / ICE_CANDIDATE / 通知类的接收与转发。
export class SignalingClient {
  constructor({ serverUrl, deviceId, onConnected, onDisconnected, onError, onMessage }) {
    this.serverUrl = serverUrl;
    this.deviceId = deviceId;
    this.onConnected = onConnected;
    this.onDisconnected = onDisconnected;
    this.onError = onError;
    this.onMessage = onMessage;
    this.ws = null;
  }

  connect() {
    try {
      this.ws = new WebSocket(this.serverUrl);
      this.ws.onopen = () => {
        this.register();
        this.onConnected && this.onConnected();
        // 启动心跳保活：每 25 秒发送 ping，防止中间代理或服务器因空闲超时断开连接
        this._startHeartbeat();
      };
      this.ws.onmessage = (ev) => {
        let msg;
        try {
          msg = JSON.parse(ev.data);
        } catch {
          return;
        }
        this.onMessage && this.onMessage(msg);
      };
      this.ws.onclose = (ev) => {
        // 记录关闭码和原因，便于诊断断连根因：
        // 1000 = 正常关闭, 1001 = 离开, 1006 = 异常断开（无 close frame）
        // 1009 = 消息过大, 1011 = 服务端异常
        let hint = '';
        if (ev.code === 1009) {
          // 关闭帧由服务端发出：服务端 WebSocket 单条消息缓冲上限过小，
          // 导致 SDP/ICE 等稍大的消息被拒绝。需在信令服务端调大消息大小上限
          // （Spring 原生 WebSocket 用 configureWebSocketTransport#setMessageSizeLimit）。
          hint = '（消息过大：请检查信令服务端 WebSocket 的 messageSizeLimit 配置是否过小）';
        }
        console.warn('[信令] WebSocket 已关闭 code=%d reason=%s wasClean=%s%s',
          ev.code, ev.reason || '(无)', ev.wasClean, hint);
        this._stopHeartbeat();
        this.onDisconnected && this.onDisconnected(ev.code, ev.reason);
      };
      this.ws.onerror = (e) => {
        console.error('[信令] WebSocket 错误', e);
        this.onError && this.onError(e?.message || 'WebSocket 错误');
      };
    } catch (e) {
      this.onError && this.onError(e.message);
    }
  }

  _startHeartbeat() {
    this._stopHeartbeat();
    this._heartbeatTimer = setInterval(() => {
      if (this.ws && this.ws.readyState === WebSocket.OPEN) {
        // 发送轻量级 ping 消息，保持连接活跃（服务端会忽略未知类型消息）
        try { this.ws.send(JSON.stringify({ type: 'PING' })); } catch { /* ignore */ }
      }
    }, 25000);
  }

  _stopHeartbeat() {
    if (this._heartbeatTimer) { clearInterval(this._heartbeatTimer); this._heartbeatTimer = null; }
  }

  register() {
    this.send({
      type: 'REGISTER',
      fromDeviceId: this.deviceId,
      deviceType: 'CONTROLLER',
    });
  }

  requestDeviceList() {
    this.send({ type: 'DEVICE_LIST', fromDeviceId: this.deviceId });
  }

  sendOffer(sdp, toDeviceId, authType = null, authValue = null) {
    const msg = {
      type: 'OFFER',
      fromDeviceId: this.deviceId,
      toDeviceId,
      deviceType: 'CONTROLLER',
      payload: JSON.stringify({ sdp }),
    };
    if (authType) msg.authType = authType;
    if (authValue != null) msg.authValue = authValue;
    this.send(msg);
  }

  sendIceCandidate(candidate, toDeviceId) {
    const payload = {
      sdpMid: candidate.sdpMid,
      sdpMLineIndex: candidate.sdpMLineIndex,
      candidate: candidate.candidate,
    };
    this.send({
      type: 'ICE_CANDIDATE',
      fromDeviceId: this.deviceId,
      toDeviceId,
      deviceType: 'CONTROLLER',
      payload: JSON.stringify(payload),
    });
  }

  send(msg) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(msg));
    }
  }

  disconnect() {
    this._stopHeartbeat();
    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }

  get isConnected() {
    return this.ws && this.ws.readyState === WebSocket.OPEN;
  }
}
