// CompilePipeline.jsx — INXM plan-creation pipeline.
//
// Visual vocabulary: circles, dots, arcs, hairlines. Only the
// currently-running scene carries the accent colour — inactive
// scenes desaturate via the --accent override in site-v4.css.
// No UI literalism (no buttons, no checklists, no docs) — each
// scene tells its step through one geometric action.

const PHASES = [
  { key: "INTENT",  label: "State the intent"   },
  { key: "COMPILE", label: "Compile the Plan"   },
  { key: "APPROVE", label: "Approve the Plan"   },
  { key: "EXECUTE", label: "Execute the Plan"   },
  { key: "RESULT",  label: "Audit the result"   },
];

const PHASE_DUR = 2400; // ms — duration of the animated portion of each scene
const HOLD_DUR  = 1200; // ms — pause at progress=1 before advancing to the next scene

// =====================================================================
// Real-use-case snippets — shown under each scene as the concrete
// version of what the abstract illustration depicts. Story: one Plan,
// RUN-4412, April vendor reconciliation.
//
// Content is split into atomic "lines" so they can fade in sequentially
// when the scene becomes active. Each line carries a --i custom prop
// that drives its animation-delay in site-v4.css.
// =====================================================================

// Helper to wrap a string of code lines into individually-animated spans.
function CodeLines({ lines, baseIndex = 0 }) {
  return (
    <code>
      {lines.map((ln, i) => (
        <span
          key={i}
          className="cp-detail__line cp-detail__codeline"
          style={{ "--i": baseIndex + i }}
        >
          {ln || "\u00a0"}
        </span>
      ))}
    </code>
  );
}

function CaseSnippet({ phase }) {
  switch (phase) {
    case "INTENT":
      return (
        <div className="cp-detail">
          <div className="cp-detail__head">
            <span className="cp-detail__byline cp-detail__line" style={{ "--i": 0 }}>// jana@inxm.ai · slack</span>
            <span className="cp-detail__id cp-detail__line" style={{ "--i": 0 }}>14:00 UTC</span>
          </div>
          <p className="cp-detail__quote">
            <span className="cp-detail__line" style={{ "--i": 1 }}>
              <span className="cp-detail__q">“</span>
              Reconcile April vendor invoices against open POs.
            </span>
            <span className="cp-detail__line" style={{ "--i": 2 }}>
              {" "}Email controller by 18:00.
              <span className="cp-detail__q">”</span>
            </span>
          </p>
        </div>
      );
    case "COMPILE":
      return (
        <div className="cp-detail">
          <div className="cp-detail__head">
            <span className="cp-detail__byline cp-detail__line" style={{ "--i": 0 }}>// PLAN-mthend-recon-v3</span>
            <span className="cp-detail__id cp-detail__line" style={{ "--i": 0 }}>€0.42 · 2m04s</span>
          </div>
          <pre className="cp-detail__code">
            <CodeLines
              baseIndex={1}
              lines={[
                "tasks:",
                "  t1 fetch_invoices  SAP",
                "  t2 fetch_open_pos  SAP",
                "  t3 match_by_vendor",
                "  t4 resolve_ids     Heal",
                "  t5 flag_exceptions →approval",
                "  t6 send_email      Mail",
              ]}
            />
          </pre>
        </div>
      );
    case "APPROVE":
      return (
        <div className="cp-detail">
          <div className="cp-detail__head">
            <span className="cp-detail__byline cp-detail__line" style={{ "--i": 0 }}>// v3 vs v2 · 4 changes</span>
            <span className="cp-detail__id cp-detail__line" style={{ "--i": 0 }}>alex@inxm.ai</span>
          </div>
          <pre className="cp-detail__code cp-detail__code--diff">
            <CodeLines
              baseIndex={1}
              lines={[
                "+ threshold_eur: 150",
                "+ recipient:     controller@…",
                "~ resolve_ids  → Heal",
                "~ p95 latency:   2m04s",
              ]}
            />
          </pre>
        </div>
      );
    case "EXECUTE":
      return (
        <div className="cp-detail">
          <div className="cp-detail__head">
            <span className="cp-detail__byline cp-detail__line" style={{ "--i": 0 }}>// RUN-4412 · live</span>
            <span className="cp-detail__id cp-detail__line" style={{ "--i": 0 }}>duration 2:09</span>
          </div>
          <pre className="cp-detail__code">
            <CodeLines
              baseIndex={1}
              lines={[
                "14:00:01 ✓ fetch_invoices · 850",
                "14:00:03 ✓ fetch_open_pos · 723",
                "14:00:04 ✓ match_by_vendor · 847",
                "14:00:06 ⏸ flag_exceptions ▸ wait",
                "14:01:58 → approval · alex@…",
                "14:02:09 ✓ sealed",
              ]}
            />
          </pre>
        </div>
      );
    case "RESULT":
      return (
        <div className="cp-detail">
          <div className="cp-detail__head">
            <span className="cp-detail__byline cp-detail__line" style={{ "--i": 0 }}>// audit · sealed</span>
            <span className="cp-detail__id cp-detail__line" style={{ "--i": 0 }}>14:02:09 UTC</span>
          </div>
          <dl className="cp-detail__kv">
            {[
              ["Matched", "847 / 850 · 99.6%"],
              ["Excepts", "3 · resolved"],
              ["Emailed", "controller@inxm.ai"],
              ["Cost",    "€0.42 · 12 ops"],
              ["Hash",    "0x9c2b·f4a1"],
            ].map(([k, v], i) => (
              <div key={k} className="cp-detail__line" style={{ "--i": i + 1 }}>
                <dt>{k}</dt>
                <dd>{v}</dd>
              </div>
            ))}
          </dl>
        </div>
      );
    default:
      return null;
  }
}

