/* global React, window */
// ============================================================
// CAT WALKER — dimensional cat that roams the desk with a smart
// wander state machine. Click it: it meows + says "meow G!".
// ============================================================

let _walkAudio = null;
function playMeow() {
  try {
    _walkAudio = _walkAudio || new (window.AudioContext || window.webkitAudioContext)();
    const ctx = _walkAudio;
    if (ctx.state === "suspended") ctx.resume();
    const t0 = ctx.currentTime;
    const mk = (mult, detune) => {
      const o = ctx.createOscillator(); o.type = "sawtooth"; o.detune.value = detune;
      o.frequency.setValueAtTime(540 * mult, t0);
      o.frequency.linearRampToValueAtTime(880 * mult, t0 + 0.11);
      o.frequency.linearRampToValueAtTime(700 * mult, t0 + 0.26);
      o.frequency.linearRampToValueAtTime(470 * mult, t0 + 0.46);
      return o;
    };
    const o1 = mk(1, 0), o2 = mk(1, 9);
    const lfo = ctx.createOscillator(); lfo.frequency.value = 22;
    const lfoG = ctx.createGain(); lfoG.gain.value = 18;
    lfo.connect(lfoG); lfoG.connect(o1.frequency);
    const bp = ctx.createBiquadFilter(); bp.type = "bandpass"; bp.frequency.value = 1150; bp.Q.value = 3.4;
    const g = ctx.createGain();
    g.gain.setValueAtTime(0.0001, t0);
    g.gain.exponentialRampToValueAtTime(0.3, t0 + 0.06);
    g.gain.setValueAtTime(0.28, t0 + 0.3);
    g.gain.exponentialRampToValueAtTime(0.0001, t0 + 0.5);
    o1.connect(bp); o2.connect(bp); bp.connect(g); g.connect(ctx.destination);
    o1.start(t0); o2.start(t0); lfo.start(t0);
    o1.stop(t0 + 0.52); o2.stop(t0 + 0.52); lfo.stop(t0 + 0.52);
  } catch (e) { /* no-op */ }
}

function WalkingCatSVG({ riso = false }) {
  const c = riso
    ? { a: "#F2503B", b: "#c93722", belly: "#F4ECDC", stripe: "#2BBFB3", line: "#23201d", ear: "#f5b7ac" }
    : { a: "#E89A4C", b: "#C26A22", belly: "#F6E7CE", stripe: "#A9521A", line: "#3a2414", ear: "#e7a98f" };
  const uid = riso ? "r" : "n";
  return (
    <svg viewBox="0 0 210 150" width="150" height="107" aria-label="walking cat" role="img">
      <defs>
        <linearGradient id={"cwBody" + uid} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={c.a} />
          <stop offset="1" stopColor={c.b} />
        </linearGradient>
        <radialGradient id={"cwHi" + uid} cx="0.35" cy="0.25" r="0.8">
          <stop offset="0" stopColor="#fff" stopOpacity="0.45" />
          <stop offset="0.55" stopColor="#fff" stopOpacity="0" />
        </radialGradient>
        <linearGradient id={"cwLeg" + uid} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0" stopColor={c.b} />
          <stop offset="1" stopColor={c.a} />
        </linearGradient>
      </defs>

      {/* ground shadow */}
      <ellipse className="cw-shadow" cx="108" cy="140" rx="78" ry="9" fill="rgba(20,12,5,.28)" />

      {/* far legs (behind body) */}
      <g fill={c.b} opacity="0.82">
        <g transform="translate(72,104)"><g className="cw-leg cw-lB"><rect x="-4.5" y="0" width="9" height="36" rx="4.5" /><ellipse cx="0" cy="35" rx="6" ry="3.4" /></g></g>
        <g transform="translate(150,104)"><g className="cw-leg cw-lA"><rect x="-4.5" y="0" width="9" height="36" rx="4.5" /><ellipse cx="0" cy="35" rx="6" ry="3.4" /></g></g>
      </g>

      {/* tail */}
      <g className="cw-tail" style={{ transformBox: "fill-box", transformOrigin: "100% 100%" }}>
        <path d="M44,92 C8,90 6,52 26,40 C34,35 44,38 44,46 C44,52 38,52 34,56 C24,64 30,82 50,82 Z"
          fill={"url(#cwBody" + uid + ")"} />
        <path d="M30,46 C26,52 28,66 40,72" fill="none" stroke={c.stripe} strokeWidth="3" strokeLinecap="round" opacity="0.6" />
      </g>

      {/* body */}
      <path d="M40,92 C34,64 58,56 96,56 L140,56 C172,56 182,70 178,92 C176,108 150,114 110,114 L74,114 C52,114 42,104 40,92 Z"
        fill={"url(#cwBody" + uid + ")"} />
      {/* belly */}
      <path d="M60,104 C70,114 150,114 168,100 C150,112 78,112 60,104 Z" fill={c.belly} opacity="0.85" />
      <ellipse cx="100" cy="98" rx="46" ry="16" fill={c.belly} opacity="0.55" />
      {/* back stripes */}
      <g stroke={c.stripe} strokeWidth="4" strokeLinecap="round" opacity="0.55">
        <path d="M92,60 q3 10 0 18" /><path d="M112,59 q3 10 0 18" /><path d="M132,60 q3 10 0 18" />
      </g>
      {/* volume highlight */}
      <path d="M40,92 C34,64 58,56 96,56 L140,56 C172,56 182,70 178,92 C176,108 150,114 110,114 L74,114 C52,114 42,104 40,92 Z"
        fill={"url(#cwHi" + uid + ")"} />

      {/* head */}
      <g>
        {/* far ear */}
        <path d="M150,44 L150,18 L172,38 Z" fill={c.b} />
        {/* neck/head */}
        <path d="M150,96 C146,60 158,42 182,44 C202,46 206,66 202,82 C198,98 176,104 162,102 C156,101 151,100 150,96 Z"
          fill={"url(#cwBody" + uid + ")"} />
        {/* near ear */}
        <path d="M176,40 L182,14 L198,40 Z" fill={c.a} />
        <path d="M180,38 L184,22 L193,38 Z" fill={c.ear} />
        {/* muzzle */}
        <ellipse cx="190" cy="82" rx="16" ry="13" fill={c.belly} opacity="0.9" />
        {/* eye */}
        <ellipse cx="183" cy="66" rx="5.5" ry="6.5" fill="#fff" />
        <circle cx="184" cy="67" r="3.6" fill={c.line} />
        <circle cx="185.2" cy="65.4" r="1.1" fill="#fff" />
        {/* nose + mouth */}
        <path d="M201,78 l5,3 l-5,3 Z" fill={c.line} opacity="0.85" />
        <path d="M199,84 q-4 4 -9 2" fill="none" stroke={c.line} strokeWidth="1.6" strokeLinecap="round" />
        {/* whiskers */}
        <g stroke={c.line} strokeWidth="1.2" strokeLinecap="round" opacity="0.5">
          <path d="M198,80 l14,-3" /><path d="M198,84 l14,2" />
        </g>
        {/* head highlight */}
        <ellipse cx="178" cy="58" rx="14" ry="10" fill="#fff" opacity="0.18" />
      </g>

      {/* near legs (over body) */}
      <g fill={"url(#cwLeg" + uid + ")"}>
        <g transform="translate(62,106)"><g className="cw-leg cw-lA"><rect x="-5" y="0" width="10" height="36" rx="5" /><ellipse cx="0" cy="35" rx="6.5" ry="3.6" fill={c.b} /></g></g>
        <g transform="translate(140,106)"><g className="cw-leg cw-lB"><rect x="-5" y="0" width="10" height="36" rx="5" /><ellipse cx="0" cy="35" rx="6.5" ry="3.6" fill={c.b} /></g></g>
      </g>
    </svg>
  );
}

