/**
 * 大屏展示页入口：支持多玩家并排渲染
 */
import { initScaler } from './scaler.js'
import { getAllPlayerStates, clearGameState, getCurrentRoom, getPlayerTeam, getCountdown, getRoomTimer } from './stateManager.js'
import { initSocket, getConnectionStatus } from './socket.js'
import { drawBackground } from './renderer/background.js'
import { drawBubbleGrid } from './renderer/bubbleGrid.js'
import { drawBubble3D, getBubbleRadius, configureBubbleLayout } from './renderer/bubble.js'
import { drawShooter } from './renderer/shooter.js'
import { drawGameInfo, drawTeamResultOverlay, drawRoomTimerCard } from './renderer/gameinfo.js'
import { detectAndCreateBursts, updateAndDrawBursts, clearPrevGrid } from './renderer/explosion.js'
import { drawIdleScreen } from './renderer/idleScreen.js'
import { SCREEN_WIDTH, SCREEN_HEIGHT, configureScreenRatio, configureSafeArea } from './constants.js'

const container = document.getElementById('game-container')
const canvas    = document.getElementById('game-canvas')
const ctx       = canvas.getContext('2d')

const SCREEN_NAME = import.meta.env.VITE_SCREEN_NAME || 'big-screen-1'
const GAME_BG_URL = 'http://link-promotion-dev.oss-cn-shanghai.aliyuncs.com/back.png'
const gameBgImg = new Image()
gameBgImg.src = GAME_BG_URL

/** 每个玩家独立的碎裂效果列表：Map<playerId, BubbleBurst[]> */
const playerBursts = new Map()

const PLAYER_FRAME_MARGIN_X = 18
const PLAYER_FRAME_MARGIN_Y = 18
const PLAYER_FRAME_RADIUS = 18

let frameCount = 0

// ─── 缩放 ─────────────────────────────────────────────────────────────────────

function applyScaler(playerCount = 1) {
  // 多玩家时横向并排，总宽度 = 单格宽 × 人数
  const totalDesignW = SCREEN_WIDTH * Math.max(1, playerCount)
  initScaler({
    designWidth:  totalDesignW,
    designHeight: SCREEN_HEIGHT,
    containerEl:  container,
    canvasEl:     canvas,
  })
}

function drawPlayerGameBackground() {
  if (gameBgImg.complete && gameBgImg.naturalWidth > 0) {
    ctx.drawImage(gameBgImg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
    return
  }

  ctx.fillStyle = '#1a0a2e'
  ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)
}

function roundRectPath(x, y, w, h, r) {
  ctx.beginPath()
  ctx.moveTo(x + r, y)
  ctx.lineTo(x + w - r, y)
  ctx.arcTo(x + w, y, x + w, y + r, r)
  ctx.lineTo(x + w, y + h - r)
  ctx.arcTo(x + w, y + h, x + w - r, y + h, r)
  ctx.lineTo(x + r, y + h)
  ctx.arcTo(x, y + h, x, y + h - r, r)
  ctx.lineTo(x, y + r)
  ctx.arcTo(x, y, x + r, y, r)
  ctx.closePath()
}

function getPlayerFrameRect() {
  return {
    x: PLAYER_FRAME_MARGIN_X,
    y: PLAYER_FRAME_MARGIN_Y,
    w: SCREEN_WIDTH - PLAYER_FRAME_MARGIN_X * 2,
    h: SCREEN_HEIGHT - PLAYER_FRAME_MARGIN_Y * 2,
    r: PLAYER_FRAME_RADIUS,
  }
}

function drawPlayerFrameShell(frame) {
  ctx.save()
  ctx.shadowColor = 'rgba(0,0,0,0.38)'
  ctx.shadowBlur = 24
  ctx.shadowOffsetY = 10
  const bg = ctx.createLinearGradient(frame.x, frame.y, frame.x, frame.y + frame.h)
  bg.addColorStop(0, 'rgba(20,10,42,0.30)')
  bg.addColorStop(1, 'rgba(8,4,22,0.46)')
  ctx.fillStyle = bg
  roundRectPath(frame.x, frame.y, frame.w, frame.h, frame.r)
  ctx.fill()
  ctx.restore()
}

