/**
 * 文件功能：聊天室下雪特效
 *
 * 使用 Canvas 绘制真实六角雪花图案（6条主臂 + 左右分叉）。
 * 采用深色描边+白色主体双遍绘制，在任何背景颜色上都清晰可见。
 * 特效总时长约 10 秒，结束后自动清理并回调。
 */

const SnowEffect = (() => {
    /**
     * 在指定位置绘制一朵六角雪花（深色轮廓 + 白色主体）
     *
     * @param  {CanvasRenderingContext2D}  ctx
     * @param  {number}  x      中心 x
     * @param  {number}  y      中心 y
     * @param  {number}  r      主臂长度
     * @param  {number}  alpha  透明度
     * @param  {number}  rot    旋转角度（弧度）
     */
    function _drawFlake(ctx, x, y, r, alpha, rot) {
        ctx.save();
        ctx.globalAlpha = alpha;
        ctx.lineCap = "round";
        ctx.translate(x, y);
        ctx.rotate(rot);

        // 两遍绘制：先深蓝色粗描边，再白色细线覆盖
        // 这样在浅蓝、白色等背景上都清晰可辨
        const passes = [
            { color: "rgba(30, 60, 140, 0.8)", lw: r * 0.22 + 2.5 }, // 深蓝粗描边
            { color: "rgba(255, 255, 255, 1.0)", lw: Math.max(1, r * 0.11) }, // 白色主体
        ];

        passes.forEach(({ color, lw }) => {
            ctx.strokeStyle = color;
            ctx.lineWidth = lw;

            for (let i = 0; i < 6; i++) {
                ctx.save();
                ctx.rotate((Math.PI / 3) * i);

                // 主臂
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(r, 0);
                ctx.stroke();

                // 斜向分叉（0.4r 和 0.65r 处各一对）
                const branchLen = r * 0.35;
                const branchAngle = Math.PI / 4; // 45°

                [0.4, 0.65].forEach((pos) => {
                    const bx = r * pos;
                    // 上分叉
                    ctx.beginPath();
                    ctx.moveTo(bx, 0);
                    ctx.lineTo(
                        bx + Math.cos(branchAngle) * branchLen,
                        Math.sin(branchAngle) * branchLen,
                    );
                    ctx.stroke();
                    // 下分叉
                    ctx.beginPath();
                    ctx.moveTo(bx, 0);
                    ctx.lineTo(
                        bx + Math.cos(branchAngle) * branchLen,
                        -Math.sin(branchAngle) * branchLen,
                    );
                    ctx.stroke();
                });

                ctx.restore();
            }
        });

        ctx.restore();
    }

    // 雪花粒子类
    class Flake {
        constructor(w, h) {
            this.w = w;
            this.h = h;
            this.reset(true);
        }

        reset(initial = false) {
            this.x = Math.random() * this.w;
            this.y = initial ? Math.random() * this.h : -20;
            this.r = Math.random() * 10 + 7; // 主臂长度 7-17px（略放大）
            this.speed = Math.random() * 1.2 + 0.4;
            this.drift = Math.random() * 0.6 - 0.3;
            this.alpha = Math.random() * 0.3 + 0.7; // 透明度 0.7-1.0
            this.rot = Math.random() * Math.PI * 2;
            this.rotSpd = (Math.random() - 0.5) * 0.02;
            this.wobble = 0;
            this.wobSpd = Math.random() * 0.03 + 0.01;
        }

        update() {
            this.wobble += this.wobSpd;
            this.x += Math.sin(this.wobble) * 0.5 + this.drift;
            this.y += this.speed;
            this.rot += this.rotSpd;
            if (this.y > this.h + 20) {
                this.reset(false);
            }
        }

        draw(ctx) {
            _drawFlake(ctx, this.x, this.y, this.r, this.alpha, this.rot);
        }
    }

    /**
     * 启动下雪特效
     *
     * @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;
        const FLAKE_COUNT = 80;

        const flakes = Array.from(
            { length: FLAKE_COUNT },
            () => new Flake(w, h),
        );

        let animId = null;
        const startTime = performance.now();

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

            flakes.forEach((f) => {
                f.update();
                f.draw(ctx);
            });

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

        animId = requestAnimationFrame(animate);
    }

    return { start };
})();
