// Hero variants for Ninja Typer
const { useState, useEffect, useRef } = React;

// ————————————————————————————————————————————————————————————
// Live typing demo — shared across hero variants
// ————————————————————————————————————————————————————————————
const DEMO_SCRIPTS = {
  professional: {
    raw: "um so i wanted to like follow up on the proposal from uh last week and get it over the line by friday",
    clean: "I wanted to follow up on the proposal from last week and get it over the line by Friday.",
    app: "Gmail",
    appHint: "To: sam@acme.co",
  },
  casual: {
    raw: "hey um can you grab milk on the way home uh the oat one not the regular",
    clean: "Hey, can you grab milk on the way home? The oat one, not the regular.",
    app: "iMessage",
    appHint: "Alex",
  },
  code: {
    raw: "um fix the race condition in the uh audio service where the mic like stays open after you release the key",
    clean: "Fix the race condition in AudioService where the mic stays open after you release the key.",
    app: "VS Code",
    appHint: "commit message",
  },
};

// Words the engine slices out of the transcript
const FILLER_WORDS = new Set(["um", "uh", "like", "basically", "maybe", "so", "kinda", "actually"]);

// Vertical scatter for flying word chips (deterministic, no Math.random)
const VF_OFFSETS = [-22, 8, -8, 18, -16, 2, 12, -2];