function drawPlayerFrameBorder(frame) {
  ctx.save()
  ctx.lineWidth = 3
  ctx.strokeStyle = 'rgba(251,191,36,0.82)'
  ctx.shadowColor = 'rgba(251,191,36,0.28)'
  ctx.shadowBlur = 18
  roundRectPath(frame.x, frame.y, frame.w, frame.h, frame.r)
  ctx.stroke()
  ctx.shadowBlur = 0

  ctx.save()
  roundRectPath(frame.x, frame.y, frame.w, frame.h, frame.r)
  ctx.clip()
  const hl = ctx.createLinearGradient(frame.x, frame.y, frame.x, frame.y + frame.h * 0.22)
  hl.addColorStop(0, 'rgba(255,255,255,0.22)')
  hl.addColorStop(1, 'rgba(255,255,255,0)')
  ctx.fillStyle = hl
  ctx.fillRect(frame.x, frame.y, frame.w, frame.h * 0.22)
  ctx.restore()
  ctx.restore()
}

// ─── 单个玩家画面渲染 ──────────────────────────────────────────────────────────

function renderPlayer(state, offsetX, roomId) {
  const pid = state.playerId ?? 1
  const frame = getPlayerFrameRect()
  const contentScale = Math.min(frame.w / SCREEN_WIDTH, frame.h / SCREEN_HEIGHT)
  const contentW = SCREEN_WIDTH * contentScale
  const contentH = SCREEN_HEIGHT * contentScale
  const contentX = frame.x + (frame.w - contentW) / 2
  const contentY = frame.y + (frame.h - contentH) / 2

  // 从 grid 数据推算偶数行列数，动态调整泡泡大小
  // 偶数行(row 0)的列数决定了整个网格的列配置
  if (state.grid && state.grid.length && state.grid[0]) {
    configureBubbleLayout(state.grid[0].length)
  }

  // 初始化该玩家的碎裂效果列表
  if (!playerBursts.has(pid)) playerBursts.set(pid, [])
  const bursts = playerBursts.get(pid)

  ctx.save()
  ctx.translate(offsetX, 0)

  drawPlayerFrameShell(frame)

  ctx.save()
  roundRectPath(frame.x, frame.y, frame.w, frame.h, frame.r)
  ctx.clip()
  ctx.translate(contentX, contentY)
  ctx.scale(contentScale, contentScale)

  drawPlayerGameBackground()

  // 泡泡网格
  if (state.grid && state.grid.length) {
    drawBubbleGrid(ctx, state.grid, state.pushAnimOffsetY ?? 0)
  }

  // 飞行中的泡泡（坐标是小游戏端屏幕坐标，需缩放到大屏设计稿坐标系）
  if (state.fireBubbles && state.fireBubbles.length) {
    const scale = state.screenWidth ? SCREEN_WIDTH / state.screenWidth : 1
    for (const fb of state.fireBubbles) {
      if (fb.active !== false) {
        drawBubble3D(ctx, fb.x * scale, fb.y * scale, getBubbleRadius(), fb.color || 1)
      }
    }
  }

  // 碎裂特效：通过对比前后帧grid自动检测消失的球
  if (state.grid) {
    detectAndCreateBursts(bursts, pid, state.grid, state.pushAnimOffsetY ?? 0)
  }
  updateAndDrawBursts(ctx, bursts)

  // 射击器
  if (state.shooter) {
    drawShooter(ctx, state.shooter)
  }

  // 得分 / 结束
  drawGameInfo(ctx, state.score ?? 0, state.isGameOver ?? false, roomId ?? state.roomId ?? '', state.nickname ?? '')

  ctx.restore()
  drawPlayerFrameBorder(frame)
  ctx.restore()
}

// ─── 多玩家分隔线 ──────────────────────────────────────────────────────────────

