<template>
    <view class="crush-canvas-container">
        <canvas
            canvas-id="crush"
            id="crush"
            class="crush-canvas"
            :style="{ width: canvasSizePx + 'px', height: canvasSizePx + 'px' }"
        ></canvas>
    </view>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue'

// 粒子接口
interface Particle {
    x: number
    y: number
    vx: number
    vy: number
    size: number
    color: string
    life: number
}

// 捏碎物品类型
type CrushItemType = 'egg' | 'walnut' | 'can' | 'balloon'

// 捏碎物品配置
interface CrushItemConfig {
    emoji: string
    color: string
    particles: number
}

const CRUSH_ITEMS: Record<CrushItemType, CrushItemConfig> = {
    egg: { emoji: '🥚', color: '#FFF9C4', particles: 20 },
    walnut: { emoji: '🥜', color: '#8D6E63', particles: 25 },
    can: { emoji: '🥫', color: '#B0BEC5', particles: 30 },
    balloon: { emoji: '🎈', color: '#FF5252', particles: 15 }
}

// 物理参数常量
const PHYSICS = {
    GRAVITY: 0.3,           // 重力加速度
    AIR_RESISTANCE: 0.98,   // 空气阻力系数
    LIFE_DECAY: 0.015,      // 生命值衰减速度（约 67 帧 = 1.1 秒）
    SPEED_MIN: 3,           // 最小初速度
    SPEED_MAX: 5,           // 最大初速度
    SIZE_MIN: 4,            // 最小粒子尺寸
    SIZE_MAX: 8,            // 最大粒子尺寸
    FPS: 60                 // 目标帧率
}

// Canvas 尺寸（px）
const canvasSizePx = ref<number>(240)
const ctx = ref<any>(null)
const timer = ref<number | null>(null)
const renderRunning = ref<boolean>(false)
const particles = ref<Particle[]>([])

onMounted(() => {
    initCanvas()
})

onBeforeUnmount(() => {
    cleanup()
})

// 初始化 Canvas
function initCanvas() {
    setTimeout(() => {
        const query = uni.createSelectorQuery().in(getCurrentInstance())
        query.select('.crush-canvas-container').boundingClientRect(data => {
            if (data && data.width > 0) {
                // 获取实际渲染尺寸（px）
                canvasSizePx.value = data.width
            }

            if (!ctx.value) {
                ctx.value = uni.createCanvasContext('crush', getCurrentInstance())
            }
        }).exec()
    }, 100)
}

// 触发捏碎特效（供外部调用）
function triggerCrush(itemType: CrushItemType) {
    if (!ctx.value) {
        return
    }

    const item = CRUSH_ITEMS[itemType]
    if (!item) {
        return
    }

    // 生成粒子
    const centerX = canvasSizePx.value / 2
    const centerY = canvasSizePx.value / 2
    const particleCount = item.particles

    for (let i = 0; i < particleCount; i++) {
        // 随机角度和速度（径向扩散）
        const angle = (Math.PI * 2 * i) / particleCount + (Math.random() - 0.5) * 0.5
        const speed = PHYSICS.SPEED_MIN + Math.random() * (PHYSICS.SPEED_MAX - PHYSICS.SPEED_MIN)

        particles.value.push({
            x: centerX,
            y: centerY,
            vx: Math.cos(angle) * speed,
            vy: Math.sin(angle) * speed,
            size: PHYSICS.SIZE_MIN + Math.random() * (PHYSICS.SIZE_MAX - PHYSICS.SIZE_MIN),
            color: item.color,
            life: 1.0
        })
    }

    ensureRenderLoop()
}

// 确保渲染循环运行
function ensureRenderLoop() {
    if (renderRunning.value) return
    renderRunning.value = true
    renderLoop()
}

// 渲染循环
function renderLoop() {
    // 更新粒子物理
    for (let i = particles.value.length - 1; i >= 0; i--) {
        const p = particles.value[i]

        // 重力
        p.vy += PHYSICS.GRAVITY

        // 空气阻力
        p.vx *= PHYSICS.AIR_RESISTANCE
        p.vy *= PHYSICS.AIR_RESISTANCE

        // 位置更新
        p.x += p.vx
        p.y += p.vy

        // 生命值衰减
        p.life -= PHYSICS.LIFE_DECAY

        // 移除死亡粒子或飞出画布的粒子
        const outOfBounds = p.x < -50 || p.x > canvasSizePx.value + 50 ||
                           p.y < -50 || p.y > canvasSizePx.value + 50
        if (p.life <= 0 || outOfBounds) {
            particles.value.splice(i, 1)
        }
    }

    // 绘制
    draw()
    ctx.value.draw(false)

    // 决定是否继续渲染
    if (particles.value.length > 0) {
        timer.value = setTimeout(() => {
            renderLoop()
        }, 1000 / PHYSICS.FPS) as unknown as number
    } else {
        timer.value = null
        renderRunning.value = false
    }
}

// 绘制粒子
function draw() {
    const c = ctx.value
    const size = canvasSizePx.value

    // 清空画布（透明）
    c.clearRect(0, 0, size, size)

    // 绘制所有粒子
    particles.value.forEach(p => {
        const alpha = p.life
        const currentSize = p.size * (0.5 + p.life * 0.5)

        c.beginPath()
        c.arc(p.x, p.y, currentSize, 0, Math.PI * 2)
        c.fillStyle = hexToRgba(p.color, alpha)
        c.fill()
    })
}

// 颜色转换工具
function hexToRgba(hex: string, alpha: number): string {
    const r = parseInt(hex.slice(1, 3), 16)
    const g = parseInt(hex.slice(3, 5), 16)
    const b = parseInt(hex.slice(5, 7), 16)
    return `rgba(${r}, ${g}, ${b}, ${alpha})`
}

// 清理资源
function cleanup() {
    if (timer.value) {
        clearTimeout(timer.value)
        timer.value = null
    }
    renderRunning.value = false
    particles.value = []
}

// 暴露方法供父组件调用
defineExpose({
    triggerCrush
})
</script>

<style scoped>
.crush-canvas-container {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none; /* 不阻挡点击事件 */
    z-index: 10;
}

.crush-canvas {
    display: block;
    width: 100%;
    height: 100%;
    background: transparent;
}
</style>
