// Corridor guided tour — a self-contained coach-mark system layered
// over the existing dashboard routes. A path through pages, not a
// single-page overlay: each step declares the route + detail state it
// needs (resolved by the App), then spotlights one real element.
// Soft scrim, 2px indigo ring, white popover. Full keyboard + ARIA;
// honors prefers-reduced-motion; docks popovers as a bottom sheet on
// narrow viewports.
const NS_tour = window.CorridorDesignSystem_8d69e0;

const SCRIM = "hsl(230 24% 12% / 0.45)";
const DISMISS_KEY = "corridor_demo_tour_dismissed";

// ── Step script — content + the app-state each step needs ─────────
// nav: { route, eventId? } — applied by the App before the popover
// renders. target/targets: selector(s) spotlighted (union rect).
window.TOUR_STEPS = [
  {
    nav: { route: "overview" }, target: '[data-tour="demo-banner"]', place: "bottom",
    title: "You're inside the real dashboard",
    body: "This is the actual Corridor provider console, running on synthetic data. Nothing here is a live account — click freely.",
  },
  {
    nav: { route: "agents" }, target: '[data-tour="agents-table"] tbody tr:nth-child(1)',
    title: "Identity is the unit, not the API key", token: "agt_4hx9k2",
    body: "Every call is attributed to the agent that made it, so spend and limits are per-agent. Note the revoked agents below: you can cut one off without touching the others.",
  },
  {
    nav: { route: "events" },
    targets: ['[data-tour="events-table"] thead th:nth-child(2)', '[data-tour="events-table"] tbody tr:nth-child(1) td:nth-child(2)', '[data-tour="events-table"] tbody tr:nth-child(2) td:nth-child(2)', '[data-tour="events-table"] tbody tr:nth-child(3) td:nth-child(2)'],
    place: "right",
    title: "Every call is a metered event",
    body: "Each event moves through a lifecycle: authorized → captured → settled. Color tells you where it is — amber in flight, green settled, red failed.",
  },
  {
    nav: { route: "events", eventId: "evt_demo_8c41af" }, target: '[data-tour="event-timeline"]', place: "left",
    title: "Money has a lifecycle, with receipts",
    body: "Authorize, capture, settle — each timestamped. Open any event and you can see exactly which rule priced it and which policy cleared it.",
  },
  {
    nav: { route: "pricing" }, target: '[data-tour="pricing-table"] tbody tr:nth-child(1)',
    title: "The rule that priced it — versioned, immutable", token: "INV-PRICING-PUBLISHED-IS-IMMUTABLE",
    body: "Published pricing is locked. “Why did this cost $1.00?” always has an answer you can point at. Drafts wait safely beside it.",
  },
  {
    nav: { route: "policies" },
    targets: ['[data-tour="policies-table"] tbody tr:nth-child(1)', '[data-tour="policies-table"] tbody tr:nth-child(2)'],
    title: "Guardrails run before the work",
    body: "Spend caps, rate limits, denylists — evaluated at authorize time, per agent. The next step shows what that actually saves you.",
  },
  {
    nav: { route: "overview" }, target: '[data-tour="overview-chart"]', place: "bottom",
    title: "Spend is a graph, not a surprise invoice",
    body: "Per-agent spend over time, with denied calls overlaid. Runaway usage shows up here as a spike you can see — long before an invoice would.",
  },
  {
    nav: { route: "overview" }, target: '[data-tour="overview-sim"]', place: "right", gateOnSim: true,
    title: "Watch a runaway agent get stopped",
    body: "Hit Simulate. An agent fires a burst of calls, spend races toward its cap — then the budget policy denies the rest, before any of it executes. This is the whole point.",
  },
  {
    nav: { route: "settlement" }, target: '[data-tour="settlement-table"] tbody tr:nth-child(1)', place: "bottom",
    title: "Money out traces back to money in", cta: true,
    body: "Captured events settle on your rail, and every payout traces to the events — and agents — that earned it. That's the loop.",
  },
];

