/* ============================================================
   HeroRing — rotating 工牌 carousel of AI character cards
   variants: 'arc' (fan over the top) · 'orbit' (full ring) · 'coverflow'
   auto-rotates; drag to spin. image-slot placeholders for real art.
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

function CharCard({ card, idx, style, dim }) {
  return (
    <div
      className={"char-card" + (card.light ? " light" : "")}
      style={{ background: card.bg, ...style, opacity: dim }}
    >
      <div className="slot-wrap">
        <img src={card.img} alt={card.role} draggable="false"
          style={{ width: "100%", height: "100%", objectFit: "cover", display: "block", pointerEvents: "none" }} />
      </div>
      <div className="role">{card.role}</div>
    </div>
  );
}

function HeroRing({ variant = "arc", cards }) {
  const N = cards.length;
  const [rot, setRot] = useState(0);
  const rotRef = useRef(0);
  const dragRef = useRef({ active: false, startX: 0, startRot: 0, moved: 0, vel: 0, lastX: 0, lastT: 0 });
  const pausedRef = useRef(false);
  const rafRef = useRef(0);

  // animation loop: idle drift + inertia
  useEffect(() => {
    let last = performance.now();
    const tick = (now) => {
      const dt = Math.min(48, now - last); last = now;
      const d = dragRef.current;
      if (!d.active) {
        if (Math.abs(d.vel) > 0.002) {
          rotRef.current += d.vel * dt;
          d.vel *= 0.94;                       // friction
        } else if (!pausedRef.current) {
          rotRef.current += 0.0042 * dt;       // gentle idle drift
        }
        setRot(rotRef.current);
      }
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, []);

  const onDown = useCallback((e) => {
    const x = e.clientX ?? (e.touches && e.touches[0].clientX);
    dragRef.current = { active: true, startX: x, startRot: rotRef.current, moved: 0, vel: 0, lastX: x, lastT: performance.now() };
    e.currentTarget.setPointerCapture?.(e.pointerId);
  }, []);
  const onMove = useCallback((e) => {
    const d = dragRef.current; if (!d.active) return;
    const x = e.clientX ?? (e.touches && e.touches[0].clientX);
    const factor = variant === "coverflow" ? 0.45 : 0.30;
    const delta = (x - d.startX) * factor;
    rotRef.current = d.startRot + delta;
    d.moved = Math.abs(x - d.startX);
    const now = performance.now();
    const dtt = now - d.lastT;
    if (dtt > 0) d.vel = ((x - d.lastX) * factor) / dtt;
    d.lastX = x; d.lastT = now;
    setRot(rotRef.current);
  }, [variant]);
  const onUp = useCallback(() => { dragRef.current.active = false; }, []);

  const norm = (a) => { a = ((a + 180) % 360 + 360) % 360 - 180; return a; };

  // ---- ARC / ORBIT geometry ----
  const buildRadial = () => {
    const R = variant === "orbit" ? 360 : 452;
    const step = 360 / N;
    return cards.map((c, i) => {
      const a = norm(i * step + rot);
      const rad = (a * Math.PI) / 180;
      const x = R * Math.sin(rad);
      const y = -R * Math.cos(rad);
      const tilt = a * (variant === "orbit" ? 0.16 : 0.26);
      const sc = 1 - Math.min(0.34, Math.abs(a) * (variant === "orbit" ? 0.0016 : 0.0019));
      let op = 1;
      if (variant === "arc") {
        // open a gap at the bottom where the CTA text lives
        const g = Math.abs(a);
        op = g > 156 ? 0 : g > 132 ? (156 - g) / 24 : 1;
      } else {
        // orbit: fade the cards passing behind the centre text
        op = Math.abs(a) > 120 ? 0.42 : 0.94;
      }
      const z = Math.round(300 - Math.abs(a));
      return {
        card: c, idx: i, dim: op,
        style: {
          transform: `translate(${x}px, ${y}px) rotate(${tilt}deg) scale(${sc})`,
          zIndex: z,
        },
      };
    });
  };

  // ---- COVERFLOW geometry ----
  const buildCoverflow = () => {
    const step = 360 / N;
    const front = rot / step;             // continuous front index
    const spacing = 196;
    return cards.map((c, i) => {
      let o = i - front;
      o = ((o + N / 2) % N + N) % N - N / 2;  // shortest wrapped offset
      const ax = o * spacing;
      const az = -Math.abs(o) * 150;
      const ry = -o * 38;
      const sc = Math.max(0.62, 1 - Math.abs(o) * 0.10);
      const op = Math.abs(o) > 2.6 ? 0 : 1;
      return {
        card: c, idx: i, dim: op,
        style: {
          transform: `translate(-50%,-50%) translate3d(${ax}px,0,${az}px) rotateY(${ry}deg) scale(${sc})`,
          zIndex: Math.round(200 - Math.abs(o) * 10),
        },
      };
    });
  };

  const items = variant === "coverflow" ? buildCoverflow() : buildRadial();

  const handlers = {
    onPointerDown: onDown, onPointerMove: onMove, onPointerUp: onUp, onPointerCancel: onUp,
    onMouseEnter: () => { pausedRef.current = true; },
    onMouseLeave: () => { pausedRef.current = false; },
  };

  if (variant === "coverflow") {
    return (
      <div className="coverflow" {...handlers}>
        <div className="coverflow-track">
          {items.map((it) => (
            <CharCard key={it.idx} card={it.card} idx={it.idx} style={it.style} dim={it.dim} />
          ))}
        </div>
      </div>
    );
  }

  return (
    <div className="ring-layer" {...handlers}>
      <div className="ring">
        {items.map((it) => (
          <CharCard key={it.idx} card={it.card} idx={it.idx} style={it.style} dim={it.dim} />
        ))}
      </div>
    </div>
  );
}

window.HeroRing = HeroRing;
