/**
 * 泡泡碎裂特效（大屏独立实现）
 *
 * 原理：大屏通过对比前后两帧的 grid 数据，检测哪些泡泡消失了，
 *       在消失位置播放一次碎裂动画。完全不依赖小游戏传来的 explosions 数据。
 *
 * 动画过程：闪光 → 碎片四散 → 渐隐消失，只播放一次。
 */
import { getBubbleRadius, BUBBLE_COLORS, gridToScreen } from './bubble.js'

// ─── 碎片粒子 ─────────────────────────────────────────────────────────────────

class Shard {
  constructor(x, y, color, angle, speed, size) {
    this.x = x
    this.y = y
    this.color = color
    this.size = size
    this.alpha = 1
    this.life = 0
    this.maxLife = 80 + Math.floor(Math.random() * 30)  // 80-110帧 ≈ 1.3-1.8秒
    this.rotation = Math.random() * Math.PI * 2
    this.rotSpeed = (Math.random() - 0.5) * 0.1
    this.gravity = 0.04
    this.vx = Math.cos(angle) * speed
    this.vy = Math.sin(angle) * speed
  }

  update() {
    this.life++
    this.vx *= 0.99
    this.vy *= 0.99
    this.vy += this.gravity
    this.x += this.vx
    this.y += this.vy
    this.rotation += this.rotSpeed
    this.size *= 0.997
    const t = this.life / this.maxLife
    this.alpha = t < 0.85 ? 1 - t * 0.2 : Math.max(0, (1 - t) / 0.15)
  }

  get alive() {
    return this.life < this.maxLife
  }

  render(ctx) {
    if (!this.alive || this.alpha <= 0) return
    ctx.globalAlpha = this.alpha
    ctx.fillStyle = this.color
    ctx.save()
    ctx.translate(this.x, this.y)
    ctx.rotate(this.rotation)
    ctx.beginPath()
    ctx.moveTo(-this.size, -this.size * 0.6)
    ctx.lineTo(this.size * 0.8, -this.size * 0.4)
    ctx.lineTo(this.size * 0.5, this.size * 0.7)
    ctx.lineTo(-this.size * 0.7, this.size * 0.5)
    ctx.closePath()
    ctx.fill()
    ctx.restore()
  }
}

// ─── 冲击波圆环 ───────────────────────────────────────────────────────────────

class Ring {
  constructor(x, y, color) {
    this.x = x
    this.y = y
    this.color = color
    this.r = getBubbleRadius() * 0.3
    this.maxR = getBubbleRadius() * 2.2
    this.life = 0
    this.maxLife = 40
  }

  get alive() {
    return this.life < this.maxLife
  }

  update() {
    this.life++
    const t = this.life / this.maxLife
    this.r = getBubbleRadius() * 0.3 + (this.maxR - getBubbleRadius() * 0.3) * t
    this.alpha = 0.6 * (1 - t)
  }

  render(ctx) {
    if (!this.alive || this.alpha <= 0) return
    ctx.globalAlpha = this.alpha
    ctx.strokeStyle = this.color
    ctx.lineWidth = 2
    ctx.beginPath()
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2)
    ctx.stroke()
  }
}

// ─── 单颗泡泡碎裂效果 ────────────────────────────────────────────────────────

class BubbleBurst {
  constructor(x, y, colorIdx) {
    this.alive = true
    this.shards = []
    this.ring = null
    this._x = x
    this._y = y

    const colorHex = BUBBLE_COLORS[colorIdx] || '#ffffff'
    const R = getBubbleRadius()

    this.flashAlpha = 1.0
    this.ring = new Ring(x, y, colorHex)

    // 碎片：10个不规则碎块
    const shardCount = 10
    for (let i = 0; i < shardCount; i++) {
      const angle = (i / shardCount) * Math.PI * 2 + (Math.random() - 0.5) * 0.5
      const speed = 0.6 + Math.random() * 1.2
      const size = R * (0.18 + Math.random() * 0.22)
      this.shards.push(new Shard(x, y, colorHex, angle, speed, size))
    }

    // 额外3个白色高光碎片
    for (let i = 0; i < 3; i++) {
      const angle = Math.random() * Math.PI * 2
      const speed = 0.8 + Math.random() * 1.5
      const size = R * 0.1
      this.shards.push(new Shard(x, y, '#ffffff', angle, speed, size))
    }
  }