const isMobile = () => window.innerWidth <= 640;
const rm = () => window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;

function unionRect(step) {
  const sels = step.targets || (step.target ? [step.target] : []);
  const els = sels.flatMap((s) => Array.from(document.querySelectorAll(s)));
  if (!els.length) return null;
  let l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
  els.forEach((el) => {
    const cr = el.getBoundingClientRect();
    l = Math.min(l, cr.left); t = Math.min(t, cr.top);
    r = Math.max(r, cr.right); b = Math.max(b, cr.bottom);
  });
  return { left: l, top: t, width: r - l, height: b - t, bottom: b, right: r, els };
}

// ── The running tour overlay ──────────────────────────────────────
function Tour({ index, nextDisabled, onNext, onBack, onSkip, onDone }) {
  const { Button } = NS_tour;
  const step = window.TOUR_STEPS[index];
  const last = index === window.TOUR_STEPS.length - 1;
  const [hole, setHole] = React.useState(null);
  const [ready, setReady] = React.useState(false);
  const [pos, setPos] = React.useState(null);
  const popRef = React.useRef(null);
  const reduced = rm();
  const PAD = 8;

  // locate target (with retry + scroll-into-view + shimmer fallback)
  React.useEffect(() => {
    setReady(false);
    let raf, tries = 0, scrolled = false, alive = true;
    function attempt() {
      if (!alive) return;
      const rect = unionRect(step);
      if (!rect) {
        if (tries++ < 60) { raf = setTimeout(attempt, 50); }
        return;
      }
      const vh = window.innerHeight;
      const out = rect.top < 84 || rect.bottom > vh - 150;
      if (out && !scrolled && !isMobile()) {
        scrolled = true;
        const target = window.scrollY + rect.top - Math.max((vh - rect.height) / 2, 90);
        window.scrollTo({ top: Math.max(target, 0), behavior: reduced ? "auto" : "smooth" });
        raf = setTimeout(attempt, reduced ? 0 : 260);
        return;
      }
      if (isMobile() && out) {
        const target = window.scrollY + rect.top - 120;
        window.scrollTo({ top: Math.max(target, 0), behavior: reduced ? "auto" : "smooth" });
      }
      const fresh = unionRect(step) || rect;
      setHole({ left: fresh.left, top: fresh.top, width: fresh.width, height: fresh.height });
      // describedby wiring
      fresh.els && fresh.els[0] && fresh.els[0].setAttribute("aria-describedby", "cor-tour-body");
      setReady(true);
    }
    attempt();
    return () => {
      alive = false; clearTimeout(raf);
      document.querySelectorAll("[aria-describedby='cor-tour-body']").forEach((el) => el.removeAttribute("aria-describedby"));
    };
  }, [index]);

  // reposition on resize / scroll
  React.useEffect(() => {
    if (!ready) return;
    function recompute() {
      const rect = unionRect(step);
      if (rect) setHole({ left: rect.left, top: rect.top, width: rect.width, height: rect.height });
    }
    window.addEventListener("resize", recompute);
    window.addEventListener("scroll", recompute, true);
    return () => {
      window.removeEventListener("resize", recompute);
      window.removeEventListener("scroll", recompute, true);
    };
  }, [ready, index]);

  // position the popover from its measured size
  React.useLayoutEffect(() => {
    if (!ready || !hole || !popRef.current) return;
    if (isMobile()) { setPos({ mobile: true }); return; }
    const pr = popRef.current.getBoundingClientRect();
    const vw = window.innerWidth, vh = window.innerHeight, gap = 14, m = 12;
    const cx = hole.left + hole.width / 2, cy = hole.top + hole.height / 2;
    const prefer = step.place || "bottom";
    const space = {
      bottom: vh - (hole.top + hole.height), top: hole.top,
      right: vw - (hole.left + hole.width), left: hole.left,
    };
    const order = [prefer, "bottom", "top", "right", "left"];
    let placement = order.find((p) => {
      if (p === "bottom" || p === "top") return space[p] >= pr.height + gap + m;
      return space[p] >= pr.width + gap + m;
    }) || prefer;

    let top, left;
    if (placement === "bottom") { top = hole.top + hole.height + gap; left = cx - pr.width / 2; }
    else if (placement === "top") { top = hole.top - gap - pr.height; left = cx - pr.width / 2; }
    else if (placement === "right") { left = hole.left + hole.width + gap; top = cy - pr.height / 2; }
    else { left = hole.left - gap - pr.width; top = cy - pr.height / 2; }

    left = Math.max(m, Math.min(left, vw - pr.width - m));
    top = Math.max(m, Math.min(top, vh - pr.height - m));
    const arrow = (placement === "bottom" || placement === "top")
      ? { axis: "x", off: Math.max(16, Math.min(cx - left, pr.width - 16)) }
      : { axis: "y", off: Math.max(16, Math.min(cy - top, pr.height - 16)) };
    setPos({ top, left, placement, arrow });
  }, [ready, hole, index]);

  // keyboard
  React.useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape") { e.preventDefault(); onSkip(); }
      else if (e.key === "ArrowLeft") { if (index > 0) onBack(); }
      else if (e.key === "ArrowRight" || e.key === "Enter") {
        e.preventDefault();
        if (nextDisabled) return;
        last ? onDone() : onNext();
      } else if (e.key === "Tab") {
        const f = popRef.current && popRef.current.querySelectorAll("button, a[href]");
        if (!f || !f.length) return;
        const first = f[0], lastEl = f[f.length - 1];
        if (e.shiftKey && document.activeElement === first) { e.preventDefault(); lastEl.focus(); }
        else if (!e.shiftKey && document.activeElement === lastEl) { e.preventDefault(); first.focus(); }
      }
    }
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [index, nextDisabled, last]);

  // focus into popover when ready
  React.useEffect(() => {
    if (ready && popRef.current) {
      const btn = popRef.current.querySelector("[data-tour-primary]");
      btn && btn.focus({ preventScroll: true });
    }
  }, [ready, index]);

  const trans = reduced ? "none" : undefined;

  // scrim clip-path: full rect minus a hole around the target
  const scrimStyle = { position: "fixed", inset: 0, zIndex: 90, background: SCRIM };
  if (ready && hole) {
    const vw = window.innerWidth, vh = window.innerHeight;
    const hx = hole.left - PAD, hy = hole.top - PAD, hw = hole.width + PAD * 2, hh = hole.height + PAD * 2;
    scrimStyle.clipPath = `path(evenodd, "M0 0 H${vw} V${vh} H0 Z M${hx} ${hy} H${hx + hw} V${hy + hh} H${hx} Z")`;
    scrimStyle.WebkitClipPath = scrimStyle.clipPath;
    if (!reduced) scrimStyle.transition = "clip-path 240ms var(--ease-out)";
  }

  return (
    <div aria-live="polite">
      {/* scrim (dims + blocks clicks; hole passes through to target) */}
      <div style={scrimStyle} onClick={(e) => e.stopPropagation()} />

      {/* focus ring on the spotlighted element */}
      {ready && hole ? (
        <div aria-hidden="true" style={{
          position: "fixed", left: hole.left - PAD, top: hole.top - PAD,
          width: hole.width + PAD * 2, height: hole.height + PAD * 2,
          border: "2px solid var(--brand)", borderRadius: "var(--radius)",
          boxShadow: "0 0 0 4px var(--brand-fill)", pointerEvents: "none", zIndex: 91,
          transition: reduced ? "none" : "all 240ms var(--ease-out)",
        }} />
      ) : null}

      {/* popover (or shimmer while target mounts) */}
      <div ref={popRef} role="dialog" aria-modal="false" aria-labelledby="cor-tour-title"
        style={{
          position: "fixed", zIndex: 93, width: pos && pos.mobile ? "auto" : 320, maxWidth: "calc(100vw - 24px)",
          left: pos && !pos.mobile ? pos.left : (pos && pos.mobile ? 12 : "50%"),
          right: pos && pos.mobile ? 12 : "auto",
          top: pos && !pos.mobile ? pos.top : "auto",
          bottom: pos && pos.mobile ? 12 : "auto",
          transform: pos ? "none" : "translate(-50%, -50%)",
          background: "var(--surface-card)", border: "1px solid var(--hairline)",
          borderRadius: "var(--radius)", boxShadow: "0 8px 28px hsl(230 24% 12% / 0.12)",
          padding: 16, opacity: ready && pos ? 1 : (ready ? 0 : 1),
          transition: reduced ? "none" : "opacity 160ms var(--ease-out), top 200ms var(--ease-out), left 200ms var(--ease-out)",
        }}>
        {/* arrow beak */}
        {ready && pos && !pos.mobile && pos.arrow ? (
          <span aria-hidden="true" style={beakStyle(pos)} />
        ) : null}

        {!ready ? (
          <Shimmer />
        ) : (
          <React.Fragment>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-muted)", textTransform: "lowercase", letterSpacing: "0.02em" }}>
                step {index + 1} / {window.TOUR_STEPS.length}
              </span>
              <button onClick={onSkip} style={skipStyle}>Skip tour</button>
            </div>
            <h2 id="cor-tour-title" style={{ margin: "8px 0 0", fontSize: 15, fontWeight: 600, lineHeight: 1.3, letterSpacing: "-0.01em", color: "var(--text-strong)", textWrap: "pretty" }}>{step.title}</h2>
            <p id="cor-tour-body" style={{ margin: "6px 0 0", fontSize: 13, lineHeight: 1.5, color: "var(--text-muted)", textWrap: "pretty" }}>{step.body}</p>
            {step.token ? (
              <div style={{ marginTop: 10, fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--text-default)", background: "var(--surface-muted)", border: "1px solid var(--hairline)", borderRadius: "var(--radius-sm)", padding: "5px 8px", display: "inline-block", wordBreak: "break-all" }}>{step.token}</div>
            ) : null}

            {step.cta ? (
              <div style={{ marginTop: 14 }}>
                <Button size="sm" as="a" href="#" data-tour-primary onClick={(e) => { e.preventDefault(); onDone(); }} style={{ width: "100%" }}>Meter your own agents →</Button>
              </div>
            ) : null}

            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: 16 }}>
              <div style={{ display: "flex", gap: 5 }} aria-hidden="true">
                {window.TOUR_STEPS.map((_, i) => (
                  <span key={i} style={{ width: i === index ? 16 : 6, height: 6, borderRadius: 3, background: i === index ? "var(--brand)" : "var(--hairline)", transition: trans || "all 200ms var(--ease-out)" }} />
                ))}
              </div>
              <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
                {index > 0 ? <Button variant="ghost" size="sm" onClick={onBack}>Back</Button> : null}
                {step.cta ? null : (
                  <Button size="sm" data-tour-primary onClick={last ? onDone : onNext} disabled={nextDisabled}>
                    {last ? "Done" : "Next"}
                  </Button>
                )}
              </div>
            </div>
            {nextDisabled ? (
              <p style={{ margin: "8px 0 0", fontSize: 11.5, color: "var(--text-muted)" }}>Next unlocks when the simulation finishes.</p>
            ) : null}
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

function beakStyle(pos) {
  const s = {
    position: "absolute", width: 12, height: 12, background: "var(--surface-card)",
    borderLeft: "1px solid var(--hairline)", borderTop: "1px solid var(--hairline)",
  };
  if (pos.placement === "bottom") return { ...s, top: -7, left: pos.arrow.off - 6, transform: "rotate(45deg)" };
  if (pos.placement === "top") return { ...s, bottom: -7, left: pos.arrow.off - 6, transform: "rotate(225deg)" };
  if (pos.placement === "right") return { ...s, left: -7, top: pos.arrow.off - 6, transform: "rotate(-45deg)" };
  return { ...s, right: -7, top: pos.arrow.off - 6, transform: "rotate(135deg)" };
}

const skipStyle = { background: "none", border: "none", padding: 0, cursor: "pointer", fontFamily: "var(--font-sans)", fontSize: 12, color: "var(--text-muted)", textDecoration: "underline", textUnderlineOffset: 3 };

function Shimmer() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
      <style>{`@keyframes cor-shim{0%{background-position:-200px 0}100%{background-position:200px 0}}`}</style>
      {[60, "100%", "85%"].map((w, i) => (
        <div key={i} style={{ height: i === 0 ? 10 : 12, width: w, borderRadius: 4, background: rm() ? "var(--surface-muted)" : "linear-gradient(90deg, var(--surface-muted) 25%, var(--surface-accent) 37%, var(--surface-muted) 63%)", backgroundSize: "400px 100%", animation: rm() ? "none" : "cor-shim 1.2s linear infinite" }} />
      ))}
    </div>
  );
}

