// Primate App Kit — Onboarding wizard (matches provided designs, steps 1–5)
const { useState: useStateOB } = React;

const TOTAL = 4;

/* ============================ shared chrome ============================ */
function TopBar({ step, onHome }) {
  return (
    <div style={{ position: "relative", zIndex: 3, display: "flex", alignItems: "center", justifyContent: "space-between", height: 64, padding: "0 28px", flexShrink: 0 }}>
      <button onClick={onHome} title="Back to home" style={{ display: "inline-flex", alignItems: "center", background: "none", border: "none", padding: 0, cursor: onHome ? "pointer" : "default", opacity: 1, transition: "opacity .14s ease" }} onMouseEnter={e => { if (onHome) e.currentTarget.style.opacity = 0.7; }} onMouseLeave={e => e.currentTarget.style.opacity = 1}>
        <Logo size={30} />
      </button>
      <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
        {Array.from({ length: TOTAL }).map((_, i) => (
          <span key={i} style={{
            height: 6, borderRadius: 999, transition: "background-color .25s ease, box-shadow .25s ease",
            width: i === step ? 26 : 6,
            background: i === step ? "var(--gold)" : i < step ? "var(--gold)" : "rgba(235,187,54,0.22)",
            boxShadow: i === step ? "0 0 8px rgba(235,187,54,0.5)" : "none",
          }} />
        ))}
      </div>
      <span style={{ font: "13px var(--font-mono)", color: "var(--fg-faint)" }}>{step + 1}/{TOTAL}</span>
    </div>
  );
}

function NavBtn({ onClick, primary, disabled, children }) {
  const [h, setH] = useStateOB(false);
  const hov = h && !disabled;
  return (
    <button onClick={disabled ? undefined : onClick} disabled={disabled} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
      style={{ font: "var(--t-btn)", height: 48, boxSizing: "border-box", padding: "0 32px", borderRadius: "var(--r-md)", whiteSpace: "nowrap",
        background: primary ? (hov ? "var(--gold-bright)" : "var(--gold)") : (hov ? "var(--bg-elevated-2)" : "var(--bg-elevated)"),
        border: primary ? "1px solid var(--gold)" : "1px solid var(--border-subtle)",
        color: primary ? "var(--on-gold)" : "var(--fg)", cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.4 : 1, transition: "background .14s ease, opacity .14s ease" }}>{children}</button>
  );
}
function NavButtons({ onPrev, onNext, last, align = "center", nextDisabled, hidePrev }) {
  return (
    <div style={{ display: "flex", gap: 16, marginTop: 40, justifyContent: align === "center" ? "center" : "flex-start" }}>
      {!hidePrev && <NavBtn onClick={onPrev}>Previous</NavBtn>}
      <NavBtn onClick={onNext} primary disabled={nextDisabled}>{last ? "Enter Primate" : "Next"}</NavBtn>
    </div>
  );
}

const GlowBG = () => (
  <div style={{ position: "absolute", inset: 0, overflow: "hidden", pointerEvents: "none" }}>
    <div style={{ position: "absolute", left: "-6%", top: "-18%", width: 760, height: 620, background: "radial-gradient(circle at 42% 42%, rgba(193,128,24,0.34), rgba(120,80,8,0.12) 42%, transparent 70%)", transform: "rotate(8deg)" }} />
  </div>
);

