// meteor-swipe.jsx
// AGENT_TARGET: meteor-swipe — canvas overlay that draws fading meteor streaks on pointer drag
// Long swipe = brighter streak. Pure expressive mark-making, no goal.

function MeteorSwipeCanvas() {
  const canvasRef = useRef(null);
  const streaksRef = useRef([]);
  const activeRef = useRef(null);
  const [swipeCue, setSwipeCue] = useState(null);
  const cueTimerRef = useRef(null);
  const lastCueAtRef = useRef(0);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const motionDisabled =
      window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true ||
      (() => {
        try {
          return sessionStorage.getItem("planets_quality_tier") === "low";
        } catch (_) {
          return false;
        }
      })();

    if (motionDisabled) return;

    const resize = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
    };
    resize();
    window.addEventListener("resize", resize);

    const drawStreak = (ctx, streak, alpha) => {
      const pts = streak.points;
      if (pts.length < 2) return;
      const totalLen = streak.totalLen || 1;
      const bright = streak.brightness;
      let runLen = 0;
      ctx.lineCap = "round";
      ctx.lineJoin = "round";
      for (let i = 1; i < pts.length; i++) {
        const dx = pts[i].x - pts[i - 1].x;
        const dy = pts[i].y - pts[i - 1].y;
        runLen += Math.sqrt(dx * dx + dy * dy);
        const t = Math.min(1, runLen / totalLen);
        const segAlpha = t * bright * alpha;
        ctx.beginPath();
        ctx.strokeStyle = `rgba(255,255,220,${segAlpha.toFixed(3)})`;
        ctx.lineWidth = 1 + t * bright * 3;
        ctx.moveTo(pts[i - 1].x, pts[i - 1].y);
        ctx.lineTo(pts[i].x, pts[i].y);
        ctx.stroke();
      }
      // glowing head
      const head = pts[pts.length - 1];
      const r = 2 + bright * 4;
      const grd = ctx.createRadialGradient(
        head.x,
        head.y,
        0,
        head.x,
        head.y,
        r,
      );
      grd.addColorStop(0, `rgba(255,255,200,${(bright * alpha).toFixed(3)})`);
      grd.addColorStop(1, "rgba(255,255,200,0)");
      ctx.beginPath();
      ctx.fillStyle = grd;
      ctx.arc(head.x, head.y, r, 0, Math.PI * 2);
      ctx.fill();
    };

    let animId = null;
    const stopTick = () => {
      if (animId !== null) {
        cancelAnimationFrame(animId);
        animId = null;
      }
    };
    const scheduleTick = () => {
      if (animId === null) animId = requestAnimationFrame(tick);
    };
    const tick = () => {
      animId = null;
      const ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      const now = performance.now();
      const keep = [];
      for (const streak of streaksRef.current) {
        const alpha =
          streak.born === null
            ? 1
            : Math.max(0, 1 - (now - streak.born) / streak.duration);
        if (alpha > 0) {
          drawStreak(ctx, streak, alpha);
          keep.push(streak);
        }
      }
      streaksRef.current = keep;
      if (activeRef.current || keep.length) scheduleTick();
    };

    const getPos = (e) => ({
      x: e.clientX ?? e.changedTouches?.[0]?.clientX ?? 0,
      y: e.clientY ?? e.changedTouches?.[0]?.clientY ?? 0,
    });

    const clearCueTimer = () => {
      if (cueTimerRef.current !== null) {
        window.clearTimeout(cueTimerRef.current);
        cueTimerRef.current = null;
      }
    };

    const showSwipeCue = (streak, pos, settling = false) => {
      const level = Math.min(1, Math.max(0.25, streak.brightness || 0.25));
      const pct = Math.round(level * 100);
      const label =
        pct >= 90
          ? "Long swipe: brightest tail"
          : pct >= 55
            ? "Longer swipe, brighter tail"
            : "Keep swiping to brighten";
      setSwipeCue({
        x: pos.x,
        y: pos.y,
        pct,
        label,
        settling,
      });
    };

    const onDown = (e) => {
      const { x, y } = getPos(e);
      const streak = {
        points: [{ x, y }],
        born: null,
        duration: 1800,
        brightness: 0.25,
        totalLen: 0,
      };
      streaksRef.current.push(streak);
      activeRef.current = streak;
      clearCueTimer();
      showSwipeCue(streak, { x, y });
      scheduleTick();
    };

    const onMove = (e) => {
      if (!activeRef.current) return;
      const { x, y } = getPos(e);
      const pts = activeRef.current.points;
      const last = pts[pts.length - 1];
      const dx = x - last.x;
      const dy = y - last.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist < 3) return;
      activeRef.current.totalLen += dist;
      pts.push({ x, y });
      // longer swipe → brighter, up to 1.0 at ~500px
      activeRef.current.brightness = Math.min(
        1,
        Math.max(0.25, activeRef.current.totalLen / 500),
      );
      const now = performance.now();
      if (now - lastCueAtRef.current > 90) {
        lastCueAtRef.current = now;
        showSwipeCue(activeRef.current, { x, y });
      }
      scheduleTick();
    };

    const onUp = () => {
      if (!activeRef.current) return;
      const streak = activeRef.current;
      const head = streak.points[streak.points.length - 1];
      streak.born = performance.now();
      // brighter streaks linger longer: 0.8s–2.4s
      streak.duration = 800 + streak.brightness * 1600;
      showSwipeCue(streak, head, true);
      clearCueTimer();
      cueTimerRef.current = window.setTimeout(() => {
        setSwipeCue(null);
        cueTimerRef.current = null;
      }, 900);
      activeRef.current = null;
      scheduleTick();
    };

    const onVisibilityChange = () => {
      if (!document.hidden) return;
      streaksRef.current = [];
      activeRef.current = null;
      clearCueTimer();
      setSwipeCue(null);
      const ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      stopTick();
    };

    window.addEventListener("pointerdown", onDown);
    window.addEventListener("pointermove", onMove);
    window.addEventListener("pointerup", onUp);
    window.addEventListener("pointercancel", onUp);
    document.addEventListener("visibilitychange", onVisibilityChange);

    return () => {
      stopTick();
      clearCueTimer();
      window.removeEventListener("resize", resize);
      window.removeEventListener("pointerdown", onDown);
      window.removeEventListener("pointermove", onMove);
      window.removeEventListener("pointerup", onUp);
      window.removeEventListener("pointercancel", onUp);
      document.removeEventListener("visibilitychange", onVisibilityChange);
    };
  }, []);

  return (
    <>
      <canvas
        ref={canvasRef}
        className="meteor-swipe-canvas"
        aria-hidden="true"
      />
      {swipeCue && (
        <div
          className={`meteor-swipe-cue ${swipeCue.settling ? "settling" : ""}`}
          style={{
            left: `${swipeCue.x}px`,
            top: `${swipeCue.y}px`,
            "--meteor-swipe-strength": `${swipeCue.pct}%`,
          }}
          role="status"
          aria-live="polite"
        >
          <span>{swipeCue.label}</span>
          <strong>{swipeCue.pct}% glow</strong>
          <i aria-hidden="true" />
        </div>
      )}
    </>
  );
}