// Shared primitive classes — see site-v4.css for the .cp-ink-*
// and .cp-accent-* rules. `cp-ink-*` always reads currentColor;
// `cp-accent-*` reads var(--accent), which is muted to grey in
// inactive scenes by the global override.

// ───────────────────────────────────────────────────────────────────
// 1 · INTENT — sender dot → dashed line → receiver circle.
//   "A plain-language request flows into the engine."
// ───────────────────────────────────────────────────────────────────
function SceneIntent({ active, progress }) {
  const p = active ? progress : 1;
  // Dashed connector draws in 0 → 1
  const connectorP = Math.min(1, p / 0.8);
  // Receiver dot lands at the end
  const arrived = p > 0.85;

  // Sound-wave arcs on the left of the sender dot — three of them,
  // staggered so the wave looks like it's "speaking" while active.
  const waves = [
    { d: "M 40 56 Q 36 60 40 64", k: 1 },
    { d: "M 36 52 Q 28 60 36 68", k: 2 },
    { d: "M 32 48 Q 20 60 32 72", k: 3 },
  ];

  return (
    <svg className="cp-art" viewBox="0 0 200 120" aria-hidden="true">
      {/* Sender dot */}
      <circle cx="50" cy="60" r="3.2" className="cp-ink-fill" />

      {/* Sound-wave arcs */}
      {waves.map((w, i) => (
        <path
          key={i}
          d={w.d}
          fill="none"
          className="cp-ink-stroke"
          strokeWidth="1"
          opacity={active ? 0.35 + 0.2 * (1 - i / 3) : 0.25}
        />
      ))}

      {/* Dashed connector — draws in from sender toward receiver */}
      <line
        x1="56"
        y1="60"
        x2={56 + (124 - 56) * connectorP}
        y2="60"
        className="cp-accent-stroke"
        strokeWidth="1.2"
        strokeDasharray="3 3"
      />

      {/* Receiver circle */}
      <circle
        cx="150"
        cy="60"
        r="26"
        fill="none"
        className="cp-ink-stroke"
        strokeWidth="1"
      />

      {/* Landed dot at receiver centre */}
      <circle
        cx="150"
        cy="60"
        r={arrived ? 3 : 0}
        className="cp-accent-fill"
        style={{ transition: "r 220ms ease" }}
      />
    </svg>
  );
}

