"use client";
// 回响星核 / Echo Nexus — 中央晶体集群 + 主动脉冲（v0.7 Canvas 粒子系统）
import { useRef, useState, useCallback, useEffect } from "react";
import { useGameStore } from "@/store/gameStore";
import { formatNum } from "@/lib/game/config";
import { useToast } from "@/hooks/use-toast";
import { sfx } from "@/hooks/useAudio";
import { PULSE_WHISPERS, maybeWhisper } from "@/lib/game/narrative";

interface FloatNum {
  id: number;
  x: number;
  y: number;
  text: string;
  born: number;
  color: string;
}

// ===== Canvas 粒子系统类型 =====
interface EnergyParticle {
  // 环绕能量粒子（持续）
  angle: number;
  radius: number;
  baseRadius: number;
  speed: number;
  size: number;
  color: string;
  alpha: number;
  phase: number;
}

interface AmbientParticle {
  // 环境星尘（缓慢漂浮）
  x: number;
  y: number;
  vx: number;
  vy: number;
  size: number;
  alpha: number;
  twinkle: number;
}

interface ShockRing {
  // 冲击波环（点击触发）
  born: number;
  color: string;
  maxRadius: number;
  duration: number;
}

interface BurstParticle {
  // 爆发粒子（点击触发，径向发散）
  x: number;
  y: number;
  vx: number;
  vy: number;
  size: number;
  color: string;
  born: number;
  life: number;
}

const COLORS = {
  emerald: "#34d399",
  fuchsia: "#e879f9",
  rose: "#fb7185",
  amber: "#fbbf24",
  white: "#ffffff",
};

function comboColor(combo: number): string {
  if (combo >= 5) return COLORS.amber;
  if (combo >= 3) return COLORS.fuchsia;
  return COLORS.emerald;
}

