// altriks-pipeline.jsx — <HeroPipeline>, the animated product story (centerpiece).
// Vic.ai-style guided storyboard: a journey rail (Capture → Extract → Match → Validate → Review →
// Deliver) fills stage-by-stage while a narrative card crossfades and a per-stage product "moment"
// plays, landing on the real Orders app.
//
// Loads AFTER altriks-ui.jsx (reads window.POAppMock / BrowserFrame / AppIcon) and BEFORE altriks-hero.jsx.
//
// Engine: one in-view-gated rAF clock. We only setState when the BEAT changes (not per frame),
// so the heavy POAppMock re-renders just twice per loop. All motion is CSS keyed off [data-phase].

// Single source of truth — rail + narrative cards both .map() over this, so the rail-fill index and
// the stage count stay in sync automatically. Copy mirrors the site's STEPS/FEATURES constants.
const STAGES = [
  { key: "capture",  n: 1, label: "Capture",
    title: "Every PO, however it arrives",
    body: "Email, PDF, or API — Altriks picks it up automatically. No new portal for your customers." },
  { key: "extract",  n: 2, label: "Extract",
    title: "Reads every line — no templates",
    body: "AI captures the header, ship-to, and every line — typed or scanned — in seconds." },
  { key: "match",    n: 3, label: "Match",
    title: "Matched to your master data",
    body: "Customer, ship-to site, and every product, resolved against your own records." },
  { key: "validate", n: 4, label: "Validate",
    title: "Checked against the agreed quote",
    body: "Every price and quantity is validated — a wrong line is caught, not keyed into your ERP." },
  { key: "review",   n: 5, label: "Review",
    title: "Review exceptions, not every order",
    body: "Clean orders flow straight through; only true exceptions reach your queue." },
  { key: "deliver",  n: 6, label: "Deliver",
    title: "ERP-ready in seconds",
    body: "A clean, structured order lands over API or webhook — with a full audit trail." },
];

const TIMELINE = [
  { key: "idle",     end: 500 },
  { key: "capture",  end: 3000 },
  { key: "extract",  end: 5500 },
  { key: "match",    end: 8000 },
  { key: "validate", end: 10500 },
  { key: "review",   end: 13000 },
  { key: "deliver",  end: 15600 },
  { key: "hold",     end: 17200 },
  { key: "reset",    end: 18000 },
];
const LOOP = 18000;

const __pipeReduce =
  typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;

// Memoize the destination app so a beat change only re-renders it when revealFirstRow flips.
// Resolve window.POAppMock lazily (at render) so this file is robust to <script> reordering.
const __MockMemo = React.memo((props) => React.createElement(window.POAppMock, props));

// The fields the OCR "types out" during EXTRACT. Qty 26 here is intentionally the as-ordered figure;
// VALIDATE catches it against the agreed quote (24), REVIEW corrects it, and DELIVER lands the
// reconciled $11,385.00 row (24 × $474.38) shown in POAppMock.
const FIELDS = [
  { k: "PO Number", v: "KGB-2026-0214-991" },
  { k: "Bill To", v: "Kyoto Garden — Greenhouse 3" },
  { k: "Order Date", v: "May 14, 2026" },
  { k: "Line 1", v: "26× Trellis Panel" },
  { k: "Amount", v: "$12,333.88" },
];

