/**
 * 文件功能：聊天室烟花特效（真实感版本）
 *
 * 完整模拟真实烟花流程：
 *  1. 火箭从底部带着尾迹飞向目标高度
 *  2. 到达位置后爆炸，产生 3 种形态：球形/柳叶/星形
 *  3. 每颗粒子带历史轨迹尾巴，随重力下坠并消散
 *
 * 全程透明 Canvas，不遮挡聊天背景。
 */

const FireworksEffect = (() => {
    // ─── 火箭类 ──────────────────────────────────────────
    class Rocket {
        /**
         * @param {number}  x        发射 x 位置
         * @param {number}  targetY  爆炸目标高度（距顶部比例）
         * @param {string}  color    爆炸颜色
         * @param {string}  type     爆炸类型：sphere / willow / ring
         */
        constructor(x, targetY, color, type, canvasHeight) {
            this.x = x;
            this.y = canvasHeight; // 从画布底部出发
            this.targetY = targetY;
            this.color = color;
            this.type = type;

            // 根据飞行距离动态计算初始速度，保证必然到达目标高度
            // 等比级数求和：total = vy / (1 - 0.98) = vy × 50
            // 加 10%~20% 余量，使火箭略微超过目标再触发爆炸（更真实）
            const dist = canvasHeight - targetY;
            this.vy = -(dist / 50) * (1.1 + Math.random() * 0.15);

            this.trail = []; // 尾迹历史坐标
            this.exploded = false;
            this.done = false;
        }

        /** 更新火箭位置，到达目标高度后标记为已爆炸 */
        update() {
            this.trail.push({ x: this.x, y: this.y });
            if (this.trail.length > 10) this.trail.shift();
            this.y += this.vy;
            this.vy *= 0.98; // 轻微减速（仿真阻力）
            if (this.y <= this.targetY) {
                this.exploded = true;
                this.done = true;
            }
        }

        /** 绘制火箭（白色头部 + 橙色尾迹） */
        draw(ctx) {
            // 尾迹（由新到旧逐渐变淡）
            for (let i = 0; i < this.trail.length; i++) {
                const a = (i / this.trail.length) * 0.6;
                ctx.save();
                ctx.globalAlpha = a;
                ctx.fillStyle = "#ffaa44";
                ctx.shadowColor = "#ff6600";
                ctx.shadowBlur = 6;
                ctx.beginPath();
                ctx.arc(this.trail[i].x, this.trail[i].y, 2, 0, Math.PI * 2);
                ctx.fill();
                ctx.restore();
            }
            // 火箭头部（亮白色光点）
            ctx.save();
            ctx.fillStyle = "#ffffff";
            ctx.shadowColor = "#ffcc88";
            ctx.shadowBlur = 10;
            ctx.beginPath();
            ctx.arc(this.x, this.y, 3, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
        }
    }

    // ─── 爆炸粒子类 ──────────────────────────────────────
    class Particle {
        /**
         * @param {number}  x      爆炸中心 x
         * @param {number}  y      爆炸中心 y
         * @param {string}  color  粒子颜色
         * @param {string}  type   爆炸类型
         * @param {number}  angle  发射角度（ring 类型用）
         */
        constructor(x, y, color, type, angle) {
            this.x = x;
            this.y = y;
            this.color = color;
            this.trail = [];

            let speed;
            if (type === "ring") {
                // 环形：均匀角度，固定速度
                speed = 5 + Math.random() * 2;
                this.vx = Math.cos(angle) * speed;
                this.vy = Math.sin(angle) * speed;
                this.gravity = 0.06;
                this.decay = 0.014;
                this.radius = 2;
            } else if (type === "willow") {
                // 柳叶：慢速，在空中下垂
                speed = Math.random() * 3 + 1;
                const a = Math.random() * Math.PI * 2;
                this.vx = Math.cos(a) * speed;
                this.vy = Math.sin(a) * speed - 2; // 初速稍微向上
                this.gravity = 0.07;
                this.decay = 0.009; // 衰减慢，拖出长尾
                this.radius = 1.5;
            } else {
                // sphere：标准球形爆炸
                speed = Math.random() * 6 + 2;
                const a = Math.random() * Math.PI * 2;
                this.vx = Math.cos(a) * speed;
                this.vy = Math.sin(a) * speed;
                this.gravity = 0.1;
                this.decay = 0.016;
                this.radius = Math.random() * 2 + 1.5;
            }

            this.alpha = 1;
            // 部分粒子有闪烁效果
            this.sparkle = Math.random() > 0.6;
            this.frame = 0;
        }

        /** 更新粒子物理状态 */
        update() {
            this.frame++;
            // 保存轨迹历史（尾迹长度由透明度控制）
            this.trail.push({ x: this.x, y: this.y });
            if (this.trail.length > 6) this.trail.shift();

            this.vy += this.gravity;
            this.x += this.vx;
            this.y += this.vy;
            this.vx *= 0.985;
            this.vy *= 0.985;

            // 闪烁：每隔几帧透明度轻微抖动
            if (this.sparkle && this.frame % 4 === 0) {
                this.alpha = Math.max(
                    0,
                    this.alpha - this.decay * (0.5 + Math.random()),
                );
            } else {
                this.alpha -= this.decay;
            }
        }

        /** 绘制粒子及其运动轨迹尾迹 */
        draw(ctx) {
            // 绘制尾迹
            for (let i = 0; i < this.trail.length; i++) {
                const a = (i / this.trail.length) * this.alpha * 0.45;
                ctx.save();
                ctx.globalAlpha = a;
                ctx.fillStyle = this.color;
                ctx.beginPath();
                ctx.arc(
                    this.trail[i].x,
                    this.trail[i].y,
                    this.radius * 0.55,
                    0,
                    Math.PI * 2,
                );
                ctx.fill();
                ctx.restore();
            }
            // 绘制粒子主体（带发光）
            ctx.save();
            ctx.globalAlpha = Math.max(0, this.alpha);
            ctx.fillStyle = this.color;
            ctx.shadowColor = this.color;
            ctx.shadowBlur = 8;
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
        }

        get alive() {
            return this.alpha > 0.01;
        }
    }

    // ─── 预定义颜色 / 类型 ───────────────────────────────
    const COLORS = [
        "#ff2200",
        "#ff7700",
        "#ffcc00",
        "#00dd44",
        "#cc00ff",
        "#ff0088",
        "#00bbff",
        "#ff4488",
        "#ffaa00",
    ];
    const TYPES = ["sphere", "willow", "ring"];

    /**
     * 生成一批爆炸粒子
     *
     * @param  {number}  x      爆炸中心 x
     * @param  {number}  y      爆炸中心 y
     * @param  {string}  color  颜色
     * @param  {string}  type   爆炸类型
     * @returns {Particle[]}
     */
    function _burst(x, y, color, type) {
        const particles = [];
        const count = type === "ring" ? 80 : type === "willow" ? 120 : 100;

        if (type === "ring") {
            // 环形：均匀分布
            for (let i = 0; i < count; i++) {
                const angle = ((Math.PI * 2) / count) * i;
                particles.push(new Particle(x, y, color, type, angle));
            }
        } else {
            for (let i = 0; i < count; i++) {
                particles.push(new Particle(x, y, color, type, 0));
            }
            // willow/sphere 中心加一颗白色闪光核心粒子
            for (let i = 0; i < 10; i++) {
                const p = new Particle(x, y, "#ffffff", "sphere", 0);
                p.decay *= 2;
                p.radius = 1;
                particles.push(p);
            }
        }
        return particles;
    }

    /**
     * 启动烟花特效
     *
     * @param  {HTMLCanvasElement}  canvas   全屏 Canvas
     * @param  {Function}           onEnd    特效结束回调
     */
    function start(canvas, onEnd) {
        const ctx = canvas.getContext("2d");
        const w = canvas.width;
        const h = canvas.height;
        const DURATION = 10000;

        let rockets = [];
        let particles = [];
        let animId = null;
        let launchCnt = 0;
        const MAX_LAUNCHES = 12;

        // 定时发射火箭
        const launchInterval = setInterval(() => {
            if (launchCnt >= MAX_LAUNCHES) {
                clearInterval(launchInterval);
                return;
            }
            const x = w * (0.15 + Math.random() * 0.7);
            const ty = h * (0.08 + Math.random() * 0.45);
            const color = COLORS[Math.floor(Math.random() * COLORS.length)];
            const type = TYPES[Math.floor(Math.random() * TYPES.length)];
            const rocket = new Rocket(x, ty, color, type, h); // 传入画布高度
            rockets.push(rocket);
            launchCnt++;
        }, 600);

        const startTime = performance.now();

        function animate(now) {
            ctx.clearRect(0, 0, w, h);

            // 更新和绘制火箭
            for (let i = rockets.length - 1; i >= 0; i--) {
                const r = rockets[i];
                if (r.done) {
                    // 火箭爆炸：生成粒子
                    const burst = _burst(r.x, r.y, r.color, r.type);
                    particles = particles.concat(burst);
                    rockets.splice(i, 1);
                } else {
                    r.update();
                    r.draw(ctx);
                }
            }

            // 更新和绘制粒子
            particles = particles.filter((p) => p.alive);
            particles.forEach((p) => {
                p.update();
                p.draw(ctx);
            });

            if (now - startTime < DURATION) {
                animId = requestAnimationFrame(animate);
            } else {
                clearInterval(launchInterval);
                cancelAnimationFrame(animId);
                ctx.clearRect(0, 0, w, h);
                onEnd();
            }
        }

        animId = requestAnimationFrame(animate);
    }

    return { start };
})();
