// src/variants/main/app.jsx — assembles the main cut of the funnel
const { useState: useStateNA, useEffect: useEffectNA, useCallback: useCallbackNA } = React;

const TWEAK_DEFAULTS_N = /*EDITMODE-BEGIN*/{
  "killerReveal": "odometer",
  "calculator": "network",
  "close": "fomo",
  "verifyOutcome": "success",
  "countdownDays": 7,
  "codesClaimed": 800,
  "videoGateMins": 8
}/*EDITMODE-END*/;

const STEPS_N = [
  { id: "gate", label: "Gate", C: GateStep, noBack: true },
  { id: "welcome", label: "Welcome", C: WelcomeStepN },
  { id: "role", label: "Q · Role", C: RoleStepN },
  { id: "contact", label: "Contact", C: ContactStep },
  { id: "venue", label: "Q · Venue", C: VenueStepN },
  { id: "killer", label: "Killer question", C: KillerQuestionStepN },
  { id: "reveal", label: "Reveal", C: RevealStep },
  { id: "chart", label: "Token chart", C: ChartRevealStep },
  { id: "dex", label: "DEX volume", C: DexVolumeStep },
  { id: "perps", label: "Perp gap", C: PerpGapStep },
  { id: "xguess", label: "Q · Multiplier", C: XGuessStep },
  { id: "xreveal", label: "Multiplier reveal", C: XRevealStep },
  { id: "opportunity", label: "Opportunity", C: OpportunityStep },
  { id: "solution", label: "Solution", C: SolutionStepN },
  { id: "symmio", label: "Proven engine", C: SymmioProofStep },
  { id: "demo", label: "Demo", C: DemoStep },
  { id: "referral", label: "Referral model", C: ReferralStep },
  { id: "volume", label: "Q · Volume", C: VolumeAskStep },
  { id: "calculator", label: "Calculator", C: CalculatorStep },
  { id: "proof", label: "Proof", C: ProofStepN },
  { id: "testimonials", label: "Testimonials", C: TestimonialsStep },
  { id: "close", label: "Close", C: CloseStepN },
  { id: "registered", label: "Registered ✓", C: RegisteredStep },
  { id: "bonushub", label: "Bonus tasks", C: BonusHubStep },
  { id: "bonusvideo", label: "Bonus video", C: VideoBonusStep },
  { id: "videoquiz", label: "Video quiz", C: VideoQuizStep },
  { id: "referralprogram", label: "Referral program", C: ReferralProgramStep },
];

const STORE_KEY_N = "vibe-pitch-main-state-v1";

// ?page=N is admin-only. Public users should never get URL pagination.
function pageFromURL() {
  const p = parseInt(new URLSearchParams(window.location.search).get("page"), 10);
  if (isNaN(p)) return null;
  return Math.min(STEPS_N.length - 1, Math.max(0, p - 1));
}

// ?step=<id> is public: anyone can deep-link to a specific step (e.g. the
// dashboard's "Watch the explainer" → ?step=bonusvideo). Accepts a STEPS_N id
// or a 0-based numeric index. Consumed once by loadStateN(), then stripped.
function publicStepFromURL() {
  const raw = new URLSearchParams(window.location.search).get("step");
  if (raw === null || raw === "") return null;
  const byId = STEPS_N.findIndex((s) => s.id === raw);
  if (byId !== -1) return byId;
  const n = parseInt(raw, 10);
  if (isNaN(n)) return null;
  return Math.min(STEPS_N.length - 1, Math.max(0, n));
}

function stripAdminURLParamsN() {
  const url = new URL(window.location.href);
  url.searchParams.delete("page");
  url.searchParams.delete("admin");
  url.searchParams.delete("step");
  try { window.history.replaceState({}, "", url); } catch (e) { /* sandboxed */ }
}

// Top-right "Log in" → user dashboard. With saved dashboard creds (written by
// the Close step at first verification) the link auto-logs-in via the #key
// fragment; without creds it lands on the dashboard's login screen.
function dashboardHrefN() {
  let creds = null;
  try { creds = JSON.parse(localStorage.getItem("vibe-dash-cred-v1") || "null"); } catch (e) { /* ignore */ }
  // Relative link: dashboard.html sits next to index.html in every
  // deployment, so same-origin always works (the server-minted absolute
  // dashboardUrl points at Pages and 404s on localhost).
  if (creds && creds.dashKey) {
    return "dashboard.html#key=" + encodeURIComponent(creds.dashKey) +
      "&account=" + encodeURIComponent(creds.refHandle || creds.account || "");
  }
  return "dashboard.html";
}

