/**
 * 微信小游戏 WebSocket 客户端封装
 *
 * 协议约定（与服务端对应）：
 *   发送 → JSON.stringify({ event: string, data: any })
 *   接收 ← JSON.stringify({ event: string, data: any })
 *
 * 用法：
 *   import GameSocket from './network/socket';
 *   GameSocket.connect();          // 在游戏初始化时调用一次
 *   GameSocket.sendState(state);   // 每帧上报状态
 *   GameSocket.emit('room:gameOver', { roomId, score });
 */

// ─── 配置 ──────────────────────────────────────────────────────────────────
/**
 * 线上部署说明：
 * - nginx: https://paopao.wxl66.cn/api/* → 转发到 http://localhost:3000/*
 *   注意：nginx 保留 /api 前缀，所以前端访问 /api/xxx 会转发到后端 /api/xxx
 * - 后端 HTTP API 前缀: /api (如 /api/rooms)
 * - 后端 WebSocket 路径: /ws (无 /api 前缀)
 *
 * 所以 WebSocket 连接地址为: wss://paopao.wxl66.cn/api/ws
 * nginx 会把 /api/ws 转发到 localhost:3000/ws
 */

// 自动判断运行环境：开发者工具 → 本地，体验版/正式版 → 线上
const isDev = (() => {
  try {
    const { miniProgram } = wx.getAccountInfoSync();
    // envVersion: 'develop'(开发者工具) | 'trial'(体验版) | 'release'(正式版)
    return miniProgram.envVersion === 'develop';
  } catch (_) {
    return false;
  }
})();

// 服务器域名
export const SERVER_HOST = isDev ? 'localhost:3000' : 'paopao.wxl66.cn';

// HTTP API 基础路径
export const API_BASE = isDev
  ? 'http://localhost:3000/api'           // 开发环境
  : 'https://paopao.wxl66.cn/api/api';    // 生产环境

// WebSocket URL
const WS_URL = isDev
  ? 'ws://localhost:3000/ws'              // 开发环境
  : 'wss://paopao.wxl66.cn/api/ws';       // 生产环境：/api(nginx入口) + /ws(后端路由)

const SERVER_URL = WS_URL;
// 重连间隔（毫秒）
const RECONNECT_DELAY = 3000;
// 最大重连次数，超出后不再尝试
const MAX_RECONNECT_COUNT = 5;

// ─── GameSocket ────────────────────────────────────────────────────────────

class GameSocket {
  constructor() {
    /** @type {WechatMiniprogram.SocketTask|null} */
    this._task = null;
    this._connected = false;
    this._connecting = false;
    this._url = SERVER_URL;
    this._reconnectCount = 0;
    this._reconnectTimer = null;
    /** 连接建立前积压的消息队列 */
    this._queue = [];
    /** 事件监听器 Map: event -> handler[] */
    this._listeners = {};
  }

  // ─── 公共 API ────────────────────────────────────────────────────────────

  /**
   * 连接到服务器并加入房间。
   * 若已连接或正在连接则忽略重复调用。
   * @param {string} [url] 服务端 WebSocket 地址，不传则使用默认值
   */
  /**
   * @param {string} [url]
   * @param {Function} [onOpen] 连接成功后立即执行的回调，用于发送 room:create / room:join
   */
  connect(url, onOpen) {
    if (url) this._url = url;
    if (onOpen) this._onOpenCallback = onOpen;
    // 已连接直接执行回调
    if (this._connected) {
      if (onOpen) { onOpen(); this._onOpenCallback = null; }
      return;
    }
    if (this._connecting) return;
    this._doConnect();
  }

  /**
   * 发送自定义事件
   * @param {string} event 事件名，如 'room:join'
   * @param {*} data 携带的数据
   */
  emit(event, data) {
    const raw = JSON.stringify({ event, data });
    if (!this._connected) {
      this._queue.push(raw);
      return;
    }
    this._sendRaw(raw);
  }

  /**
   * 监听服务端推送的事件
   * @param {string} event 事件名
   * @param {Function} handler 回调
   */
  on(event, handler) {
    if (!this._listeners[event]) this._listeners[event] = [];
    this._listeners[event].push(handler);
  }

  /**
   * 移除事件监听
   * @param {string} event
   * @param {Function} [handler] 不传则移除该事件所有监听
   */
  off(event, handler) {
    if (!this._listeners[event]) return;
    if (!handler) {
      delete this._listeners[event];
    } else {
      this._listeners[event] = this._listeners[event].filter(fn => fn !== handler);
    }
  }

  /**
   * 上报游戏实时状态帧（快捷方式，等同于 emit('room:state', ...)）
   * @param {object} stateData DataBus.serialize() 的返回值（附加了 roomId）
   */
  sendState(stateData) {
    this.emit('room:state', stateData);
  }

  /**
   * 主动断开连接，停止自动重连
   */
  disconnect() {
    this._stopReconnect();
    this._reconnectCount = MAX_RECONNECT_COUNT; // 阻止后续重连
    if (this._task) {
      try { this._task.close(); } catch (_) {}
    }
    this._task = null;
    this._connected = false;
    this._connecting = false;
  }

  // ─── 内部实现 ─────────────────────────────────────────────────────────────

  _doConnect() {
    this._connecting = true;

    const task = wx.connectSocket({
      url: this._url,
      complete: () => {},
    });

    task.onOpen(() => {
      this._task = task;
      this._connected = true;
      this._connecting = false;
      this._reconnectCount = 0;

      // 发送积压的消息（room:create / room:join 由业务层主动 emit，不在此自动发送）
      while (this._queue.length > 0) {
        this._sendRaw(this._queue.shift());
      }

      // 触发连接成功回调
      if (this._onOpenCallback) {
        this._onOpenCallback();
        this._onOpenCallback = null;
      }
    });

    task.onMessage((res) => {
      try {
        const msg = JSON.parse(res.data);
        const handlers = this._listeners[msg.event];
        if (handlers) {
          handlers.forEach(fn => {
            try { fn(msg.data); } catch (_) {}
          });
        }
      } catch (_) {}
    });

    task.onClose(() => {
      this._onDisconnected();
    });

    task.onError(() => {
      this._onDisconnected();
    });
  }

  _onDisconnected() {
    this._connected = false;
    this._connecting = false;
    this._task = null;
    this._scheduleReconnect();
  }

  _scheduleReconnect() {
    if (this._reconnectCount >= MAX_RECONNECT_COUNT) return;
    this._stopReconnect();
    this._reconnectTimer = GameGlobal.setTimeout(() => {
      this._reconnectCount++;
      this._doConnect();
    }, RECONNECT_DELAY);
  }

  _stopReconnect() {
    if (this._reconnectTimer) {
      GameGlobal.clearTimeout(this._reconnectTimer);
      this._reconnectTimer = null;
    }
  }

  _sendRaw(raw) {
    if (!this._connected || !this._task) return;
    try {
      this._task.send({ data: raw });
    } catch (_) {}
  }
}

export default new GameSocket();