// ── First-visit offer card (toast-style, dismissible) ─────────────
function TourOffer({ onStart, onDismiss }) {
  const [show, setShow] = React.useState(false);
  React.useEffect(() => { const t = setTimeout(() => setShow(true), 600); return () => clearTimeout(t); }, []);
  const { Button } = NS_tour;
  return (
    <div role="region" aria-label="Guided tour offer" style={{
      position: "fixed", right: 24, bottom: 24, zIndex: 80, width: 340, maxWidth: "calc(100vw - 32px)",
      background: "var(--surface-card)", border: "1px solid var(--hairline)", borderRadius: "var(--radius)",
      boxShadow: "0 12px 32px hsl(230 24% 12% / 0.14)", padding: 18,
      opacity: show ? 1 : 0, transform: show ? "translateY(0)" : "translateY(12px)",
      transition: rm() ? "none" : "opacity 260ms var(--ease-out), transform 260ms var(--ease-out)",
    }}>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--text-muted)", textTransform: "lowercase", letterSpacing: "0.02em" }}>guided tour</div>
      <h2 style={{ margin: "7px 0 0", fontSize: 15, fontWeight: 600, letterSpacing: "-0.01em", color: "var(--text-strong)", textWrap: "pretty" }}>New here? See how a call becomes money.</h2>
      <p style={{ margin: "5px 0 0", fontSize: 13, lineHeight: 1.5, color: "var(--text-muted)" }}>~90 seconds. Synthetic data — nothing here is real.</p>
      <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
        <Button size="sm" onClick={onStart}>Start tour</Button>
        <Button variant="ghost" size="sm" onClick={onDismiss}>No thanks</Button>
      </div>
    </div>
  );
}

// ── Persistent top-bar affordance ─────────────────────────────────
function TourButton({ onStart }) {
  return (
    <button onClick={onStart} style={{
      display: "inline-flex", alignItems: "center", gap: 7, height: 36, padding: "0 13px",
      border: "1px solid var(--hairline)", borderRadius: "var(--radius-md)", background: "var(--surface-card)",
      fontFamily: "var(--font-sans)", fontSize: 13, fontWeight: 500, color: "var(--text-strong)", cursor: "pointer",
      transition: "background-color 150ms var(--ease-out)",
    }}
      onMouseEnter={(e) => (e.currentTarget.style.background = "var(--surface-accent)")}
      onMouseLeave={(e) => (e.currentTarget.style.background = "var(--surface-card)")}>
      <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--brand)" }} />
      Take the tour
    </button>
  );
}

Object.assign(window, { Tour, TourOffer, TourButton, TOUR_DISMISS_KEY: DISMISS_KEY });
