/* Animated product visuals for the four product-overview feature rows.
   Each recreates a real Mesh UI surface in calm motion: off-white card,
   white window chrome, ONE focal element. Motion only runs in view, eases
   on cubic-bezier(.22,1,.36,1), holds ~1.6s, then loops. prefers-reduced-
   motion → jumps straight to the finished end state, no animation. */

function fsReduced() {
  return typeof window.matchMedia === 'function' &&
    window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

/* Staggered reveal: returns a count 0..total that climbs one per step,
   holds at full, then resets and loops. Reduced motion → pinned at total. */
function useStagger(total, inView, { stepMs = 640, holdMs = 1700 } = {}) {
  const [n, setN] = React.useState(0);
  React.useEffect(() => {
    if (!inView) return;
    if (fsReduced()) { setN(total); return; }
    let t; let c = 0; setN(0);
    const step = () => {
      c += 1; setN(c);
      if (c >= total) { t = setTimeout(() => { c = 0; setN(0); t = setTimeout(step, stepMs); }, holdMs); }
      else { t = setTimeout(step, stepMs); }
    };
    t = setTimeout(step, stepMs);
    return () => clearTimeout(t);
  }, [inView, total, stepMs, holdMs]);
  return n;
}

/* Phase cycler: loops 0→1→…→count-1→0. Reduced motion → pinned at last. */
function usePhases(count, inView, durations) {
  const [p, setP] = React.useState(0);
  React.useEffect(() => {
    if (!inView) return;
    if (fsReduced()) { setP(count - 1); return; }
    let t; let c = 0; setP(0);
    const tick = () => { c = (c + 1) % count; setP(c); t = setTimeout(tick, durations[c]); };
    t = setTimeout(tick, durations[0]);
    return () => clearTimeout(t);
  }, [inView, count]);
  return p;
}

/* Phase loop: dwell on phase i for durations[i], then advance, looping.
   Reduced motion → pinned at reduceTo. */
function usePhaseLoop(durations, inView, reduceTo) {
  const [p, setP] = React.useState(0);
  React.useEffect(() => {
    if (!inView) return;
    if (fsReduced()) { setP(reduceTo); return; }
    let t; let c = 0; setP(0);
    const tick = () => { c = (c + 1) % durations.length; setP(c); t = setTimeout(tick, durations[c]); };
    t = setTimeout(tick, durations[0]);
    return () => clearTimeout(t);
  }, [inView]);
  return p;
}

const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);