function CatWalker({ riso = false }) {
  const wrapRef = React.useRef(null);
  const xRef = React.useRef(null);
  const dirRef = React.useRef(1);
  const [facing, setFacing] = React.useState(1);
  const [walking, setWalking] = React.useState(true);
  const [bubble, setBubble] = React.useState(false);
  const bubbleT = React.useRef(null);
  const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

  const meow = () => {
    playMeow();
    setBubble(true);
    clearTimeout(bubbleT.current);
    bubbleT.current = setTimeout(() => setBubble(false), 1900);
  };

  React.useEffect(() => {
    const margin = 60;
    const vw = () => window.innerWidth;
    if (xRef.current == null) xRef.current = Math.max(margin, vw() * 0.2);
    if (reduce) {
      if (wrapRef.current) wrapRef.current.style.transform = `translateX(${xRef.current}px)`;
      setWalking(false);
      return;
    }
    let raf, last = 0, mode = "walk", pauseUntil = 0;
    const speed = 66; // px/s
    const step = (ts) => {
      if (!last) last = ts;
      const dt = Math.min(0.05, (ts - last) / 1000); last = ts;
      if (mode === "walk") {
        xRef.current += speed * dirRef.current * dt;
        if (xRef.current < margin) { xRef.current = margin; dirRef.current = 1; setFacing(1); }
        else if (xRef.current > vw() - margin) { xRef.current = vw() - margin; dirRef.current = -1; setFacing(-1); }
        // occasionally stop to look around (~ every 5s avg)
        if (Math.random() < dt / 5) { mode = "pause"; setWalking(false); pauseUntil = ts + 1500 + Math.random() * 2800; }
      } else {
        if (ts > pauseUntil) {
          mode = "walk"; setWalking(true);
          if (Math.random() < 0.5) { dirRef.current *= -1; setFacing((f) => -f); }
        }
      }
      if (wrapRef.current) wrapRef.current.style.transform = `translateX(${xRef.current}px)`;
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    const onResize = () => { const m = 60; if (xRef.current > vw() - m) xRef.current = vw() - m; };
    window.addEventListener("resize", onResize);
    return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", onResize); };
  }, []);

  return (
    <div className="cat-walker" ref={wrapRef} aria-hidden="true">
      {bubble && <div className="cat-bubble">meow G!</div>}
      <div className="cat-walker-flip cat-clickable" style={{ transform: `scaleX(${facing})` }}
        onClick={meow} role="button" tabIndex={-1} title="meow!">
        <div className={"cat-bob" + (walking ? " walking" : "")}>
          {window.PixelTuxedoSide ? <window.PixelTuxedoSide size={140} walking={walking} /> : <WalkingCatSVG riso={riso} />}
        </div>
      </div>
    </div>
  );
}

window.CatWalker = CatWalker;
window.WalkingCatSVG = WalkingCatSVG;