// ───────────────────────────────────────────────────────────────────
// 2 · COMPILE — 6 spokes draw outward from a centre dot to vertices.
//   "Scattered intent becomes a structured Plan."
// ───────────────────────────────────────────────────────────────────
function SceneCompile({ active, progress }) {
  const p = active ? progress : 1;
  const cx = 100, cy = 60, r = 32;
  const verts = Array.from({ length: 6 }, (_, i) => {
    const a = (Math.PI * 2 / 6) * i - Math.PI / 2;
    return { x: cx + Math.cos(a) * r, y: cy + Math.sin(a) * r };
  });

  return (
    <svg className="cp-art" viewBox="0 0 200 120" aria-hidden="true">
      {/* Spokes — drawn sequentially, one per sixth of progress */}
      {verts.map((v, i) => {
        const segP = Math.max(0, Math.min(1, p * 6 - i));
        return (
          <line
            key={"s" + i}
            x1={cx}
            y1={cy}
            x2={cx + (v.x - cx) * segP}
            y2={cy + (v.y - cy) * segP}
            className="cp-accent-stroke"
            strokeWidth="1"
          />
        );
      })}

      {/* Outer vertex dots — always present, faintly */}
      {verts.map((v, i) => {
        const segP = Math.max(0, Math.min(1, p * 6 - i));
        return (
          <circle
            key={"v" + i}
            cx={v.x}
            cy={v.y}
            r={2.4}
            className="cp-ink-fill"
            opacity={0.25 + 0.75 * segP}
          />
        );
      })}

      {/* Centre dot */}
      <circle cx={cx} cy={cy} r="3" className="cp-ink-fill" />
    </svg>
  );
}

// ───────────────────────────────────────────────────────────────────
// 3 · APPROVE — four corner brackets close inward around a dot.
//   "The Plan is committed. The frame snaps shut."
// ───────────────────────────────────────────────────────────────────
function SceneApprove({ active, progress }) {
  const p = active ? progress : 1;
  // Brackets travel from outside-the-frame to their final inner positions.
  const travel = (1 - p) * 22;
  const cx = 100, cy = 60;
  const TL = { x: cx - 36, y: cy - 22 };
  const TR = { x: cx + 36, y: cy - 22 };
  const BL = { x: cx - 36, y: cy + 22 };
  const BR = { x: cx + 36, y: cy + 22 };
  const len = 8; // arm length of each bracket
  const ease = p > 0.95 ? 1 : 0;

  return (
    <svg className="cp-art" viewBox="0 0 200 120" aria-hidden="true">
      {/* Centre Plan dot — the thing being framed */}
      <circle
        cx={cx}
        cy={cy}
        r={3 + ease * 0.6}
        className="cp-ink-fill"
        style={{ transition: "r 200ms ease" }}
      />

      {/* Faint outline circle around the dot — the Plan itself */}
      <circle
        cx={cx}
        cy={cy}
        r="14"
        fill="none"
        className="cp-ink-stroke"
        strokeWidth="1"
        opacity="0.35"
      />

      {/* Four corner brackets, closing inward */}
      <g transform={`translate(${-travel}, ${-travel})`}>
        <path
          d={`M ${TL.x} ${TL.y + len} L ${TL.x} ${TL.y} L ${TL.x + len} ${TL.y}`}
          fill="none"
          className="cp-accent-stroke"
          strokeWidth="1.3"
          strokeLinecap="square"
        />
      </g>
      <g transform={`translate(${travel}, ${-travel})`}>
        <path
          d={`M ${TR.x - len} ${TR.y} L ${TR.x} ${TR.y} L ${TR.x} ${TR.y + len}`}
          fill="none"
          className="cp-accent-stroke"
          strokeWidth="1.3"
          strokeLinecap="square"
        />
      </g>
      <g transform={`translate(${-travel}, ${travel})`}>
        <path
          d={`M ${BL.x} ${BL.y - len} L ${BL.x} ${BL.y} L ${BL.x + len} ${BL.y}`}
          fill="none"
          className="cp-accent-stroke"
          strokeWidth="1.3"
          strokeLinecap="square"
        />
      </g>
      <g transform={`translate(${travel}, ${travel})`}>
        <path
          d={`M ${BR.x - len} ${BR.y} L ${BR.x} ${BR.y} L ${BR.x} ${BR.y - len}`}
          fill="none"
          className="cp-accent-stroke"
          strokeWidth="1.3"
          strokeLinecap="square"
        />
      </g>
    </svg>
  );
}