function drawDivider(x) {
  ctx.save()
  const top = PLAYER_FRAME_MARGIN_Y + 26
  const bottom = SCREEN_HEIGHT - PLAYER_FRAME_MARGIN_Y - 26
  const grad = ctx.createLinearGradient(x, top, x, bottom)
  grad.addColorStop(0,   'rgba(139,92,246,0)')
  grad.addColorStop(0.2, 'rgba(139,92,246,0.5)')
  grad.addColorStop(0.8, 'rgba(139,92,246,0.5)')
  grad.addColorStop(1,   'rgba(139,92,246,0)')
  ctx.strokeStyle = grad
  ctx.lineWidth = 2
  ctx.setLineDash([6, 6])
  ctx.beginPath()
  ctx.moveTo(x, top)
  ctx.lineTo(x, bottom)
  ctx.stroke()
  ctx.setLineDash([])
  ctx.restore()
}

// ─── VS 分隔线（两队中间）──────────────────────────────────────────────────────

function drawVSDivider(x) {
  ctx.save()
  const centerY = SCREEN_HEIGHT / 2
  const pillW = 58
  const pillH = 70
  const pillX = x - pillW / 2
  const pillY = centerY - pillH / 2

  ctx.fillStyle = 'rgba(12,18,36,0.82)'
  ctx.strokeStyle = 'rgba(103,232,249,0.9)'
  ctx.lineWidth = 2
  ctx.shadowColor = 'rgba(34,211,238,0.35)'
  ctx.shadowBlur = 18
  roundRectPath(pillX, pillY, pillW, pillH, 16)
  ctx.fill()
  ctx.stroke()

  ctx.shadowBlur = 0
  ctx.fillStyle = 'rgba(125,211,252,0.95)'
  ctx.fillRect(pillX + 8, pillY + 8, pillW - 16, 3)

  // V|S 文字
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  ctx.font = 'bold 44px Arial'
  ctx.fillStyle = '#F8FAFC'
  ctx.strokeStyle = 'rgba(8,15,34,0.9)'
  ctx.lineWidth = 4
  ctx.shadowColor = 'rgba(103,232,249,0.65)'
  ctx.shadowBlur = 16
  ctx.strokeText('V|S', x, centerY + 1)
  ctx.fillText('V|S', x, centerY)
  ctx.shadowBlur = 0
  ctx.restore()
}


// ─── 倒计时覆盖层 ─────────────────────────────────────────────────────────────

function drawCountdownOverlay(totalWidth) {
  const countdown = getCountdown()
  if (!countdown.active) return

  const cx = totalWidth / 2
  const cy = SCREEN_HEIGHT / 2

  ctx.save()
  ctx.setTransform(1, 0, 0, 1, 0, 0)

  // 半透明遮罩
  ctx.fillStyle = 'rgba(0,0,0,0.6)'
  ctx.fillRect(0, 0, totalWidth, SCREEN_HEIGHT)

  // 脉冲效果
  const pulse = 1 + 0.08 * Math.sin(frameCount * 0.15)
  const fontSize = Math.min(totalWidth, SCREEN_HEIGHT) * 0.3 * pulse

  // 倒计时数字
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  ctx.font = `bold ${fontSize}px Arial`
  ctx.shadowColor = 'rgba(251,191,36,0.8)'
  ctx.shadowBlur = 30

  const numGrad = ctx.createLinearGradient(cx - 60, cy - 40, cx + 60, cy + 40)
  numGrad.addColorStop(0, '#FDE68A')
  numGrad.addColorStop(0.5, '#FCD34D')
  numGrad.addColorStop(1, '#F59E0B')
  ctx.fillStyle = numGrad
  ctx.fillText(String(countdown.value), cx, cy)
  ctx.shadowBlur = 0

  // "游戏即将开始" 文字
  const subFontSize = Math.min(totalWidth, SCREEN_HEIGHT) * 0.06
  ctx.font = `bold ${subFontSize}px Arial`
  ctx.fillStyle = 'rgba(196,181,253,0.9)'
  ctx.fillText('游戏即将开始', cx, cy + SCREEN_HEIGHT * 0.15)

  ctx.restore()
}

// ─── 主循环 ───────────────────────────────────────────────────────────────────

let _lastPlayerCount = 1
let _lastScreenHeight = SCREEN_HEIGHT