/* Count a figure up from 0 → `to` when `active`. */
function CountUp({ to, active }) {
  const [v, setV] = React.useState(0);
  React.useEffect(() => {
    if (!active) { setV(0); return; }
    if (fsReduced()) { setV(to); return; }
    let raf; const dur = 460; const start = performance.now();
    const step = (now) => {
      const t = Math.min(1, (now - start) / dur);
      setV(Math.round(easeOutCubic(t) * to));
      if (t < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [active, to]);
  return <span>${v.toLocaleString()}</span>;
}

/* ── 1. Vendor outreach (Slack DM) → one unified row ───────────────── */
const FS_FRAGMENTS = [
  { icon: 'file-text', src: 'Contract', text: 'MSA v3 · Salesforce', x: 150, y: -76, r: 6 },
  { icon: 'receipt', src: 'Invoice', text: 'Invoice #4471', x: -150, y: 82, r: -5 },
];
const FS_COSTS = [['Incurred', 8250, 'in'], ['Prepaid', 1200, 'pre'], ['Incoming', 3400, 'inc']];

function ShotUnified() {
  const [ref, inView] = useReveal();
  // 0 pre · 1 Slack DM + chips in · 2 converge · 3 row resolves · 4 count + hold
  const phase = usePhaseLoop([220, 2400, 1500, 1200, 2400], inView, 4);
  const converged = phase >= 2;
  const rowShown = phase >= 3;
  const counting = phase >= 4;
  return (
    <div className="fs fs--star" ref={ref}>
      <div className="fs-win">
        <div className="fs-win-bar">
          <span className="fs-win-title">october · vendor costs</span>
          <span className={'fs-badge' + (counting ? ' on' : '')}>
            <Icon name={counting ? 'check' : 'git-merge'} className="ic" /> {counting ? 'Unified' : 'Gathering…'}
          </span>
        </div>
        <div className="fsu-stage">
          {FS_FRAGMENTS.map((c) => (
            <div className="fsu-chip" key={c.src} style={{
              opacity: phase === 1 ? 1 : 0,
              transform: converged
                ? 'translate(-50%, -50%) scale(.72)'
                : `translate(calc(-50% + ${c.x}px), calc(-50% + ${c.y}px)) rotate(${c.r}deg)`,
            }}>
              <span className="fsu-chip-ic"><Icon name={c.icon} className="ic" /></span>
              <div className="fsu-chip-tx-wrap">
                <div className="fsu-chip-src">{c.src}</div>
                <div className="fsu-chip-tx">{c.text}</div>
              </div>
            </div>
          ))}

          <div className="fsu-slack" style={{
            opacity: phase === 1 ? 1 : 0,
            transform: converged
              ? 'translate(-50%, -50%) scale(.8)'
              : 'translate(-50%, calc(-50% - 4px)) rotate(-1.5deg)',
          }}>
            <div className="fsu-slack-hd">
              <span className="fsu-slack-av">M</span>
              <span className="fsu-slack-nm">Mesh</span>
              <span className="fsu-slack-app">APP</span>
              <span className="fsu-slack-tm">9:02 AM</span>
            </div>
            <div className="fsu-slack-msg">Hi Sarah, can you confirm receipt of services from Salesforce for October? Mesh needs this by EOD to complete the accrual.</div>
            <div className="fsu-slack-tag"><Icon name="sparkles" className="ic" /> Sent by Mesh</div>
          </div>

          <div className="fsu-row" style={{
            opacity: rowShown ? 1 : 0,
            transform: `translate(-50%, -50%) scale(${rowShown ? 1 : 0.94})`,
          }}>
            <div className="fsu-vendor">
              <span className="fsu-avatar">SF</span>Salesforce
              <span className="fsu-period">Oct</span>
            </div>
            <div className="fsu-cells">
              {FS_COSTS.map(([k, val, tone]) => (
                <div className="fsu-cell" key={k}>
                  <span className="fsu-k">{k}</span>
                  <span className={'fsu-v fsu-v--' + tone}><CountUp to={val} active={counting} /></span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── 2. Policy engine: write the rule once, runs every period ──────── */
const FS_POLICY_RULE = 'Accrue rent monthly → split evenly across lease term';
const FS_PERIODS = ['Apr', 'May', 'Jun'];

/* Timeline: type the rule → reveal tag → check Apr/May/Jun in sequence →
   settle → pause → loop. Reduced motion jumps to the finished state. */
function usePolicyTimeline(inView) {
  const [typed, setTyped] = React.useState(0);
  const [showTag, setShowTag] = React.useState(false);
  const [checked, setChecked] = React.useState(0);
  React.useEffect(() => {
    if (!inView) return;
    const full = FS_POLICY_RULE.length;
    if (fsReduced()) { setTyped(full); setShowTag(true); setChecked(3); return; }
    let typeInt; const timers = [];
    const run = () => {
      setTyped(0); setShowTag(false); setChecked(0);
      let i = 0;
      typeInt = setInterval(() => {
        i += 1; setTyped(i);
        if (i >= full) {
          clearInterval(typeInt);
          timers.push(setTimeout(() => setShowTag(true), 300));
          timers.push(setTimeout(() => setChecked(1), 820));
          timers.push(setTimeout(() => setChecked(2), 1240));
          timers.push(setTimeout(() => setChecked(3), 1660));
          timers.push(setTimeout(run, 1660 + 1500)); // settle + 1.5s pause, then loop
        }
      }, 28);
    };
    run();
    return () => { clearInterval(typeInt); timers.forEach(clearTimeout); };
  }, [inView]);
  return { typed, showTag, checked };
}

function ShotPolicy() {
  const [ref, inView] = useReveal();
  const { typed, showTag, checked } = usePolicyTimeline(inView);
  const typing = typed < FS_POLICY_RULE.length;
  return (
    <div className="fs fs--star" ref={ref}>
      <div className="fs-win">
        <div className="fs-win-bar">
          <span className="fs-win-title">accrual policy · editor</span>
          <span className="fsp-live"><Icon name="refresh-cw" className="ic" /> Runs every close</span>
        </div>
        <div className="fsp-body">
          <div className="fsp-rule">
            <span className="fsp-rule-ic"><Icon name="file-code-2" className="ic" /></span>
            <span className="fsp-rule-tx">
              {FS_POLICY_RULE.slice(0, typed)}
              {typing && <span className="fsp-caret"></span>}
            </span>
          </div>
          <div className={'fsp-tag' + (showTag ? ' show' : '')}>
            <Icon name="pencil" className="ic" /> Policy v4 · human-editable
          </div>
          <div className="fsp-periods">
            {FS_PERIODS.map((p, i) => (
              <div className={'fsp-chip' + (i < checked ? ' done' : '')} key={p}>
                <span className="fsp-chip-p">{p}</span>
                <span className="fsp-chip-st">
                  {i < checked
                    ? <React.Fragment><Icon name="check" className="ic" /> Accrued</React.Fragment>
                    : '—'}
                </span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── 3. Audit trail (featured): figure → its full source lineage ───── */
const FS_LINEAGE = [
  ['file-cog', 'Policy v4'],
  ['scroll-text', 'Vendor contract, MSA v3'],
  ['receipt', 'Invoice #4471'],
];

/* Timeline: figure rests → connector draws down → 3 lineage nodes reveal
   in sequence → "Full audit trail" label fades in → pause → loop. */
function useAuditTimeline(inView) {
  const [drawn, setDrawn] = React.useState(false);
  const [nodes, setNodes] = React.useState(0);
  const [showLabel, setShowLabel] = React.useState(false);
  React.useEffect(() => {
    if (!inView) return;
    if (fsReduced()) { setDrawn(true); setNodes(3); setShowLabel(true); return; }
    const timers = [];
    const run = () => {
      setDrawn(false); setNodes(0); setShowLabel(false);
      timers.push(setTimeout(() => setDrawn(true), 320));
      timers.push(setTimeout(() => setNodes(1), 720));
      timers.push(setTimeout(() => setNodes(2), 1100));
      timers.push(setTimeout(() => setNodes(3), 1480));
      timers.push(setTimeout(() => setShowLabel(true), 1860));
      timers.push(setTimeout(run, 1860 + 1500));
    };
    run();
    return () => timers.forEach(clearTimeout);
  }, [inView]);
  return { drawn, nodes, showLabel };
}

function ShotAudit() {
  const [ref, inView] = useReveal();
  const { drawn, nodes, showLabel } = useAuditTimeline(inView);
  return (
    <div className="fs fs--star" ref={ref}>
      <div className="fs-win">
        <div className="fsa-top">
          <div className="fsa-num">$8,250</div>
          <div className="fsa-label">Accrued expense</div>
        </div>
        <div className="fsa-chain">
          <span className={'fsa-line' + (drawn ? ' drawn' : '')}></span>
          {FS_LINEAGE.map(([ic, tx], i) => (
            <div className={'fsa-node' + (i < nodes ? ' show' : '')} key={tx}>
              <span className="fsa-node-ic"><Icon name={ic} className="ic" /></span>
              <span className="fsa-node-tx">{tx}</span>
            </div>
          ))}
        </div>
        <div className={'fsa-trail' + (showLabel ? ' show' : '')}>
          <Icon name="shield-check" className="ic" /> Full audit trail
        </div>
      </div>
    </div>
  );
}

/* ── 4. Post to ERP: approve here, it lands in the ERP, no re-keying ── */
const FS_ERP_STATUS = [
  ['check', 'Approved'],
  ['arrow-up-from-line', 'Posted'],
  ['check-check', 'Synced to NetSuite'],
];

function ShotErp() {
  const [ref, inView] = useReveal();
  const phase = usePhases(3, inView, [1500, 1400, 2600]); // Approved → Posted → Synced (holds)
  const [ic, label] = FS_ERP_STATUS[phase];
  return (
    <div className="fs fs--star" ref={ref}>
      <div className="fs-win">
        <div className="fs-win-bar">
          <span className="fs-win-title">journal entry</span>
          <span className={'fse-pill fse-pill--' + phase} key={phase}>
            <Icon name={ic} className="ic" /> {label}
          </span>
        </div>
        <div className="fse-flow">
          <div className="fse-je">
            <div className="fse-je-id">JE-2208</div>
            <div className="fse-je-meta">Accrued expense</div>
            <div className="fse-je-amt">$8,250</div>
          </div>
          <div className="fse-conn"><span className={'fse-conn-line' + (phase >= 1 ? ' on' : '')}></span></div>
          <div className={'fse-erp' + (phase >= 2 ? ' done' : '')}>
            <span className="fse-erp-logo">NS</span>
            <span className="fse-erp-name">NetSuite</span>
            <span className="fse-erp-check"><Icon name="check" className="ic" /></span>
          </div>
        </div>
        <div className={'fse-note' + (phase >= 2 ? ' show' : '')}>
          <Icon name="shield-check" className="ic" /> No re-keying · no rip-and-replace
        </div>
      </div>
    </div>
  );
}

/* ── 5. Variance analysis: a flagged swing, traced to its origin ───── */
/* BVA bars — one vendor over its budget line, highlighted. Salesforce is the
   centered, flagged bar. Heights are % of the plot. */
const FSV_BARS = [
  ['Atlassian', 30],
  ['Datadog', 38],
  ['Salesforce', 80, true],
  ['Slack', 26],
  ['AWS', 34],
];
/* Trace path: variance → accrual policy version → data source. */
const FSV_TRACE = [
  ['trending-up', 'Variance', '+$3,400'],
  ['file-cog', 'Policy', 'Accrual v4'],
  ['database', 'Source', 'Coupa PO #4471'],
];

function ShotVariance() {
  const [ref, inView] = useReveal();
  // 0 reset · 1 bars grow (flag) · 2 cursor + tooltip · 3-5 trace nodes · 6 explained
  const phase = usePhaseLoop([260, 1600, 1600, 740, 740, 780, 2600], inView, 6);
  const grown = phase >= 1;
  const resolved = phase >= 6;
  const flagged = grown && !resolved;
  const tipShown = phase >= 2;
  const nodesShown = Math.min(3, Math.max(0, phase - 2));
  return (
    <div className="fs fs--star" ref={ref}>
      <div className="fs-win">
        <div className="fs-win-bar">
          <span className="fs-win-title">vendor variance · october</span>
          <span className={'fs-badge' + (resolved ? ' on' : flagged ? ' flag' : '')}>
            <Icon name={resolved ? 'shield-check' : flagged ? 'alert-triangle' : 'bar-chart-3'} className="ic" />
            {resolved ? 'Explained' : flagged ? 'Variance flagged' : 'Budget vs actual'}
          </span>
        </div>
        <div className="fsv-plot">
          <div className={'fsv-tip' + (tipShown ? ' show' : '') + (resolved ? ' ok' : '')}>
            <div className="fsv-tip-hd">
              <span className="fsv-avatar">SF</span> Salesforce
            </div>
            <div className="fsv-tip-amt">+$3,400</div>
            <div className="fsv-tip-sub">
              {resolved
                ? <React.Fragment><Icon name="check" className="ic" /> Explained · +41% vs budget</React.Fragment>
                : '+41% vs budget'}
            </div>
            <span className="fsv-tip-caret"></span>
          </div>
          <div className="fsv-bars">
            <div className="fsv-budget"><span className="fsv-budget-tag">Budget</span></div>
            {FSV_BARS.map(([name, pct, flag]) => (
              <div className="fsv-bar" key={name}>
                <div
                  className={'fsv-bar-fill' + (flag ? (resolved ? ' resolved' : ' flag') : '')}
                  style={{ height: grown ? pct + '%' : '0%' }}
                ></div>
                <span className="fsv-bar-lbl">{name}</span>
              </div>
            ))}
          </div>
          <div className={'fsv-cursor' + (tipShown ? ' on' : '')}>
            <Icon name="mouse-pointer-2" className="ic" />
          </div>
        </div>
        <div className="fsv-trace">
          {FSV_TRACE.map(([ic, k, v], i) => (
            <React.Fragment key={k}>
              {i > 0 && <span className={'fsv-tconn' + (i < nodesShown ? ' on' : '')}></span>}
              <div className={'fsv-tnode' + (i < nodesShown ? ' show' : '') + (resolved ? ' ok' : '')}>
                <span className="fsv-tnode-ic"><Icon name={ic} className="ic" /></span>
                <span className="fsv-tnode-tx">
                  <span className="fsv-tnode-k">{k}</span>
                  <span className="fsv-tnode-v">{v}</span>
                </span>
              </div>
            </React.Fragment>
          ))}
        </div>
      </div>
    </div>
  );
}

window.FS_SHOTS = { unified: ShotUnified, policy: ShotPolicy, audit: ShotAudit, erp: ShotErp, variance: ShotVariance };
Object.assign(window, { ShotUnified, ShotPolicy, ShotAudit, ShotErp, ShotVariance });