/* hanging bananas illustration for split-layout steps (ascii monkey omitted per source) */
function HangingBananas({ bottom = 40, glowCount = 0, animate = false }) {
  // each banana lights up (flickers to the bright SVG) as repos get selected
  const bananas = [
    { left: "18%", drop: "14vh", size: 92, rot: -22 },
    { left: "46%", drop: "22vh", size: 175, rot: -4 },
    { left: "66%", drop: "34vh", size: 84, rot: 20 },
    { left: "84%", drop: "17vh", size: 104, rot: 12 },
  ];
  const litOrder = [1, 3, 0, 2];
  const litSet = new Set(litOrder.slice(0, Math.max(0, Math.min(glowCount, litOrder.length))));
  // distinct breathing speed + phase per banana so each fades at its own rate
  const breath = [
    { dur: 4.3, delay: -1.1 },
    { dur: 7.1, delay: -5.4 },
    { dur: 3.4, delay: -2.7 },
    { dur: 5.8, delay: -0.6 },
  ];
  // subtle scattered stars/dots behind the bananas (white + gold, a few twinkle)
  const stars = [
    { left: "12%", top: "16%", size: 2, gold: false, dur: 4.2 },
    { left: "27%", top: "9%", size: 3, gold: true, dur: 0 },
    { left: "38%", top: "26%", size: 2, gold: false, dur: 5.5 },
    { left: "55%", top: "13%", size: 2.5, gold: true, dur: 3.6 },
    { left: "63%", top: "30%", size: 1.5, gold: false, dur: 0 },
    { left: "74%", top: "10%", size: 2, gold: false, dur: 6.1 },
    { left: "86%", top: "24%", size: 3, gold: true, dur: 4.8 },
    { left: "20%", top: "40%", size: 1.5, gold: true, dur: 0 },
    { left: "48%", top: "44%", size: 2, gold: false, dur: 5.0 },
    { left: "91%", top: "46%", size: 2, gold: false, dur: 3.9 },
    { left: "33%", top: "55%", size: 1.5, gold: true, dur: 4.5 },
    { left: "70%", top: "52%", size: 2.5, gold: false, dur: 0 },
  ];
  return (
    <div style={{ position: "absolute", right: 0, top: 0, bottom: 0, width: "50%", pointerEvents: "none", overflow: "hidden" }}>
      {stars.map((s, i) => {
        const color = s.gold ? "#EBBB36" : "#FFFFFF";
        return (
          <span key={`star-${i}`} style={{
            position: "absolute", left: s.left, top: s.top, width: s.size, height: s.size, borderRadius: "50%",
            background: color, boxShadow: `0 0 ${s.size * 2}px ${s.size * 0.6}px ${s.gold ? "rgba(235,187,54,0.55)" : "rgba(255,255,255,0.5)"}`,
            opacity: s.dur ? undefined : 0.5,
            animation: s.dur ? `starTwinkle ${s.dur}s ease-in-out ${(-i * 0.7).toFixed(1)}s infinite` : undefined,
          }} />
        );
      })}
      {bananas.map((b, i) => {
        const lit = litSet.has(i);
        const wrapTransform = `translateX(-17%) rotate(${b.rot}deg)`;
        return (
          <div key={i} style={{ position: "absolute", left: b.left, top: 0, transform: "translateX(-50%)", display: "flex", flexDirection: "column", alignItems: "center" }}>
            <div style={{ width: 1, height: b.drop, background: "linear-gradient(180deg, transparent, rgba(235,187,54,0.3))" }} />
            {animate ? (
              <div style={{ position: "relative", width: b.size, marginTop: -3, transformOrigin: "67% 0%", transform: wrapTransform }}>
                <img src="assets/banana.svg" width={b.size} style={{ display: "block", filter: "drop-shadow(0 6px 14px rgba(0,0,0,0.55))" }} />
                <img src="assets/banana-glow.svg" width={b.size} style={{ position: "absolute", left: 0, top: 0, display: "block", willChange: "opacity", animation: `bananaBreathe ${breath[i].dur}s ease-in-out ${breath[i].delay}s infinite` }} />
              </div>
            ) : (
              <img key={`${i}-${lit ? "lit" : "dim"}`} className={lit ? "banana-flicker" : undefined} src={lit ? "assets/banana-glow.svg" : "assets/banana.svg"} width={b.size} style={{ display: "block", marginTop: -3, transformOrigin: "67% 0%", transform: wrapTransform, filter: lit ? "none" : "drop-shadow(0 6px 14px rgba(0,0,0,0.55))", opacity: lit ? 1 : 0.95 }} />
            )}
          </div>
        );
      })}
      {/* orangutan standing on a glowing gradient line */}
      <div style={{ position: "absolute", left: 0, right: 0, bottom: bottom, display: "flex", justifyContent: "center" }}>
        <div style={{ position: "absolute", left: "20%", right: "20%", bottom: 0, height: 4, background: "linear-gradient(90deg, rgba(242,201,76,0) 0%, #F2C94C 50%, rgba(242,201,76,0) 100%)" }} />
        <img src="assets/monkey.webp" style={{ position: "relative", height: 380, display: "block", marginBottom: -41, filter: "drop-shadow(0 18px 26px rgba(0,0,0,0.5))" }} />
      </div>
    </div>
  );
}