// ───────────────────────────────────────────────────────────────────
// 4 · EXECUTE — clock face. 24 ticks fill clockwise. A sweep hand
//   marks "now". "The Plan runs through real time."
// ───────────────────────────────────────────────────────────────────
function SceneExecute({ active, progress }) {
  const p = active ? progress : 1;
  const N = 24;
  const cx = 100, cy = 60;
  const rOuter = 38;
  const rInner = 32;

  // Sweep hand angle — at p=0 points up (12 o'clock), rotates clockwise
  const handA = Math.PI * 2 * p - Math.PI / 2;
  const handLen = rInner - 3;

  return (
    <svg className="cp-art" viewBox="0 0 200 120" aria-hidden="true">
      {/* 24 radial ticks. Filled clockwise as p advances. */}
      {Array.from({ length: N }, (_, i) => {
        const a = (Math.PI * 2 / N) * i - Math.PI / 2;
        const filled = i / N <= p + 0.001;
        const x1 = cx + Math.cos(a) * rInner;
        const y1 = cy + Math.sin(a) * rInner;
        const x2 = cx + Math.cos(a) * rOuter;
        const y2 = cy + Math.sin(a) * rOuter;
        return (
          <line
            key={i}
            x1={x1}
            y1={y1}
            x2={x2}
            y2={y2}
            className={filled ? "cp-accent-stroke" : "cp-ink-stroke"}
            strokeWidth="1.2"
            opacity={filled ? 1 : 0.35}
            strokeLinecap="round"
          />
        );
      })}

      {/* Centre pivot */}
      <circle cx={cx} cy={cy} r="2.4" className="cp-ink-fill" />

      {/* Sweeping hand (active only) */}
      {active && (
        <line
          x1={cx}
          y1={cy}
          x2={cx + Math.cos(handA) * handLen}
          y2={cy + Math.sin(handA) * handLen}
          className="cp-accent-stroke"
          strokeWidth="1.4"
          strokeLinecap="round"
        />
      )}
    </svg>
  );
}

// ───────────────────────────────────────────────────────────────────
// 5 · RESULT — three concentric rings draw inward to a bullseye.
//   "Every signal lands at the centre. Auditable, sealed."
// ───────────────────────────────────────────────────────────────────
function SceneResult({ active, progress }) {
  const p = active ? progress : 1;
  const cx = 100, cy = 60;

  // Three rings — outer fills first, then middle, then inner (accent).
  const rings = [
    { r: 36, accent: false, t: Math.max(0, Math.min(1, p * 3)) },
    { r: 24, accent: false, t: Math.max(0, Math.min(1, p * 3 - 1)) },
    { r: 12, accent: true,  t: Math.max(0, Math.min(1, p * 3 - 2)) },
  ];

  return (
    <svg className="cp-art" viewBox="0 0 200 120" aria-hidden="true">
      {rings.map((ring, i) => {
        const circ = 2 * Math.PI * ring.r;
        return (
          <circle
            key={i}
            cx={cx}
            cy={cy}
            r={ring.r}
            fill="none"
            className={ring.accent ? "cp-accent-stroke" : "cp-ink-stroke"}
            strokeWidth={ring.accent ? "1.2" : "1"}
            strokeDasharray={`${ring.t * circ} ${circ}`}
            transform={`rotate(-90 ${cx} ${cy})`}
            opacity={ring.accent ? 1 : 0.7}
          />
        );
      })}

      {/* Centre bullseye dot — turns accent at the end */}
      <circle
        cx={cx}
        cy={cy}
        r={p > 0.95 ? 3.4 : 2.6}
        className={p > 0.95 ? "cp-accent-fill" : "cp-ink-fill"}
        style={{ transition: "r 200ms ease" }}
      />
    </svg>
  );
}

const SCENES = {
  INTENT:  SceneIntent,
  COMPILE: SceneCompile,
  APPROVE: SceneApprove,
  EXECUTE: SceneExecute,
  RESULT:  SceneResult,
};