function loadStateN() {
  let saved = { step: 0, answers: {} };
  try {
    const raw = localStorage.getItem(STORE_KEY_N);
    if (raw) {
      const s = JSON.parse(raw);
      if (typeof s.step === "number" && s.step >= 0 && s.step < STEPS_N.length) saved = s;
    }
  } catch (e) { /* fresh start */ }
  // A public ?step=<id> deep-link overrides the resumed step (saved answers
  // are kept), so a user who already finished the funnel still lands on the
  // requested step rather than resuming at the end.
  const deepStep = publicStepFromURL();
  if (deepStep !== null) saved = { ...saved, step: deepStep };
  return saved;
}

function PitchAppMain() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS_N);
  const [state, setState] = useStateNA(loadStateN);
  const [dir, setDir] = useStateNA("fwd");
  const [adminMode, setAdminMode] = useStateNA(false);
  const [adminRequested, setAdminRequested] = useStateNA(false);
  const [adminKey, setAdminKey] = useStateNA("");
  const [adminBusy, setAdminBusy] = useStateNA(false);
  const [adminError, setAdminError] = useStateNA("");
  const { step, answers } = state;

  useEffectNA(() => {
    localStorage.setItem(STORE_KEY_N, JSON.stringify(state));
    if (window.track) track.sync({ stepId: STEPS_N[state.step].id, stepIndex: state.step, answers: state.answers });
  }, [state]);

  // Repaint when the server copy overrides arrive after first render
  const [, setCopyTick] = useStateNA(0);
  useEffectNA(() => {
    const onCopy = () => setCopyTick((t) => t + 1);
    window.addEventListener("vibe-copy-loaded", onCopy);
    return () => window.removeEventListener("vibe-copy-loaded", onCopy);
  }, []);

  useEffectNA(() => {
    const params = new URLSearchParams(window.location.search);
    // ?step was already consumed by loadStateN() during first render; clear it
    // now (for everyone) so a later refresh resumes from saved progress.
    if (params.get("admin") !== "1") {
      if (params.has("page") || params.has("step")) stripAdminURLParamsN();
      return;
    }
    if (params.has("step")) {
      const url = new URL(window.location.href);
      url.searchParams.delete("step");
      try { window.history.replaceState({}, "", url); } catch (e) { /* sandboxed */ }
    }
    setAdminRequested(true);
  }, []);

  const submitAdmin = useCallbackNA(async (e) => {
    if (e) e.preventDefault();
    const key = adminKey.trim();
    const api = (window.VIBE_ACCESS_API || "").replace(/\/$/, "");
    if (!api || !key) return;
    setAdminBusy(true);
    setAdminError("");
    try {
      const res = await fetch(api + "/admin/api/ping", { headers: { Authorization: "Bearer " + key } });
      if (!res.ok) throw new Error("bad admin key");
      setAdminMode(true);
      setAdminRequested(false);
      setAdminKey("");
      window.postMessage({ type: "__activate_edit_mode" }, "*");
      const urlStep = pageFromURL();
      if (urlStep !== null) setState((s) => ({ ...s, step: urlStep }));
    } catch (err) {
      setAdminError("Wrong admin password.");
    } finally {
      setAdminBusy(false);
    }
  }, [adminKey]);

  const cancelAdmin = useCallbackNA(() => {
    setAdminRequested(false);
    setAdminKey("");
    setAdminError("");
    stripAdminURLParamsN();
  }, []);

  // Keep ?page=N in the URL in sync with the current step, admin-only.
  useEffectNA(() => {
    if (!adminMode) {
      const url = new URL(window.location.href);
      if (url.searchParams.has("page")) {
        url.searchParams.delete("page");
        try { window.history.replaceState({ step }, "", url); } catch (e) { /* sandboxed */ }
      }
      return;
    }
    const url = new URL(window.location.href);
    const cur = parseInt(url.searchParams.get("page"), 10);
    if (cur === step + 1) return;
    url.searchParams.set("page", String(step + 1));
    try { window.history.pushState({ step }, "", url); } catch (e) { /* sandboxed */ }
  }, [step, adminMode]);

  // Browser back / forward navigates the funnel in admin mode only.
  useEffectNA(() => {
    const onPop = () => {
      if (!adminMode) return;
      const urlStep = pageFromURL();
      if (urlStep === null) return;
      setState((s) => {
        if (s.step === urlStep) return s;
        setDir(urlStep < s.step ? "back" : "fwd");
        return { ...s, step: urlStep };
      });
    };
    window.addEventListener("popstate", onPop);
    return () => window.removeEventListener("popstate", onPop);
  }, [adminMode]);

  const setAnswer = useCallbackNA((key, val) => {
    setState((s) => ({ ...s, answers: { ...s.answers, [key]: val } }));
  }, []);

  const next = useCallbackNA(() => {
    setDir("fwd");
    setState((s) => ({ ...s, step: Math.min(STEPS_N.length - 1, s.step + 1) }));
  }, []);

  const back = useCallbackNA(() => {
    setDir("back");
    setState((s) => ({ ...s, step: Math.max(0, s.step - 1) }));
  }, []);

  // Global Enter advances by clicking the visible primary action
  useEffectNA(() => {
    const onKey = (e) => {
      if (e.key !== "Enter" || e.shiftKey || e.metaKey || e.ctrlKey) return;
      const tag = (document.activeElement || {}).tagName;
      if (tag === "TEXTAREA") return;
      const btn = document.querySelector("[data-primary]:not(:disabled)");
      if (btn && tag !== "INPUT") { e.preventDefault(); btn.click(); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const cur = STEPS_N[step];
  const progress = (step / (STEPS_N.length - 1)) * 100;
  const hideChromeLogin = cur.id === "demo" || cur.id === "bonusvideo";
  const restart = () => {
    setDir("back");
    setState({ step: 0, answers: {} });
  };

  return (
    <div className="stage">
      <div className="progress-rail"><div className="progress-fill" style={{ width: progress + "%" }}></div></div>
      <div className="chrome-top">
        <div className="wordmark"><img className="wordmark-img" src="assets/vibe-fontLogo-square.svg" alt="Vibe" /></div>
        <div className="chrome-right">
          <div className="chrome-step-count">{step + 1} / {STEPS_N.length}</div>
          {!hideChromeLogin && <a className="chrome-login" href={dashboardHrefN()}>Log in →</a>}
        </div>
      </div>
      <div className="step-scroll">
        <div className={"step" + (dir === "back" ? " going-back" : "")} key={cur.id} data-screen-label={cur.label}>
          <cur.C answers={answers} setAnswer={setAnswer} next={next} back={back} tweaks={tweaks} adminMode={adminMode} />
        </div>
      </div>
      <div className="action-bar">
        <div className="action-left">
          <button className="btn ghost back-btn" type="button" disabled={step === 0} onClick={back}>← Back</button>
          <div className="enter-hint">press <kbd>Enter ↵</kbd> to continue</div>
        </div>
        {adminMode &&
        <div className="nav-arrows">
            <button className="nav-arrow" type="button" title="Back" disabled={step === 0} onClick={back}>↑</button>
            <button className="nav-arrow" type="button" title="Forward" disabled={step === STEPS_N.length - 1} onClick={next}>↓</button>
          </div>
        }
      </div>

      {adminRequested && !adminMode &&
      ReactDOM.createPortal(
        <div className="admin-login">
          <form className="admin-login-box" onSubmit={submitAdmin}>
            <div className="admin-login-kicker">Team only</div>
            <div className="admin-login-title">Admin mode</div>
            <p className="admin-login-sub">Enter the admin key to unlock step navigation and edit mode.</p>
            <input
            className="admin-login-input"
            type="password"
            placeholder="Admin key"
            value={adminKey}
            autoFocus
            autoComplete="off"
            spellCheck={false}
            onChange={(e) => setAdminKey(e.target.value)} />
            {adminError && <div className="admin-login-error">{adminError}</div>}
            <div className="admin-login-actions">
              <button className="btn pink" type="submit" disabled={!adminKey.trim() || adminBusy}>{adminBusy ? "Checking…" : "Unlock admin →"}</button>
              <button className="btn ghost" type="button" onClick={cancelAdmin}>Cancel</button>
            </div>
          </form>
        </div>,
        document.body
      )}

      <TweaksPanel>
        <TweakSection label="Key screen variants" />
        <TweakRadio label="Killer reveal" value={tweaks.killerReveal}
          options={["odometer", "scale"]}
          onChange={(v) => setTweak("killerReveal", v)} />
        <TweakRadio label="Calculator" value={tweaks.calculator}
          options={["simple", "network"]}
          onChange={(v) => setTweak("calculator", v)} />
        <TweakRadio label="Close style" value={tweaks.close}
          options={["fomo", "classy"]}
          onChange={(v) => setTweak("close", v)} />
        <TweakRadio label="Verify outcome" value={tweaks.verifyOutcome}
          options={["success", "error"]}
          onChange={(v) => setTweak("verifyOutcome", v)} />
        <TweakSection label="FOMO dials" />
        <TweakSlider label="Countdown (days)" value={tweaks.countdownDays} min={1} max={14} step={1}
          onChange={(v) => setTweak("countdownDays", v)} />
        <TweakSlider label="Codes claimed" value={tweaks.codesClaimed} min={400} max={985} step={5}
          onChange={(v) => setTweak("codesClaimed", v)} />
        <TweakSlider label="Video gate (minutes)" value={tweaks.videoGateMins} min={0} max={8} step={1}
          onChange={(v) => setTweak("videoGateMins", v)} />
        <TweakSection label="Demo" />
        <TweakButton label="Restart funnel" onClick={restart} />
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<PitchAppMain />);