// raw speech -> chips: fillers fly solo (they get sliced), real words fly
// in short phrases so each chip is readable on its way to the engine
function tokenizeSpeech(raw) {
  const words = raw.split(/\s+/);
  const chips = [];
  let buf = [];
  const flush = () => { if (buf.length) { chips.push({ text: buf.join(" "), filler: false }); buf = []; } };
  words.forEach(w => {
    const bare = w.toLowerCase().replace(/[^a-z']/g, "");
    if (FILLER_WORDS.has(bare)) {
      flush();
      chips.push({ text: w, filler: true });
    } else {
      buf.push(w);
      if (buf.length === 3) flush();
    }
  });
  flush();
  return chips;
}

function LiveDemo({ compact = false, toneKey = "professional" }) {
  const [phase, setPhase] = useState("speaking"); // speaking | done
  const [chips, setChips] = useState([]);
  const [typed, setTyped] = useState("");
  const [pulse, setPulse] = useState(0);
  const [pillPhase, setPillPhase] = useState(0);
  const [micLevel, setMicLevel] = useState(0.03);
  const timers = useRef([]);
  const script = DEMO_SCRIPTS[toneKey] || DEMO_SCRIPTS.professional;

  // the mascot's animation clock: same 60ms / +0.25 tick as the app,
  // plus a simulated mic level in the range the real AudioService reports
  useEffect(() => {
    if (phase !== "speaking") return;
    const id = setInterval(() => {
      setPillPhase(p => p + 0.25);
      const t = performance.now() / 1000;
      setMicLevel(Math.abs(Math.sin(t * 2.1) * Math.sin(t * 3.7)) * 0.05 + 0.02);
    }, 60);
    return () => clearInterval(id);
  }, [phase]);

  const clear = () => {
    timers.current.forEach(clearTimeout);
    timers.current = [];
  };
  const later = (fn, ms) => timers.current.push(setTimeout(fn, ms));

  const run = () => {
    clear();
    setChips([]);
    setTyped("");
    setPulse(0);
    setPhase("speaking");

    const defs = tokenizeSpeech(script.raw);
    const EMIT = 460;    // ms between chips leaving the mouth (slow enough to read)
    const FLIGHT = 1400; // ms chip travel time to the engine (matches .vf-fly CSS)
    const TYPE_MS = 22;  // ms per output character

    // Output text is revealed in sync with chip arrivals: a real chip gets
    // absorbed, the engine pulses, and the corresponding slice of clean text
    // types out. Fillers get sliced and add nothing. Cause, then effect.
    const clean = script.clean;
    const totalReal = defs.filter(d => !d.filler).length;
    let realSeen = 0;
    let typedPos = 0;

    defs.forEach((c, i) => {
      const id = i;
      later(() => {
        setChips(prev => [...prev, { ...c, id, state: "fly", lane: i % VF_OFFSETS.length }]);
      }, i * EMIT);
      if (c.filler) {
        later(() => {
          // the engine slices it: strike through, drop, vanish
          setChips(prev => prev.map(ch => ch.id === id ? { ...ch, state: "slice" } : ch));
          later(() => setChips(prev => prev.filter(ch => ch.id !== id)), 800);
        }, i * EMIT + FLIGHT);
      } else {
        realSeen += 1;
        const from = typedPos;
        const to = Math.round(clean.length * (realSeen / totalReal));
        typedPos = to;
        later(() => {
          // absorbed: chip gone, engine pulses, its words type out
          setChips(prev => prev.filter(ch => ch.id !== id));
          setPulse(p => p + 1);
          for (let k = from; k < to; k++) {
            later(() => setTyped(clean.slice(0, k + 1)), (k - from) * TYPE_MS);
          }
        }, i * EMIT + FLIGHT);
      }
    });

    const lastChunk = Math.ceil(clean.length / Math.max(totalReal, 1));
    const doneAt = defs.length * EMIT + FLIGHT + lastChunk * TYPE_MS + 300;
    later(() => setPhase("done"), doneAt);
    later(run, doneAt + 3000); // loop the story
  };

  // autoplay on mount + restart on tone change
  useEffect(() => {
    const t = setTimeout(run, 400);
    return () => { clearTimeout(t); clear(); };
    // eslint-disable-next-line
  }, [toneKey]);

  const speaking = phase === "speaking";

  return (
    <div className={`demo-card vf-card ${compact ? "compact" : ""}`}>
      {/* fake app chrome */}
      <div className="demo-chrome">
        <div className="demo-dots">
          <span /><span /><span />
        </div>
        <div className="demo-app">
          <span className="demo-app-name">{script.app}</span>
          <span className="demo-app-hint">{script.appHint}</span>
        </div>
        <div className="demo-shortcut">
          <kbd>fn</kbd>
          <span className="demo-hold">hold</span>
        </div>
      </div>

      {/* voice -> engine -> text pipeline */}
      <div className="vf-stage">
        {/* you, talking */}
        <div className="vf-zone">
          <div className={`vf-speaker ${speaking ? "vf-speaking" : ""}`}>
            <svg viewBox="0 0 96 96" aria-hidden>
              <circle cx="42" cy="48" r="30" fill="var(--ink)" />
              <rect x="16" y="38" width="52" height="18" fill="var(--ink)" />
              <rect x="24" y="42" width="38" height="10" rx="5" fill="var(--paper)" />
              <circle cx="36" cy="47" r="2.6" fill="var(--accent)" />
              <circle cx="51" cy="47" r="2.6" fill="var(--accent)" />
              <path className="vf-arc vf-arc-1" d="M76 40 q7 8 0 16" fill="none" stroke="var(--accent-ink)" strokeWidth="2.5" strokeLinecap="round" />
              <path className="vf-arc vf-arc-2" d="M83 34 q11 14 0 28" fill="none" stroke="var(--accent-ink)" strokeWidth="2.5" strokeLinecap="round" />
            </svg>
          </div>
          <div className="vf-caption">you, talking</div>
        </div>

        {/* flight lane for word chips */}
        <div className="vf-lane">
          {chips.map(c => (
            <span
              key={c.id}
              className={`vf-chip ${c.filler ? "vf-chip-filler" : ""} vf-${c.state}`}
              style={{ "--vf-top": `${VF_OFFSETS[c.lane]}px` }}
            >
              {c.text}
            </span>
          ))}
        </div>

        {/* the ninja: the app's actual floating indicator, listening */}
        <div className="vf-zone">
          <div className="vf-engine-pill">
            <span key={pulse} className="vf-engine-pop">
              <NinjaPill
                state={speaking ? "recording" : "result"}
                level={micLevel}
                phase={pillPhase}
                hovering={false}
                scale={1.35}
              />
            </span>
          </div>
          <div className="vf-caption">{speaking ? "the ninja, listening" : "the ninja, satisfied"}</div>
        </div>

        {/* what lands in your app */}
        <div className="vf-zone vf-zone-out">
          <div className="vf-field">
            <div className="vf-field-text">
              {typed}
              {phase !== "done" && <span className="demo-caret" />}
            </div>
            {phase === "done" && (
              <div className="vf-inserted">
                <svg width="12" height="12" viewBox="0 0 14 14" fill="none" aria-hidden>
                  <path d="M2 7.5L5.5 11L12 3.5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
                inserted. no um survived.
              </div>
            )}
          </div>
          <div className="vf-caption">cleaned, typed into {script.app}</div>
        </div>
      </div>

      <div className="demo-footer">
        <div className="demo-meta">hold fn · speak · release</div>
      </div>
    </div>
  );
}

// ————————————————————————————————————————————————————————————
// Shuriken mark
// ————————————————————————————————————————————————————————————
function Shuriken({ size = 40, spin = true, color = "var(--accent)" }) {
  return (
    <svg width={size} height={size} viewBox="0 0 60 60" className={spin ? "shuriken-spin" : ""} aria-hidden>
      <g fill={color} stroke="var(--ink)" strokeWidth="2" strokeLinejoin="round">
        <path d="M30 4 L36 24 L56 30 L36 36 L30 56 L24 36 L4 30 L24 24 Z" />
      </g>
      <circle cx="30" cy="30" r="4" fill="var(--paper)" stroke="var(--ink)" strokeWidth="2" />
    </svg>
  );
}

// Stylized mask illustration built from flat shapes
function NinjaMaskIllustration({ tone = "orange" }) {
  const bg = tone === "orange" ? "var(--accent-soft)" : tone === "green" ? "var(--accent-2-soft)" : "var(--paper-2)";
  return (
    <div className="mask-illustration" style={{ background: bg }}>
      {/* speed lines */}
      <svg className="mask-lines" viewBox="0 0 400 400" aria-hidden>
        {Array.from({ length: 14 }).map((_, i) => (
          <line
            key={i}
            x1={-20 + i * 30} y1="0"
            x2={-60 + i * 30} y2="400"
            stroke="var(--ink)" strokeOpacity="0.08" strokeWidth="1"
          />
        ))}
      </svg>

      {/* shuriken floaters */}
      <div className="mask-float mask-float-1"><Shuriken size={44} color="var(--accent)" /></div>
      <div className="mask-float mask-float-2"><Shuriken size={28} color="var(--accent-2)" /></div>
      <div className="mask-float mask-float-3"><Shuriken size={20} color="var(--ink)" /></div>

      {/* the mask — geometric */}
      <svg className="mask-svg" viewBox="0 0 240 240" aria-hidden>
        {/* head */}
        <rect x="40" y="50" width="160" height="150" rx="80" fill="var(--ink)" />
        {/* wrap band */}
        <rect x="30" y="100" width="180" height="40" fill="var(--ink)" />
        <rect x="30" y="100" width="180" height="40" fill="var(--paper)" opacity="0" />
        {/* eye slit */}
        <rect x="70" y="112" width="100" height="16" rx="8" fill="var(--paper)" />
        {/* eye glow */}
        <circle cx="100" cy="120" r="4" fill="var(--accent)" />
        <circle cx="140" cy="120" r="4" fill="var(--accent)" />
        {/* tie ends */}
        <path d="M200 135 L235 125 L230 155 L200 150 Z" fill="var(--ink)" />
        <path d="M30 135 L5 128 L10 158 L30 150 Z" fill="var(--ink)" />
      </svg>

      {/* speech scroll */}
      <div className="mask-scroll">
        <div className="mask-scroll-dot" />
        <span>silent. fast. precise.</span>
      </div>
    </div>
  );
}

// ————————————————————————————————————————————————————————————
// Hero variants
// ————————————————————————————————————————————————————————————
const COPY = {
  bold: {
    eyebrow: "Voice in, clean text out",
    title: ["Type at the speed", "of thought."],
    sub: "Ninja Typer turns your voice into clean text in any Mac app. Hold fn, speak your mind, release. Done. The um's never make it out alive.",
    cta: "Download for Mac",
    ctaSub: "free during early access",
  },
  playful: {
    eyebrow: "The silent keyboard assassin",
    title: ["Stop typing.", "Start whispering."],
    sub: "Hold fn, mumble something, and watch Ninja Typer strike. Clean sentences land in any text field on your Mac. Your wrists will write you a thank-you note.",
    cta: "Unleash the ninja",
    ctaSub: "early access · no card required",
  },
  precise: {
    eyebrow: "Dictation for macOS",
    title: ["Speak it faster than", "you could type it."],
    sub: "Press fn, speak naturally, release. Ninja Typer transcribes your speech and tidies it up: fillers gone, punctuation fixed, your words untouched.",
    cta: "Get Ninja Typer",
    ctaSub: "free for now",
  },
};

function HeroCentered({ tone, copyKey, toneKey }) {
  const c = COPY[copyKey] || COPY.bold;
  return (
    <section className="hero hero-centered">
      <div className="hero-eyebrow">
        <Shuriken size={20} />
        <span>{c.eyebrow}</span>
      </div>
      <h1 className="hero-title">
        {c.title[0]}<br />
        <span className="hero-title-accent">{c.title[1]}</span>
      </h1>
      <p className="hero-sub">{c.sub}</p>
      <PlatformBadge />
      <div className="hero-ctas">
        <a className="btn btn-primary" href={window.NT_DOWNLOAD_URL} download>
          {c.cta}
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden>
            <path d="M3 7h8M7 3l4 4-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </a>
        <div className="hero-cta-sub">{c.ctaSub}</div>
      </div>
      <div className="hero-demo-wrap">
        <LiveDemo toneKey={toneKey} />
      </div>
      <HeroRibbon />
    </section>
  );
}

function HeroSplit({ tone, copyKey, toneKey }) {
  const c = COPY[copyKey] || COPY.bold;
  return (
    <section className="hero hero-split">
      <div className="hero-split-left">
        <div className="hero-eyebrow">
          <Shuriken size={20} />
          <span>{c.eyebrow}</span>
        </div>
        <h1 className="hero-title">
          {c.title[0]}<br />
          <span className="hero-title-accent">{c.title[1]}</span>
        </h1>
        <p className="hero-sub">{c.sub}</p>
        <div className="hero-ctas">
          <a className="btn btn-primary" href={window.NT_DOWNLOAD_URL} download>
            {c.cta}
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden>
              <path d="M3 7h8M7 3l4 4-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </a>
          <div className="hero-cta-sub">{c.ctaSub}</div>
        </div>
        <div className="hero-stats">
          <div><strong>57</strong><span>languages</span></div>
          <div><strong>1</strong><span>key to hold</span></div>
          <div><strong>$0</strong><span>early access</span></div>
        </div>
      </div>
      <div className="hero-split-right">
        <NinjaMaskIllustration tone={tone} />
      </div>
    </section>
  );
}

function HeroDemo({ tone, copyKey, toneKey }) {
  const c = COPY[copyKey] || COPY.bold;
  return (
    <section className="hero hero-demo">
      <div className="hero-demo-header">
        <div className="hero-eyebrow">
          <Shuriken size={20} />
          <span>{c.eyebrow}</span>
        </div>
        <h1 className="hero-title hero-title-tight">
          {c.title[0]} <span className="hero-title-accent">{c.title[1]}</span>
        </h1>
        <p className="hero-sub">{c.sub}</p>
      </div>
      <div className="hero-demo-big">
        <LiveDemo toneKey={toneKey} />
        <div className="hero-demo-side">
          <a className="btn btn-primary btn-large" href={window.NT_DOWNLOAD_URL} download>
            {c.cta}
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden>
              <path d="M3 7h8M7 3l4 4-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </a>
          <div className="hero-cta-sub">{c.ctaSub}</div>
          <div className="hero-tone-picker">
            <span className="tone-picker-label">Try a scenario ↓</span>
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { HeroCentered, HeroSplit, HeroDemo, Shuriken, NinjaMaskIllustration, LiveDemo, COPY, DEMO_SCRIPTS });