function loop() {
  frameCount++
  const states  = getAllPlayerStates()
  const roomId  = getCurrentRoom()
  const connStatus = getConnectionStatus()
  const playerCount = states.length || 1
  const totalWidth = SCREEN_WIDTH * Math.max(playerCount, 1)
  const roomTimer = getRoomTimer()
  let allGameOver = false

  // 从任意一个玩家的 state 中提取屏幕比例和安全区域，在渲染前统一配置
  if (states.length > 0 && states[0].screenRatio) {
    configureScreenRatio(states[0].screenRatio)
    configureSafeArea(states[0].safeAreaTop, states[0].safeAreaBottom, states[0].screenWidth)
  }

  // 按队伍分组
  const teamAStates = states.filter(s => getPlayerTeam(s.playerId ?? 1) === 'A')
  const teamBStates = states.filter(s => getPlayerTeam(s.playerId ?? 1) === 'B')
  const totalSlots = Math.max(teamAStates.length + teamBStates.length, 1)

  // 人数变化 或 屏幕高度变化时重新计算缩放
  if (totalSlots !== _lastPlayerCount || SCREEN_HEIGHT !== _lastScreenHeight) {
    _lastPlayerCount = totalSlots
    _lastScreenHeight = SCREEN_HEIGHT
    applyScaler(totalSlots)
    // 清理消失玩家的碎裂列表和grid快照
    for (const pid of playerBursts.keys()) {
      if (!states.find(s => (s.playerId ?? 1) === pid)) {
        playerBursts.delete(pid)
        clearPrevGrid(pid)
      }
    }
  }

  // 绘制背景（横向铺满整个大屏）
  ctx.save()
  ctx.setTransform(1, 0, 0, 1, 0, 0)
  drawBackground(ctx, SCREEN_WIDTH * totalSlots, SCREEN_HEIGHT)
  ctx.restore()

  if (states.length > 0) {
    allGameOver = states.every(s => s.isGameOver)

    if (allGameOver && states.length > 1) {
      // 最终结果页使用干净背景，不再保留各玩家游戏盘面
      const totalWidth = SCREEN_WIDTH * totalSlots
      ctx.save()
      ctx.setTransform(1, 0, 0, 1, 0, 0)
      ctx.clearRect(0, 0, totalWidth, SCREEN_HEIGHT)
      drawBackground(ctx, totalWidth, SCREEN_HEIGHT)
      drawTeamResultOverlay(ctx, states, getPlayerTeam, totalWidth)
      ctx.restore()
    } else {
      // ── 按队伍分组渲染：A队左，B队右 ────────────────────────────────────────
      let currentOffsetX = 0
      const dividerXs = []
      const hasBothTeams = teamAStates.length > 0 && teamBStates.length > 0

      // 渲染A队玩家
      teamAStates.forEach((state, idx) => {
        const offsetX = currentOffsetX

        // 记录分隔线（A队内部）
        if (idx > 0) dividerXs.push(offsetX)

        renderPlayer(state, offsetX, roomId)

        currentOffsetX += SCREEN_WIDTH
      })

      // 渲染B队玩家
      teamBStates.forEach((state, idx) => {
        const offsetX = currentOffsetX

        // 记录分隔线（B队内部）
        if (idx > 0) dividerXs.push(offsetX)

        renderPlayer(state, offsetX, roomId)

        currentOffsetX += SCREEN_WIDTH
      })

      dividerXs.forEach(drawDivider)
      if (hasBothTeams) drawVSDivider(totalWidth / 2)
    }
  } else {
    // ── 空闲等待画面 ──────────────────────────────────────────────────────
    drawIdleScreen(ctx, SCREEN_WIDTH, SCREEN_HEIGHT, roomId, connStatus, SCREEN_NAME, frameCount)
  }

  if (states.length > 0 && !allGameOver && roomTimer.active) {
    drawRoomTimerCard(ctx, roomTimer.remainingSec, totalWidth)
  }

  // ── 倒计时覆盖层（服务端驱动，所有端同步）──────────────────────────────
  drawCountdownOverlay(SCREEN_WIDTH * totalSlots)

  requestAnimationFrame(loop)
}

// ─── 启动 ─────────────────────────────────────────────────────────────────────

function start() {
  applyScaler(1)
  initSocket()
  window.addEventListener('resize', () => applyScaler(_lastPlayerCount))
  loop()
}

start()