export function CrystalOrb() {
  const pulse = useGameStore((s) => s.pulse);
  const crystals = useGameStore((s) => s.crystals);
  const crystalsPerSec = useGameStore((s) => s.crystalsPerSec);
  const crystalCap = useGameStore((s) => s.crystalCap);
  const combo = useGameStore((s) => s._combo);
  const { toast } = useToast();

  const [floats, setFloats] = useState<FloatNum[]>([]);
  const idRef = useRef(0);

  // Canvas refs
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const containerRef = useRef<HTMLDivElement | null>(null);
  const pulseAnimRef = useRef(0);
  const [pulseAnim, setPulseAnim] = useState(0); // 触发 SVG 环动画

  // 粒子状态 refs（不触发 re-render）
  const energyParticlesRef = useRef<EnergyParticle[]>([]);
  const ambientParticlesRef = useRef<AmbientParticle[]>([]);
  const shockRingsRef = useRef<ShockRing[]>([]);
  const burstParticlesRef = useRef<BurstParticle[]>([]);

  const comboRef = useRef(combo);
  const fillPctRef = useRef(0);
  const crystalsRef = useRef(crystals);
  const crystalCapRef = useRef(crystalCap);
  useEffect(() => {
    comboRef.current = combo;
    crystalsRef.current = crystals;
    crystalCapRef.current = crystalCap;
  }, [combo, crystals, crystalCap]);

  const mouseRef = useRef<{ x: number; y: number; inside: boolean }>({
    x: 0,
    y: 0,
    inside: false,
  });

  // ===== 初始化粒子 =====
  const initParticles = useCallback((w: number, h: number) => {
    const cx = w / 2;
    const cy = h / 2;
    const baseR = Math.min(w, h) * 0.28;

    // 环绕能量粒子（3 层，每层不同速度方向）
    const energy: EnergyParticle[] = [];
    const layers = [
      { count: 14, rMul: 0.95, speed: 0.6, color: COLORS.emerald },
      { count: 10, rMul: 1.15, speed: -0.4, color: COLORS.fuchsia },
      { count: 8, rMul: 1.35, speed: 0.3, color: COLORS.rose },
    ];
    layers.forEach((layer) => {
      for (let i = 0; i < layer.count; i++) {
        energy.push({
          angle: (Math.PI * 2 * i) / layer.count + Math.random() * 0.3,
          radius: baseR * layer.rMul,
          baseRadius: baseR * layer.rMul,
          speed: layer.speed * (0.8 + Math.random() * 0.4),
          size: 1.5 + Math.random() * 2,
          color: layer.color,
          alpha: 0.5 + Math.random() * 0.4,
          phase: Math.random() * Math.PI * 2,
        });
      }
    });
    energyParticlesRef.current = energy;

    // 环境星尘
    const ambient: AmbientParticle[] = [];
    for (let i = 0; i < 40; i++) {
      ambient.push({
        x: Math.random() * w,
        y: Math.random() * h,
        vx: (Math.random() - 0.5) * 8,
        vy: (Math.random() - 0.5) * 8,
        size: 0.5 + Math.random() * 1.5,
        alpha: 0.2 + Math.random() * 0.5,
        twinkle: Math.random() * Math.PI * 2,
      });
    }
    ambientParticlesRef.current = ambient;
    void cx;
    void cy;
  }, []);

  // ===== 触发脉冲效果（Canvas 部分）=====
  const triggerPulseEffect = useCallback(
    (x: number, y: number, res: { combo: number; gain: number }) => {
      const color = comboColor(res.combo);
      const now = performance.now();

      // 冲击波环（多层错峰）
      shockRingsRef.current.push({
        born: now,
        color: COLORS.emerald,
        maxRadius: 140,
        duration: 700,
      });
      if (res.combo >= 3) {
        shockRingsRef.current.push({
          born: now + 100,
          color: COLORS.fuchsia,
          maxRadius: 170,
          duration: 800,
        });
      }
      if (res.combo >= 5) {
        shockRingsRef.current.push({
          born: now + 200,
          color: COLORS.amber,
          maxRadius: 200,
          duration: 900,
        });
      }

      // 径向爆发粒子
      const pcount = 10 + Math.min(10, res.combo) * 2;
      for (let i = 0; i < pcount; i++) {
        const angle = (Math.PI * 2 * i) / pcount + Math.random() * 0.4;
        const speed = 120 + Math.random() * 180;
        burstParticlesRef.current.push({
          x,
          y,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          size: 2 + Math.random() * 3,
          color,
          born: now,
          life: 600 + Math.random() * 300,
        });
      }

      // 让能量粒子被"推开"再回弹
      energyParticlesRef.current.forEach((p) => {
        p.radius = p.baseRadius * (1.25 + Math.random() * 0.15);
      });
    },
    []
  );

  // ===== 点击处理 =====
  const handleClick = useCallback(
    (e: React.MouseEvent<HTMLButtonElement>) => {
      const res = pulse();
      if (!res) return;
      const rect = e.currentTarget.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;
      const id = idRef.current++;
      const floatColor = comboColor(res.combo);
      setFloats((f) => [
        ...f,
        {
          id,
          x,
          y,
          text: `+${res.gain.toFixed(1)}`,
          born: Date.now(),
          color: floatColor,
        },
      ]);
      triggerPulseEffect(x, y, res);
      setPulseAnim((n) => n + 1);
      sfx(res.combo >= 3 ? "pulseCombo" : "pulse", { combo: res.combo });
      setTimeout(() => {
        setFloats((f) => f.filter((it) => it.id !== id));
      }, 900);
      if (res.combo >= 5 && res.combo % 5 === 0) {
        // v0.9 叙事融入：高连击时注入世界观低语
        const whisper = maybeWhisper(PULSE_WHISPERS, 0.6);
        toast({
          title: `×${res.combo} 连击！`,
          description: whisper ? `「${whisper}」` : "谐振叠加，产能飙升。",
        });
      } else if (res.combo >= 3 && res.combo % 3 === 0) {
        // 3 连击时也有概率出现叙事
        const whisper = maybeWhisper(PULSE_WHISPERS, 0.3);
        if (whisper) {
          toast({ title: "低语", description: `「${whisper}」` });
        }
      }
    },
    [pulse, toast, triggerPulseEffect]
  );

  // ===== Canvas 动画循环 =====
  useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;

    let rafId = 0;
    let lastTime = performance.now();
    let dpr = Math.min(window.devicePixelRatio || 1, 2);

    const resize = () => {
      const rect = container.getBoundingClientRect();
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      canvas.width = Math.max(1, Math.floor(rect.width * dpr));
      canvas.height = Math.max(1, Math.floor(rect.height * dpr));
      canvas.style.width = `${rect.width}px`;
      canvas.style.height = `${rect.height}px`;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      initParticles(rect.width, rect.height);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(container);

    const draw = (now: number) => {
      const dt = Math.min(0.05, (now - lastTime) / 1000);
      lastTime = now;
      const w = canvas.width / dpr;
      const h = canvas.height / dpr;
      const cx = w / 2;
      const cy = h / 2;
      const baseR = Math.min(w, h) * 0.28;

      ctx.clearRect(0, 0, w, h);

      // === 1. 环境星尘 ===
      ambientParticlesRef.current.forEach((p) => {
        p.x += p.vx * dt;
        p.y += p.vy * dt;
        p.twinkle += dt * 2;
        if (p.x < 0) p.x = w;
        if (p.x > w) p.x = 0;
        if (p.y < 0) p.y = h;
        if (p.y > h) p.y = 0;
        const tw = 0.5 + 0.5 * Math.sin(p.twinkle);
        ctx.globalAlpha = p.alpha * tw;
        ctx.fillStyle = "#ffffff";
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
        ctx.fill();
      });
      ctx.globalAlpha = 1;

      // === 2. 外层辉光（呼吸）===
      const breath = 0.85 + 0.15 * Math.sin(now * 0.001);
      const glowGrad = ctx.createRadialGradient(
        cx,
        cy,
        baseR * 0.3,
        cx,
        cy,
        baseR * 2.2
      );
      glowGrad.addColorStop(0, `rgba(52,211,153,${0.18 * breath})`);
      glowGrad.addColorStop(0.5, `rgba(232,121,249,${0.1 * breath})`);
      glowGrad.addColorStop(1, "rgba(0,0,0,0)");
      ctx.fillStyle = glowGrad;
      ctx.fillRect(0, 0, w, h);

      // === 3. 进度填充环（背景 + 进度）===
      ctx.lineWidth = 2.5;
      ctx.strokeStyle = "rgba(255,255,255,0.06)";
      ctx.beginPath();
      ctx.arc(cx, cy, baseR * 1.45, 0, Math.PI * 2);
      ctx.stroke();

      const fp = Math.min(
        100,
        (crystalsRef.current / Math.max(1, crystalCapRef.current)) * 100
      );
      fillPctRef.current = fp;
      const ringR = baseR * 1.45;
      const grad = ctx.createLinearGradient(
        cx - ringR,
        cy - ringR,
        cx + ringR,
        cy + ringR
      );
      grad.addColorStop(0, COLORS.emerald);
      grad.addColorStop(0.5, COLORS.fuchsia);
      grad.addColorStop(1, COLORS.rose);
      ctx.strokeStyle = grad;
      ctx.lineWidth = 3;
      ctx.lineCap = "round";
      ctx.shadowBlur = 8;
      ctx.shadowColor = COLORS.emerald;
      ctx.beginPath();
      ctx.arc(
        cx,
        cy,
        ringR,
        -Math.PI / 2,
        -Math.PI / 2 + (Math.PI * 2 * fp) / 100
      );
      ctx.stroke();
      ctx.shadowBlur = 0;

      // === 4. 环绕能量粒子 ===
      energyParticlesRef.current.forEach((p) => {
        p.angle += p.speed * dt;
        // 回弹到 baseRadius
        p.radius += (p.baseRadius - p.radius) * Math.min(1, dt * 4);
        const px = cx + Math.cos(p.angle) * p.radius;
        const py = cy + Math.sin(p.angle) * p.radius;
        const flicker = 0.7 + 0.3 * Math.sin(now * 0.005 + p.phase);
        ctx.globalAlpha = p.alpha * flicker;
        ctx.fillStyle = p.color;
        ctx.shadowBlur = 10;
        ctx.shadowColor = p.color;
        ctx.beginPath();
        ctx.arc(px, py, p.size, 0, Math.PI * 2);
        ctx.fill();

        // 拖尾（向心方向的小线段）
        ctx.globalAlpha = p.alpha * flicker * 0.4;
        ctx.strokeStyle = p.color;
        ctx.lineWidth = p.size * 0.6;
        ctx.beginPath();
        ctx.moveTo(px, py);
        ctx.lineTo(
          cx + Math.cos(p.angle - p.speed * 0.08) * (p.radius - 2),
          cy + Math.sin(p.angle - p.speed * 0.08) * (p.radius - 2)
        );
        ctx.stroke();
      });
      ctx.globalAlpha = 1;
      ctx.shadowBlur = 0;

      // === 5. 中央晶核 ===
      const coreR = baseR * 0.95;
      // 鼠标接近时晶核轻微偏移（视差感）
      let coreOffsetX = 0;
      let coreOffsetY = 0;
      if (mouseRef.current.inside) {
        const dx = mouseRef.current.x - cx;
        const dy = mouseRef.current.y - cy;
        const dist = Math.hypot(dx, dy);
        if (dist > 0.1) {
          coreOffsetX = (dx / dist) * Math.min(8, dist * 0.05);
          coreOffsetY = (dy / dist) * Math.min(8, dist * 0.05);
        }
      }
      const ccx = cx + coreOffsetX;
      const ccy = cy + coreOffsetY;

      // 晶核主体（径向渐变）
      const coreGrad = ctx.createRadialGradient(
        ccx - coreR * 0.25,
        ccy - coreR * 0.3,
        coreR * 0.1,
        ccx,
        ccy,
        coreR
      );
      coreGrad.addColorStop(0, "rgba(255,255,255,0.95)");
      coreGrad.addColorStop(0.3, `rgba(52,211,153,${0.85 * breath})`);
      coreGrad.addColorStop(0.65, "rgba(232,121,249,0.55)");
      coreGrad.addColorStop(1, "rgba(251,113,133,0.2)");
      ctx.fillStyle = coreGrad;
      ctx.shadowBlur = 30;
      ctx.shadowColor = COLORS.emerald;
      ctx.beginPath();
      ctx.arc(ccx, ccy, coreR, 0, Math.PI * 2);
      ctx.fill();

      // 晶核内部六边形纹理
      ctx.save();
      ctx.translate(ccx, ccy);
      ctx.globalAlpha = 0.25;
      ctx.strokeStyle = "rgba(255,255,255,0.6)";
      ctx.lineWidth = 0.8;
      const hexR = coreR * 0.7;
      for (let layer = 0; layer < 3; layer++) {
        const r = hexR * (1 - layer * 0.3);
        ctx.beginPath();
        for (let i = 0; i < 6; i++) {
          const a = (Math.PI / 3) * i + now * 0.0002 * (layer % 2 ? 1 : -1);
          const px = Math.cos(a) * r;
          const py = Math.sin(a) * r;
          if (i === 0) ctx.moveTo(px, py);
          else ctx.lineTo(px, py);
        }
        ctx.closePath();
        ctx.stroke();
      }
      ctx.restore();

      // 高光
      ctx.globalAlpha = 0.4;
      ctx.fillStyle = "#ffffff";
      ctx.beginPath();
      ctx.ellipse(
        ccx - coreR * 0.25,
        ccy - coreR * 0.35,
        coreR * 0.35,
        coreR * 0.18,
        -0.4,
        0,
        Math.PI * 2
      );
      ctx.fill();
      ctx.globalAlpha = 1;
      ctx.shadowBlur = 0;

      // === 6. 冲击波环 ===
      shockRingsRef.current = shockRingsRef.current.filter((ring) => {
        const elapsed = now - ring.born;
        if (elapsed < 0 || elapsed > ring.duration) return elapsed <= ring.duration + 50;
        const t = elapsed / ring.duration;
        const r = ring.maxRadius * t;
        const alpha = (1 - t) * 0.8;
        ctx.globalAlpha = alpha;
        ctx.strokeStyle = ring.color;
        ctx.lineWidth = 2.5 * (1 - t * 0.5);
        ctx.shadowBlur = 12;
        ctx.shadowColor = ring.color;
        ctx.beginPath();
        ctx.arc(cx, cy, r, 0, Math.PI * 2);
        ctx.stroke();
        ctx.shadowBlur = 0;
        return true;
      });
      shockRingsRef.current = shockRingsRef.current.filter(
        (r) => now - r.born < r.duration
      );
      ctx.globalAlpha = 1;

      // === 7. 爆发粒子 ===
      burstParticlesRef.current = burstParticlesRef.current.filter((p) => {
        const age = now - p.born;
        if (age > p.life) return false;
        p.x += p.vx * dt;
        p.y += p.vy * dt;
        p.vx *= 0.96;
        p.vy *= 0.96;
        const t = age / p.life;
        const alpha = 1 - t;
        ctx.globalAlpha = alpha;
        ctx.fillStyle = p.color;
        ctx.shadowBlur = 8;
        ctx.shadowColor = p.color;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.size * (1 - t * 0.5), 0, Math.PI * 2);
        ctx.fill();
        return true;
      });
      ctx.globalAlpha = 1;
      ctx.shadowBlur = 0;

      rafId = requestAnimationFrame(draw);
    };
    rafId = requestAnimationFrame(draw);

    return () => {
      cancelAnimationFrame(rafId);
      ro.disconnect();
    };
  }, [initParticles]);

  // ===== 鼠标追踪（视差）=====
  const handleMouseMove = useCallback(
    (e: React.MouseEvent<HTMLButtonElement>) => {
      const rect = e.currentTarget.getBoundingClientRect();
      mouseRef.current = {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top,
        inside: true,
      };
    },
    []
  );
  const handleMouseLeave = useCallback(() => {
    mouseRef.current.inside = false;
  }, []);

  // 进度比例（用于显示）
  const fillPct = Math.min(100, (crystals / Math.max(1, crystalCap)) * 100);

  return (
    <div className="relative flex flex-col items-center justify-center gap-4 select-none">
      {/* 连击显示 */}
      {combo > 1 && (
        <div className="absolute -top-2 left-1/2 -translate-x-1/2 px-3 py-1 rounded-full bg-rose-500/20 border border-rose-400/40 text-rose-200 text-xs font-mono animate-pulse z-10">
          ×{combo} 连击
        </div>
      )}

      <button
        onClick={handleClick}
        onMouseMove={handleMouseMove}
        onMouseLeave={handleMouseLeave}
        className="relative h-52 w-52 sm:h-64 sm:w-64 rounded-full focus:outline-none group"
        aria-label="脉冲扫描，获取记忆晶体"
      >
        {/* Canvas 粒子层 */}
        <div
          ref={containerRef}
          className="absolute inset-0 rounded-full overflow-hidden"
        >
          <canvas ref={canvasRef} className="block w-full h-full" />
        </div>

        {/* CSS 旋转外环装饰（与 Canvas 叠加）*/}
        <div
          className="absolute inset-2 rounded-full border border-emerald-400/30 pointer-events-none"
          style={{ animation: "echo-spin 18s linear infinite" }}
        >
          <div className="absolute top-0 left-1/2 -translate-x-1/2 -translate-y-1/2 h-2 w-2 rounded-full bg-emerald-300 shadow-[0_0_8px_#34d399]" />
          <div className="absolute bottom-0 left-1/2 -translate-x-1/2 translate-y-1/2 h-1.5 w-1.5 rounded-full bg-rose-300 shadow-[0_0_8px_#fb7185]" />
        </div>
        {/* 反向旋转虚线内环 */}
        <div
          className="absolute inset-6 rounded-full border border-fuchsia-400/20 border-dashed pointer-events-none"
          style={{ animation: "echo-spin 24s linear infinite reverse" }}
        />

        {/* 脉冲扩散环（点击时，CSS 叠加 Canvas 冲击波）*/}
        <div
          key={`ring-${pulseAnim}`}
          className="absolute inset-8 rounded-full border-2 border-emerald-400/60 pointer-events-none"
          style={{ animation: "echo-ring 0.7s ease-out forwards" }}
        />

        {/* 浮动数字（保留 HTML，便于清晰文字）*/}
        {floats.map((f) => (
          <span
            key={f.id}
            className="absolute pointer-events-none font-mono font-bold text-sm z-10"
            style={{
              left: f.x,
              top: f.y,
              color: f.color,
              transform: "translate(-50%, -50%)",
              animation: "echo-float 0.9s ease-out forwards",
              textShadow: `0 0 8px ${f.color}`,
            }}
          >
            {f.text}
          </span>
        ))}
      </button>

      {/* 数值显示 */}
      <div className="text-center">
        <div
          className="text-2xl font-mono font-bold text-emerald-300"
          style={{ textShadow: "0 0 12px rgba(52,211,153,0.5)" }}
        >
          {formatNum(crystals)}
        </div>
        <div className="text-xs text-muted-foreground mt-0.5">
          记忆晶体 · {crystalsPerSec.toFixed(1)}/s · 上限{" "}
          {formatNum(crystalCap)}
        </div>
        <div className="text-[11px] text-muted-foreground/70 mt-2">
          点击晶体发起
          <span className="text-emerald-300">脉冲扫描</span>，连击叠加加成
        </div>
        <div className="text-[10px] text-muted-foreground/50 mt-1 tabular-nums">
          仓库 {fillPct.toFixed(1)}% · 连击 ×{Math.max(1, combo)}
        </div>
      </div>

      <style jsx>{`
        @keyframes echo-spin {
          to {
            transform: rotate(360deg);
          }
        }
        @keyframes echo-float {
          0% {
            opacity: 1;
            transform: translate(-50%, -50%) scale(1);
          }
          100% {
            opacity: 0;
            transform: translate(-50%, -180%) scale(1.3);
          }
        }
        @keyframes echo-ring {
          0% {
            transform: scale(0.8);
            opacity: 0.8;
          }
          100% {
            transform: scale(1.6);
            opacity: 0;
          }
        }
      `}</style>
    </div>
  );
}