/* ============================ form atoms ============================ */
function L({ children, req }) {
  return <label style={{ font: "var(--t-label)", fontWeight: 400, color: "var(--fg)", display: "block", marginBottom: 8 }}>{children}{req && <span style={{ color: "var(--danger)", marginLeft: 4 }}>*</span>}</label>;
}
function Inp({ placeholder }) {
  const [f, setF] = useStateOB(false);
  const [h, setH] = useStateOB(false);
  return <input placeholder={placeholder} onFocus={() => setF(true)} onBlur={() => setF(false)} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
    style={{ width: "100%", boxSizing: "border-box", height: 48, padding: "0 16px", borderRadius: "var(--r-md)", background: "var(--bg-elevated)", border: `1px solid ${f ? "var(--gold-mid)" : h ? "var(--border-hover)" : "var(--border-subtle)"}`, color: "var(--fg)", font: "var(--t-body)", outline: "none", transition: "border-color .14s ease" }} />;
}
function Sel({ placeholder, options = [] }) {
  const [open, setOpen] = useStateOB(false);
  const [val, setVal] = useStateOB("");
  const [h, setH] = useStateOB(false);
  return (
    <div style={{ position: "relative" }}>
      <button onClick={() => setOpen(o => !o)} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} style={{ width: "100%", boxSizing: "border-box", height: 48, padding: "0 16px", borderRadius: "var(--r-md)", background: "var(--bg-elevated)", border: `1px solid ${open ? "var(--gold-mid)" : h ? "var(--border-hover)" : "var(--border-subtle)"}`, color: val ? "var(--fg)" : "var(--fg-placeholder)", font: "var(--t-body)", display: "flex", alignItems: "center", justifyContent: "space-between", cursor: "pointer", transition: "border-color .14s ease" }}>
        {val || placeholder}<Icon name="chevron-down" size={18} color="var(--fg-placeholder)" />
      </button>
      {open && (
        <div style={{ position: "absolute", top: 52, left: 0, right: 0, zIndex: 20, background: "var(--bg-elevated)", border: "1px solid var(--border)", borderRadius: "var(--r-md)", padding: 4, boxShadow: "var(--shadow-md)" }}>
          {options.map(o => <div key={o} onClick={() => { setVal(o); setOpen(false); }} style={{ padding: "10px 12px", borderRadius: "var(--r-sm)", font: "var(--t-body-sm)", color: "var(--fg-secondary)", cursor: "pointer" }} onMouseEnter={e => e.currentTarget.style.background = "rgba(255,255,255,0.05)"} onMouseLeave={e => e.currentTarget.style.background = "transparent"}>{o}</div>)}
        </div>
      )}
    </div>
  );
}
function CheckBox({ on, square = true }) {
  return (
    <span style={{ width: 20, height: 20, borderRadius: square ? 6 : "50%", flexShrink: 0, background: on ? "var(--gold)" : "transparent", border: `1px solid ${on ? "var(--gold)" : "#52525B"}`, display: "flex", alignItems: "center", justifyContent: "center", transition: "all .12s ease" }}>
      {on && <Icon name="check" size={13} color="var(--on-gold)" />}
    </span>
  );
}

/* ============================ steps ============================ */
function StepProfile() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 22 }}>
      <div><L req>Full Name</L><Inp placeholder="John Doe" /></div>
      <div><L req>Organization Name</L><Inp placeholder="Example Org" /></div>
      <div><L>Organization Website</L><Inp placeholder="example.com" /></div>
      <div><L>Company Size</L><Sel placeholder="Select a size" options={["1–10", "11–50", "51–200", "201–1,000", "1,000+"]} /></div>
    </div>
  );
}

function StepConnect({ onNext }) {
  const [h, setH] = useStateOB(false);
  return (
    <div style={{ display: "flex", justifyContent: "center" }}>
      <button onClick={onNext} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} className="grad-border-gold"
        style={{ display: "flex", width: "100%", height: 48, boxSizing: "border-box", justifyContent: "center", alignItems: "center", gap: 12, padding: "0 40px", borderRadius: "var(--r-md)", background: h ? "#211F1D" : "#191918", color: "var(--fg)", font: "var(--t-btn)", fontWeight: 700, cursor: "pointer", transition: "background .12s ease", whiteSpace: "nowrap" }}>
        <img src="assets/github-mark.svg" width="20" height="20" />Authorize GitHub
      </button>
    </div>
  );
}

const REPOS = ["jeremybell232/taskflow", "jeremybell232/notably", "jeremybell232/pagemint", "jeremybell232/loopmail"];