function PipeCheck() {
  return (
    <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
      <path d="M3 7.2l2.6 2.6L11 4.2" stroke="#fff" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}
function PipeWarn() {
  return (
    <svg width="13" height="13" viewBox="0 0 16 16" fill="none" aria-hidden="true">
      <path d="M8 2.3l6 10.4H2L8 2.3z" stroke="#fff" strokeWidth="1.6" strokeLinejoin="round" />
      <path d="M8 6.6v3.1M8 11.4v.1" stroke="#fff" strokeWidth="1.7" strokeLinecap="round" />
    </svg>
  );
}

function PipeMatchCard({ icon, label, from, to, tag }) {
  return (
    <div className="alt-pipe__matchcard">
      <span className="alt-pipe__mcicon"><window.AppIcon name={icon} size={15} /></span>
      <div className="alt-pipe__mcbody">
        <div className="alt-pipe__mclabel">{label}</div>
        <div className="alt-pipe__mcfrom">{from}</div>
        <div className="alt-pipe__mcto">{to} <em>{tag}</em></div>
      </div>
      <span className="ring" aria-hidden="true" />
      <span className="alt-pipe__check" aria-hidden="true"><PipeCheck /></span>
    </div>
  );
}

// The journey rail. railIndex drives both the fill (via the --rail-i custom prop) and each dot's state.
function PipeRail({ railIndex }) {
  return (
    <div className="alt-pipe__rail" style={{ "--rail-i": railIndex }} aria-hidden="true">
      <div className="alt-pipe__railtrack"><div className="alt-pipe__railfill" /></div>
      {STAGES.map((s, i) => (
        <div
          key={s.key}
          className="alt-pipe__dot"
          data-state={i < railIndex ? "done" : i === railIndex ? "active" : "future"}
          style={{ left: ((i + 0.5) / STAGES.length * 100) + "%" }}
        >
          <span className="alt-pipe__dotwrap"><span className="alt-pipe__dotcore" /></span>
          <span className="alt-pipe__dotlabel">{s.label}</span>
        </div>
      ))}
    </div>
  );
}

function HeroPipeline() {
  const [phase, setPhase] = React.useState(__pipeReduce ? "hold" : "idle");
  const rootRef = React.useRef(null);
  const raf = React.useRef(0);
  const base = React.useRef(0);
  const playing = React.useRef(false);
  const cur = React.useRef(phase);

  React.useEffect(() => {
    if (__pipeReduce || typeof IntersectionObserver === "undefined") { setPhase("hold"); return; }
    const phaseAt = (t) => {
      const x = t % LOOP;
      const seg = TIMELINE.find((p) => x < p.end);
      return seg ? seg.key : "reset";
    };
    const tick = () => {
      const ph = phaseAt(performance.now() - base.current);
      if (ph !== cur.current) { cur.current = ph; setPhase(ph); }
      raf.current = requestAnimationFrame(tick);
    };
    const start = () => { if (!playing.current) { playing.current = true; base.current = performance.now(); tick(); } };
    const stop = () => { playing.current = false; cancelAnimationFrame(raf.current); };
    let inView = false;
    const io = new IntersectionObserver(
      ([e]) => { inView = e.isIntersecting; if (inView && !document.hidden) start(); else stop(); },
      { rootMargin: "-15% 0px -15% 0px", threshold: 0 }
    );
    if (rootRef.current) io.observe(rootRef.current);
    const onVis = () => { if (document.hidden) stop(); else if (inView) start(); };
    document.addEventListener("visibilitychange", onVis);
    return () => { io.disconnect(); cancelAnimationFrame(raf.current); document.removeEventListener("visibilitychange", onVis); };
  }, []);

  const idx = STAGES.findIndex((s) => s.key === phase);    // capture..deliver → 0..5; idle/hold/reset → -1
  const railIndex = phase === "hold" ? STAGES.length - 1 : idx; // hold parks on full rail; idle/reset → -1
  const revealRow = phase === "deliver" || phase === "hold";

  return (
    <div className="alt-pipe" ref={rootRef} data-phase={phase} aria-hidden="true">
      <div className="alt-pipe__screen">
        <window.BrowserFrame url="app.altriks.com/orders" live>
          <__MockMemo revealFirstRow={revealRow} />
        </window.BrowserFrame>

        <div className="alt-pipe__stagewrap">
          {/* product moments — absolute-stacked, cross-faded by [data-phase], collapse on the payoff.
              The journey rail below names each stage, so no narrative card is shown. */}
          <div className="alt-pipe__focus">
            {/* 1 — CAPTURE: the incoming PO document */}
            <div className="alt-pipe__moment alt-pipe__moment--capture">
              <div className="alt-pipe__doc">
                <div className="alt-pipe__chip">
                  <window.AppIcon name="clip" size={14} /> PO_4471.pdf
                  <span className="alt-pipe__from"><window.AppIcon name="mail" size={13} /> orders@kyotogarden.com</span>
                </div>
                <div className="alt-pipe__lines">
                  <i style={{ width: "62%" }} /><i style={{ width: "88%" }} /><i style={{ width: "74%" }} />
                  <i style={{ width: "92%" }} /><i style={{ width: "55%" }} /><i style={{ width: "80%" }} />
                </div>
              </div>
            </div>

            {/* 2 — EXTRACT: fields typed out under a scan beam */}
            <div className="alt-pipe__moment alt-pipe__moment--extract">
              <div className="alt-pipe__fields">
                <div className="alt-pipe__beam" />
                {FIELDS.map((f, i) => (
                  <div className="alt-pipe__field" key={f.k} style={{ "--d": (0.15 + i * 0.14) + "s" }}>
                    <span>{f.k}</span>
                    <b><i className="alt-pipe__type">{f.v}</i></b>
                  </div>
                ))}
              </div>
            </div>

            {/* 3 — MATCH: resolve against master data */}
            <div className="alt-pipe__moment alt-pipe__moment--match">
              <div className="alt-pipe__match">
                <PipeMatchCard icon="users" label="Customer" from="orders@kyotogarden.com" to="Kyoto Garden" tag="CUST-1042" />
                <PipeMatchCard icon="building" label="Ship-to site" from="“Greenhouse 3”" to="Greenhouse 3" tag="SITE-3" />
                <PipeMatchCard icon="box" label="Product" from="“Trellis Panel”" to="SKU TP-24" tag="Master Data" />
              </div>
            </div>

            {/* 4 — VALIDATE: check each line against the agreed quote */}
            <div className="alt-pipe__moment alt-pipe__moment--validate">
              <div className="alt-pipe__quote">
                <div className="alt-pipe__qhead">
                  <window.AppIcon name="file" size={14} /> Line 1 · Trellis Panel
                  <span>vs QUOTE-1042</span>
                </div>
                <div className="alt-pipe__qrow alt-pipe__qrow--ok">
                  <span className="alt-pipe__qlabel">Unit price</span>
                  <span className="alt-pipe__qval">$474.38 <em>=</em> $474.38</span>
                  <span className="alt-pipe__qbadge alt-pipe__qbadge--ok"><PipeCheck /></span>
                </div>
                <div className="alt-pipe__qrow alt-pipe__qrow--warn">
                  <span className="alt-pipe__qlabel">Quantity</span>
                  <span className="alt-pipe__qval">PO 26 <em>≠</em> Quote 24</span>
                  <span className="alt-pipe__qbadge alt-pipe__qbadge--warn"><PipeWarn /></span>
                </div>
                <div className="alt-pipe__qflag">1 line flagged — routed to review</div>
              </div>
            </div>

            {/* 5 — REVIEW: a human clears the one exception; clean lines never stop */}
            <div className="alt-pipe__moment alt-pipe__moment--review">
              <div className="alt-pipe__queue">
                <div className="alt-pipe__qhdr">
                  <span><window.AppIcon name="users" size={14} /> Review queue</span>
                  <span className="alt-pipe__qcount">
                    <b className="alt-pipe__qc1">1</b>
                    <b className="alt-pipe__qc0">0</b>
                  </span>
                </div>
                <div className="alt-pipe__qitem">
                  <span className="alt-pipe__qidesc">Quantity · Trellis Panel</span>
                  <span className="alt-pipe__qibefore">PO 26 → 24</span>
                  <span className="alt-pipe__qicheck" aria-hidden="true"><PipeCheck /></span>
                </div>
                <div className="alt-pipe__qready">Adjusted to the agreed quote · order ready to deliver</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <PipeRail railIndex={railIndex} />
    </div>
  );
}

Object.assign(window, { HeroPipeline });