  update() {
    if (this.flashAlpha > 0) {
      this.flashAlpha -= 0.05   // 约20帧(0.33秒)渐隐
    }

    for (const s of this.shards) {
      if (s.alive) s.update()
    }

    if (this.ring && this.ring.alive) {
      this.ring.update()
    }

    const shardsAlive = this.shards.some(s => s.alive)
    const ringAlive = this.ring && this.ring.alive
    if (!shardsAlive && !ringAlive && this.flashAlpha <= 0) {
      this.alive = false
    }
  }

  render(ctx) {
    if (this.flashAlpha > 0) {
      ctx.save()
      ctx.globalAlpha = this.flashAlpha * 0.7
      ctx.fillStyle = '#ffffff'
      ctx.beginPath()
      ctx.arc(this._x, this._y, getBubbleRadius() * 1.3, 0, Math.PI * 2)
      ctx.fill()
      ctx.restore()
    }

    ctx.save()
    if (this.ring && this.ring.alive) {
      this.ring.render(ctx)
    }
    ctx.restore()

    ctx.save()
    for (const s of this.shards) {
      if (s.alive) s.render(ctx)
    }
    ctx.restore()
    ctx.globalAlpha = 1
  }
}

// ─── 对外接口 ─────────────────────────────────────────────────────────────────

/** 每个玩家的上一帧 grid 快照 + 总球数：Map<playerId, { grid, totalCount }> */
const prevSnapshots = new Map()

/**
 * 统计 grid 中泡泡总数
 */
function countBubbles(grid) {
  let count = 0
  for (const row of grid) {
    if (!row) continue
    for (const c of row) {
      if (c > 0) count++
    }
  }
  return count
}

/**
 * 通过对比前后两帧 grid，检测消失的泡泡并创建碎裂效果
 *
 * 处理 pushDown 场景：消除后可能触发补行，grid 顶部插入新行导致行号整体偏移。
 * 通过计算行偏移量（新增行数）来对齐对比，确保消除+补行同帧发生时碎裂效果不丢失。
 */
export function detectAndCreateBursts(burstList, playerId, grid, pushAnimOffsetY = 0) {
  if (!grid || !grid.length) return

  const prev = prevSnapshots.get(playerId)
  const currCount = countBubbles(grid)

  if (prev) {
    const prevGrid = prev.grid

    // 计算行偏移：新grid比旧grid多出的行数（pushDown插入的新行数）
    // pushDown 总是在顶部插入偶数行（通常是2行），所以偏移量 = grid.length - prevGrid.length
    const rowOffset = Math.max(0, grid.length - prevGrid.length)

    // 逐格对比（旧grid的 row 对应新grid的 row+rowOffset）
    for (let prevRow = 0; prevRow < prevGrid.length; prevRow++) {
      const prevRowArr = prevGrid[prevRow]
      const currRow = prevRow + rowOffset
      const currRowArr = grid[currRow]
      if (!prevRowArr) continue
      for (let col = 0; col < prevRowArr.length; col++) {
        const prevColor = prevRowArr[col]
        const currColor = (currRowArr && currRowArr[col]) || 0
        if (prevColor > 0 && currColor === 0) {
          // 球消失了，用新的行号计算屏幕位置（因为球已经被推到新位置了）
          const { x, y } = gridToScreen(currRow, col)
          burstList.push(new BubbleBurst(x, y + (pushAnimOffsetY || 0), prevColor))
        }
      }
    }
  }

  // 保存当前帧快照
  prevSnapshots.set(playerId, {
    grid: grid.map(row => row ? [...row] : []),
    totalCount: currCount
  })
}

/**
 * 更新并绘制碎裂效果列表
 */
export function updateAndDrawBursts(ctx, burstList) {
  if (!burstList || !burstList.length) return
  for (let i = burstList.length - 1; i >= 0; i--) {
    const b = burstList[i]
    b.update()
    b.render(ctx)
    if (!b.alive) burstList.splice(i, 1)
  }
}

/**
 * 清除某个玩家的 grid 快照（玩家离开时调用）
 */
export function clearPrevGrid(playerId) {
  prevSnapshots.delete(playerId)
}