function RepoTable({ indexing, selected, onToggle }) {
  const [localOn, setLocalOn] = useStateOB({ 1: true, 3: true });
  const rawOn = selected || localOn;
  const setOn = onToggle || setLocalOn;
  let on = rawOn;
  let count = Object.values(on).filter(Boolean).length;
  // indexing opened with nothing selected → still show one repo indexing by default
  if (indexing && count === 0) { on = { 1: true }; count = 1; }
  const fillGrad = "linear-gradient(90deg, rgba(235,187,54,0.03) 0%, rgba(235,187,54,0.05) 50%, rgba(235,187,54,0.03) 100%)";
  const goldLine = "linear-gradient(90deg, rgba(235,187,54,0.20) 0%, rgba(235,187,54,0.40) 50%, rgba(235,187,54,0.10) 100%)";
  const tableFill = "linear-gradient(180deg, #27272A 0%, #191918 100%)";
  const [hSearch, setHSearch] = useStateOB(false);
  return (
    <div style={{ width: "100%", maxWidth: 512, boxSizing: "border-box", borderRadius: "var(--r-md)", border: "1px solid var(--border)", background: "transparent", padding: 14, display: "flex", flexDirection: "column", gap: 12 }}>
      <div onMouseEnter={() => setHSearch(true)} onMouseLeave={() => setHSearch(false)} style={{ display: "flex", alignItems: "center", gap: 10, height: 36, padding: "0 14px", borderRadius: "var(--r-sm)", background: "var(--bg-elevated)", border: `1px solid ${hSearch ? "var(--border-hover)" : "var(--border-subtle)"}`, transition: "border-color .14s ease" }}>
        <Icon name="search" size={16} color="var(--fg-placeholder)" />
        <input placeholder="Search repository" style={{ flex: 1, background: "transparent", border: "none", outline: "none", color: "var(--fg)", font: "var(--t-body-sm)" }} />
      </div>
      <div style={{ borderRadius: "var(--r-md)", border: "1px solid var(--border)", background: tableFill, overflow: "hidden" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 18px", borderBottom: `1px solid ${on[0] ? "transparent" : "var(--border)"}` }}>
          {!indexing && <CheckBox on={count === REPOS.length} />}<span style={{ font: "var(--t-label)", color: "var(--fg-secondary)" }}>Name</span>
        </div>
        {REPOS.map((r, i) => {
          const sel = !!on[i];
          // every selected row draws its TOP edge; only the last of a run draws a
          // bottom edge. This keeps each inter-row separator owned by the lower row,
          // so selecting a repo above an already-selected one doesn't shift the line.
          const topLine = sel;
          const botLine = sel && !on[i + 1];
          const rowBg = sel
            ? [topLine && `${goldLine} left top / 100% 1px no-repeat`, botLine && `${goldLine} left bottom / 100% 1px no-repeat`, fillGrad].filter(Boolean).join(", ")
            : "transparent";
          return (
            <div key={r} onClick={indexing ? undefined : () => setOn(s => ({ ...s, [i]: !s[i] }))}
              onMouseEnter={indexing ? undefined : e => { if (!on[i]) e.currentTarget.style.background = "rgba(255,255,255,0.03)"; }}
              onMouseLeave={indexing ? undefined : e => { if (!on[i]) e.currentTarget.style.background = "transparent"; }}
              style={{ display: "flex", alignItems: "center", gap: 12, height: 45, boxSizing: "border-box", padding: "0 18px", cursor: indexing ? "default" : "pointer", transition: "background .1s ease",
                borderBottom: `1px solid ${sel ? "transparent" : (i < REPOS.length - 1 && !on[i + 1]) ? "var(--border)" : "transparent"}`,
                background: rowBg }}>
              {!indexing && <CheckBox on={!!on[i]} />}
              <img src="assets/github-mark.svg" width="18" height="18" style={{ flexShrink: 0 }} />
              <span style={{ font: "var(--t-body-sm)", color: "var(--fg)", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{r}</span>
              {indexing && on[i] && (
                <span style={{ flexShrink: 0, display: "inline-flex", alignItems: "center", gap: 6, padding: "4px 10px", borderRadius: "var(--r-pill)", border: "1px solid var(--gold-mid)", background: "rgba(235,187,54,0.08)", color: "var(--gold)", font: "var(--t-badge)" }}>
                  <span className="ob-spin" style={{ display: "inline-flex" }}><Icon name="loader-circle" size={12} color="var(--gold)" /></span>Indexing
                </span>
              )}
            </div>
          );
        })}
      </div>
      <div style={{ font: "var(--t-caption)", color: "var(--fg-faint)" }}>{count} of {REPOS.length} selected</div>
    </div>
  );
}

const STEPS = [
  { layout: "center", title: "Create Your Profile", sub: "Just a few details to get you in.", body: StepProfile, w: 530 },
  { layout: "center", title: "Connect to GitHub", sub: "Authorize Primate to run checks on your Pull Requests.", body: StepConnect, w: 420, navBottom: true },
  { layout: "split", title: "Select Repositories", sub: "Choose which repositories you'd like to enable for code review.", body: (p) => <RepoTable {...p} />, w: 512, requireRepo: true },
  { layout: "split", title: "Primate is indexing your repository.", sub: "Before reviewing your code, Primate builds a full node graph of your repo. This step takes a little time, but ensures every PR review is thorough and context-aware.", body: (p) => <RepoTable indexing {...p} />, w: 512, indexing: true },
];

function Onboarding({ onDone, onBack, onHome, initialStep = 0, onStepChange }) {
  const [step, setStep] = useStateOB(initialStep);
  const vp = useViewport();
  const compact = vp !== "desktop";
  const mobile = vp === "mobile";
  const tablet = vp === "tablet";
  React.useEffect(() => { if (onStepChange) onStepChange(step); }, [step]);
  const cfg = STEPS[step];
  const Body = cfg.body;
  const last = step === TOTAL - 1;
  const prev = () => step === 0 ? (onBack ? onBack() : onDone()) : setStep(s => s - 1);
  const next = () => last ? onDone() : setStep(s => s + 1);

  // repo selection is lifted here so the hanging bananas can light up to match
  const [repoSel, setRepoSel] = useStateOB({});
  const repoCount = Object.values(repoSel).filter(Boolean).length;

  // keep the monkey's platform line aligned to the bottom of the nav buttons
  const splitRef = React.useRef(null);
  const navRef = React.useRef(null);
  const [monkeyBottom, setMonkeyBottom] = useStateOB(60);
  React.useLayoutEffect(() => {
    function measure() {
      if (splitRef.current && navRef.current) {
        const sb = splitRef.current.getBoundingClientRect().bottom;
        const nb = navRef.current.getBoundingClientRect().bottom;
        setMonkeyBottom(Math.max(8, sb - nb));
      }
    }
    measure();
    window.addEventListener("resize", measure);
    return () => window.removeEventListener("resize", measure);
  }, [step]);

  return (
    <div style={{ position: "relative", height: "100%", display: "flex", flexDirection: "column", background: "var(--bg)", overflow: "hidden" }}>
      <GlowBG />
      <TopBar step={step} onHome={onHome} />

      {cfg.layout === "center" ? (
        <div style={{ position: "relative", zIndex: 2, flex: 1, overflowY: "auto", display: "flex", justifyContent: "center", padding: "11vh 24px 48px" }}>
          <div style={{ width: "100%", maxWidth: cfg.w, display: "flex", flexDirection: "column", alignItems: "center" }}>
            <div style={{ textAlign: "center", marginBottom: 40 }}>
              <h1 style={{ font: `600 ${mobile ? 24 : 28}px/1.2 var(--font-sans)`, color: "var(--fg)", margin: 0 }}>{cfg.title}</h1>
              <p style={{ font: "var(--t-body)", color: "var(--fg-secondary)", margin: "10px 0 0" }}>{cfg.sub}</p>
            </div>
            <div style={{ width: "100%" }}><Body onNext={next} /></div>
            {!cfg.navBottom && <NavButtons onPrev={prev} onNext={next} last={last} align="center" hidePrev={step === 0} />}
          </div>
        </div>
      ) : (
        <div ref={splitRef} style={{ position: "relative", zIndex: 2, flex: 1, overflow: "hidden" }}>
          {!compact && <HangingBananas bottom={monkeyBottom} glowCount={repoCount} animate={cfg.indexing} />}
          <div style={{ position: "relative", zIndex: 2, height: "100%", boxSizing: "border-box", overflowY: "auto", display: "flex", flexDirection: "column", justifyContent: compact ? "flex-start" : "center", margin: tablet ? "0 auto" : 0, padding: mobile ? "28px clamp(20px, 6vw, 40px) 40px" : tablet ? "32px 14px 40px" : "0 clamp(40px, 9%, 150px)", maxWidth: mobile ? "100%" : tablet ? 540 : 760 }}>
            <h1 style={{ font: `600 ${mobile ? 24 : 28}px/1.2 var(--font-sans)`, color: "var(--fg)", margin: 0 }}>{cfg.title}</h1>
            <p style={{ font: "var(--t-body)", color: "var(--fg-secondary)", margin: "10px 0 32px", maxWidth: 460 }}>{cfg.sub}</p>
            <Body selected={repoSel} onToggle={setRepoSel} />
            <div ref={navRef} style={{ display: "inline-flex" }}>
              <NavButtons onPrev={prev} onNext={next} last={last} align="left" nextDisabled={cfg.requireRepo && repoCount === 0} />
            </div>
          </div>
        </div>
      )}

      {cfg.navBottom && (
        <div style={{ position: "relative", zIndex: 2, flexShrink: 0, padding: "20px 24px 40px", display: "flex", justifyContent: "center" }}>
          <NavBtn onClick={prev}>Previous</NavBtn>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { Onboarding });