function CompilePipeline() {
  const [phaseIdx, setPhaseIdx] = React.useState(0);
  const [progress, setProgress] = React.useState(0);
  // Gate the animation on visibility so it doesn't burn cycles
  // (and looks broken on mobile) before the user scrolls to it.
  const containerRef = React.useRef(null);
  const [inView, setInView] = React.useState(false);
  // When true, every scene renders at progress=1 (full state) and
  // the auto-cycle is paused. The single "Show all" button toggles
  // this. Resuming restarts the cycle from step 1.
  const [pinAll, setPinAll] = React.useState(false);
  // On mobile, the sequential reveal doesn't read well — the user
  // is already vertically scrolling, so animations off-screen feel
  // broken. Show every scene at its final state.
  const [isMobile, setIsMobile] = React.useState(() => {
    if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
      return false;
    }
    return window.matchMedia("(max-width: 640px)").matches;
  });
  React.useEffect(() => {
    if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
    const mq = window.matchMedia("(max-width: 640px)");
    const onChange = (e) => setIsMobile(e.matches);
    if (mq.addEventListener) mq.addEventListener("change", onChange);
    else mq.addListener(onChange);
    return () => {
      if (mq.removeEventListener) mq.removeEventListener("change", onChange);
      else mq.removeListener(onChange);
    };
  }, []);

  React.useEffect(() => {
    const el = containerRef.current;
    if (!el || typeof IntersectionObserver === "undefined") {
      setInView(true);
      return;
    }
    const io = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          if (e.isIntersecting) setInView(true);
          else setInView(false);
        }
      },
      { rootMargin: "0px 0px -20% 0px", threshold: 0.15 }
    );
    io.observe(el);
    return () => io.disconnect();
  }, []);

  React.useEffect(() => {
    if (!inView || pinAll || isMobile) return;
    let raf;
    let alive = true;
    let cur = phaseIdx;
    let stepStart = performance.now() - progress * PHASE_DUR;
    const tick = (now) => {
      if (!alive) return;
      const elapsed = now - stepStart;
      const p = Math.min(1, elapsed / PHASE_DUR);
      setProgress(p);
      if (elapsed >= PHASE_DUR + HOLD_DUR) {
        cur = (cur + 1) % PHASES.length;
        stepStart = now;
        setPhaseIdx(cur);
        setProgress(0);
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => {
      alive = false;
      cancelAnimationFrame(raf);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [inView, pinAll]);

  const toggleShowAll = () => {
    if (pinAll) {
      // Resume: restart the cycle from step 1.
      setPinAll(false);
      setPhaseIdx(0);
      setProgress(0);
    } else {
      // Pin all scenes at their final state.
      setPinAll(true);
    }
  };

  // Per-scene state when pinAll is active vs normal cycling.
  // On mobile, behave as if pinAll is on.
  const allOn = pinAll || isMobile;
  const effectivePhaseIdx = allOn ? PHASES.length - 1 : phaseIdx;

  return (
    <div className={"cp-runthrough" + (isMobile ? " is-mobile" : "")} ref={containerRef}>
      <div className="cp-stage">
        {PHASES.map((ph, i) => {
          const Scene = SCENES[ph.key];
          const isActive = allOn || i === phaseIdx;
          const stateCls = allOn
            ? " is-active"
            : i === phaseIdx
            ? " is-active"
            : i < phaseIdx
            ? " is-past"
            : " is-future";
          const sceneProgress = allOn
            ? 1
            : i === phaseIdx
            ? progress
            : i < phaseIdx
            ? 1
            : 0;
          return (
            <div key={ph.key} className={"cp-scene" + stateCls} aria-hidden={!isActive && !allOn && i > phaseIdx}>
              <div className="cp-scene__art">
                <Scene
                  active={isActive}
                  progress={sceneProgress}
                />
              </div>
              <div className="cp-scene__caption">
                <span className="cp-scene__num">{"/" + String(i + 1).padStart(2, "0")}</span>
                <span className="cp-scene__label">{ph.label}</span>
              </div>
              <CaseSnippet phase={ph.key} key={ph.key + "@" + (allOn ? "all" : phaseIdx)} />
            </div>
          );
        })}
      </div>

      {/* Timeline underneath — desktop / tablet only. On mobile,
          every scene renders at full state simultaneously, so the
          timeline is pointless. */}
      {!isMobile && (
      <div className="cp-timeline" role="group" aria-label="Plan progress">
        <ol className="cp-timeline__track">
          {PHASES.map((ph, i) => {
            const fillScale = pinAll
              ? 1
              : i < phaseIdx
              ? 1
              : i === phaseIdx
              ? progress
              : 0;
            return (
              <li
                key={ph.key}
                className={
                  "cp-timeline__seg" +
                  (i === effectivePhaseIdx ? " is-active" : "") +
                  (pinAll || i < phaseIdx ? " is-past" : "")
                }
              >
                <button
                  type="button"
                  className="cp-timeline__btn"
                  aria-label={`Jump to ${ph.label}`}
                  onClick={() => {
                    setPinAll(false);
                    setPhaseIdx(i);
                    setProgress(1);
                  }}
                >
                  <span
                    className="cp-timeline__fill"
                    style={{ transform: `scaleX(${fillScale})` }}
                  />
                </button>
              </li>
            );
          })}
        </ol>
        <button
          type="button"
          className={"cp-timeline__toggle" + (pinAll ? " is-on" : "")}
          onClick={toggleShowAll}
          title={pinAll ? "Restart the cycle from step 1" : "Pin every step at its final state"}
        >
          {pinAll ? "↻ Restart" : "Show all"}
        </button>
      </div>
      )}
    </div>
  );
}

window.CompilePipeline = CompilePipeline;
