/**
 * 原生 WebSocket 客户端封装：连接后台，监听 screen:roomChanged、room:state
 *
 * 消息协议（与服务端一致）：
 *   发送 → JSON.stringify({ event: string, data: any })
 *   接收 ← JSON.stringify({ event: string, data: any })
 */
import { setCurrentRoom, setGameState, getPlayerState, clearGameState, setPlayerGameOver, setAllGameOver, setPlayerTeam, setCountdown, clearCountdown, setRoomTimer, clearRoomTimer } from './stateManager.js'

/**
 * WebSocket 服务器地址配置
 *
 * 部署说明：
 * - 本地开发：ws://localhost:3000/ws
 * - 线上生产：wss://paopao.wxl66.cn/api/ws
 *   nginx 会把 /api/ws 转发到 localhost:3000/ws
 *
 * 环境变量优先级：
 * 1. import.meta.env.VITE_SOCKET_URL - 通过 .env 文件配置
 * 2. 默认根据当前环境自动选择
 */
console.log(import.meta.env.DEV)
const isDev = import.meta.env.DEV
const defaultServerUrl = import.meta.env.VITE_SOCKET_URL || (
  isDev
    ? 'ws://localhost:3000/ws'           // 开发环境
    : 'wss://paopao.wxl66.cn/api/ws'     // 生产环境：/api(nginx入口) + /ws(后端路由)
)

const RECONNECT_DELAY = 2000
const MAX_RECONNECT_DELAY = 10000

/** 0=未连接 1=已连接 2=重连中 */
let connectionStatus = 0
let ws = null
let reconnectTimer = null
let reconnectDelay = RECONNECT_DELAY
let manualClose = false

export function getConnectionStatus() {
  return connectionStatus
}

export function initSocket(serverUrl = defaultServerUrl) {
  if (ws) return
  manualClose = false
  _connect(serverUrl)
}

function _connect(serverUrl) {
  ws = new WebSocket(serverUrl)

  ws.addEventListener('open', () => {
    connectionStatus = 1
    reconnectDelay = RECONNECT_DELAY
    console.log('[Socket] 已连接')

    // 注册大屏身份
    _send('screen:join', {
      screenName: import.meta.env.VITE_SCREEN_NAME || 'big-screen-1',
    })
  })

  ws.addEventListener('close', () => {
    connectionStatus = 0
    console.warn('[Socket] 断开连接')
    ws = null
    if (!manualClose) _scheduleReconnect(serverUrl)
  })

  ws.addEventListener('error', (err) => {
    connectionStatus = 0
    console.error('[Socket] 连接失败:', err.message || err)
  })

  ws.addEventListener('message', (evt) => {
    let msg
    try {
      msg = JSON.parse(evt.data)
    } catch {
      return
    }
    const { event, data } = msg || {}
    _dispatch(event, data)
  })
}

function _send(event, data) {
  if (ws && ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ event, data }))
  }
}

function _scheduleReconnect(serverUrl) {
  connectionStatus = 2
  console.log(`[Socket] ${reconnectDelay}ms 后重连...`)
  reconnectTimer = setTimeout(() => {
    reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_DELAY)
    _connect(serverUrl)
  }, reconnectDelay)
}

function _dispatch(event, data) {
  switch (event) {
    /**
     * 服务器通知大屏切换房间
     * data: { roomId: string | null }
     */
    case 'screen:roomChanged': {
      const roomId = data?.roomId ?? null
      console.log('[Socket] screen:roomChanged, roomId:', roomId)
      clearCountdown()
      clearRoomTimer()
      setCurrentRoom(roomId)
      if (!roomId) clearGameState()
      break
    }

    /**
     * 接收小游戏实时状态帧
     */
    case 'room:state': {
      // 如果状态中有 team 信息，更新玩家队伍
      if (data?.playerId && data?.team) {
        setPlayerTeam(data.playerId, data.team)
      }
      // 如果状态中有 nickname，更新到状态中
      if (data?.playerId && data?.nickname) {
        const prev = getPlayerState(data.playerId) || {}
        data.nickname = data.nickname || prev.nickname
      }
      setGameState(data)
      break
    }

    /**
     * 玩家加入房间，更新队伍信息
     */
    case 'room:playerJoined': {
      // 如果有玩家列表，更新所有玩家的队伍信息
      if (data?.players) {
        data.players.forEach(p => {
          if (p.playerId && p.team) {
            setPlayerTeam(p.playerId, p.team)
          }
        })
      }
      break
    }

    /**
     * 某个玩家游戏结束（正常结束/泡泡压底）
     * data: { roomId, scores: {playerId: score, ...}, nicknames: {playerId: nickname, ...}, playerId, nickname }
     */
    case 'room:gameOver': {
      console.log('[Socket] room:gameOver', data)
      // 处理所有玩家的分数和队伍信息
      if (data?.scores) {
        Object.entries(data.scores).forEach(([pid, score]) => {
          const numPid = Number(pid)
          const playerNickname = data.nicknames?.[pid] || data.nickname
          // 更新队伍信息（确保结果页分组正确）
          if (data.teams?.[pid]) {
            setPlayerTeam(numPid, data.teams[pid])
          }
          setPlayerGameOver(numPid, score, playerNickname)
        })
      } else if (data?.playerId !== undefined) {
        setPlayerGameOver(data.playerId, data.score, data.nickname)
      }
      break
    }

    /**
     * 服务端统一倒计时（3→2→1）
     * data: { roomId, value }
     */
    case 'room:countdown': {
      console.log('[Socket] room:countdown, value:', data?.value)
      setCountdown(data?.value ?? 0)
      break
    }

    /**
     * 服务端通知游戏正式开始
     * data: { roomId, sessionId, gameDuration }
     */
    case 'room:gameStart': {
      console.log('[Socket] room:gameStart')
      clearCountdown()
      setRoomTimer(data?.gameDuration ?? 0, data?.startAtMs ?? Date.now())
      break
    }

    /**
     * 服务端倒计时到期，所有玩家强制结束
     * data: { roomId, durationSec }
     */
    case 'room:timeUp': {
      console.log('[Socket] room:timeUp，所有玩家游戏结束')
      clearRoomTimer()
      setAllGameOver()
      break
    }

    case 'screen:joined': {
      console.log('[Socket] 大屏注册成功:', data)
      clearCountdown()
      clearRoomTimer()
      setCurrentRoom(data?.currentRoomId ?? null)
      if (!data?.currentRoomId) clearGameState()
      break
    }

    case 'error': {
      console.error('[Socket] 服务端错误:', data?.message)
      break
    }

    default:
      break
  }
}

export function closeSocket() {
  manualClose = true
  clearTimeout(reconnectTimer)
  if (ws) {
    ws.close()
    ws = null
  }
  connectionStatus = 0
}
