/* global React, ReactDOM, window */
/* Sales demo — the Sales Flow home/designing/intake screens running live inside
   one product shell, wired through to studies and results. */
const { useState: sfS, useEffect: sfE } = React;

const SF_NAV = [
  { id: "home", icon: "home", label: "Home" },
  { id: "studies", icon: "clipboard-list", label: "Studies" },
  { id: "assets", icon: "shirt", label: "Assets" },
  { id: "library", icon: "books", label: "Library" }
];

const SF_TIERS = {
  quick: { label: "Gut check", meta: "~30 minutes · Digital Twins", sample: "300 twins · UK, FR, DE", audience: "300 total · 300 Twins, 0 humans", lands: "today" },
  standard: { label: "Decision support", meta: "48 hours · Twins, then real shoppers", sample: "1,240 shoppers · UK, FR, DE", audience: "1,240 total · 600 Twins, 640 humans", lands: "in 48 hours" },
  extended: { label: "Defensible research", meta: "5 days · full consumer panel", sample: "2,000 shoppers · UK, FR, DE, US", audience: "2,000 total · 400 Twins, 1,600 humans", lands: "in 5 days" }
};

const SEED = [{
  id: "demo-study",
  name: "Women's Apparel — Spring '28 range read",
  owner: "Dan Leahy",
  updated: "Today · 2 hrs ago",
  mins: 120,
  status: "Live",
  responses: 1240,
  profiles: 3,
  badge: "mint",
  cas: ["ca-age", "ca-gender", "ca-activity"]
}];

const SF_TWEAKS = /*EDITMODE-BEGIN*/{
  "designSeconds": 9,
  "publishSeconds": 1.2
}/*EDITMODE-END*/;

function SFResults() {
  if (!window.ApparelInsights) return <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", color: "#636c79", fontSize: 13 }}>Loading results…</div>;
  return (
    <div className="gl-page od-embed" style={{ flex: 1, minHeight: 0 }}>
      <div className="pf-app"><div className="gl-appbody">
        <window.ApparelInsights viewMode="client" claimDivider={false} confMode="badge" railMode="none" confAlways />
      </div></div>
    </div>
  );
}

/* The publish confirmation used to be a 492px modal over the intake screen.
   It is now the "review" route — window.StudyCheckout — because Dan asked for
   the approach to be something the user explicitly sees and chooses rather than
   something that happens in the background, and a modal you dismiss is the
   background. Two confirm gates back to back would be one too many, so the
   dialog went with it; the .sf-dlg styles stay for anything else that needs them. */

function SFLanded({ tier, name, opt, onGo }) {
  const t = SF_TIERS[tier] || SF_TIERS.standard;
  /* When the review screen was used, it — not the tier — is the last word on
     what got sent, because the user may have moved off the recommendation
     there. Falling back to the tier copy would tell them they published
     something other than what they just confirmed. */
  const steps = [
    /* opt.name is used as written, not lower-cased. It carries the audience
       method, and "Digital Twins" is a proper noun that stays capitalised
       wherever it is rendered. */
    { k: "live", icon: "broadcast", label: "In field now",
      val: opt ? opt.total.toLocaleString() + " respondents · " + opt.name : t.sample },
    { k: "read", icon: "wave-sine", label: "Surveying", val: opt ? opt.back + " · " + opt.who : t.meta },
    { k: "land", icon: "mail", label: "Delivery", val: "We'll email you when the results are in!" }
  ];
  return (
    <div className="sf-land">
      <div className="sf-land__motes">{Array.from({ length: 9 }).map((_, i) => <span key={i} style={{ "--i": i }}></span>)}</div>
      <div className="sf-land__card">
        <div className="sf-land__seal">
          <svg viewBox="0 0 44 44" aria-hidden="true"><circle className="sf-land__ring" cx="22" cy="22" r="19" /><path className="sf-land__tick" d="M13.5 22.8l5.6 5.4L31 16.4" /></svg>
        </div>
        <div className="sf-land__kicker">It's out the door</div>
        <h2 className="sf-land__h">{name}</h2>
        <div className="sf-land__sub">Nothing left to chase. We'll take it from here and bring back three pages you can put in front of the room.</div>
        <div className="sf-land__steps">
          <span className="sf-land__thread"></span>
          {steps.map((s, i) => (
            <div className="sf-land__step" key={s.k} style={{ "--d": (0.55 + i * 0.16) + "s" }}>
              <span className="sf-land__dot"><i className={"ti ti-" + s.icon}></i></span>
              <b>{s.label}</b><span>{s.val}</span>
            </div>
          ))}
        </div>
        <button className="sf-land__go" onClick={onGo}>See early data<i className="ti ti-arrow-right"></i></button>
      </div>
    </div>
  );
}

/* ---------- shareable links ----------
   The demo is one page, so every link to it used to land on Home and whoever
   you sent it to had to be walked through the clicks to reach what you meant.
   Each screen now writes itself into the address bar, reads one back on load,
   and follows Back/Forward, so the address bar is always the link to hand
   over — copy it out of the browser the way you would any other page.

     #/                      home
     #/studies               the studies list
     #/studies/<id>          that study, on Insights
     #/studies/<id>/<tab>    that study, on intake | insights | results | report
     #/assets                the asset library
     #/library               the question library
     #/new                   the manual study builder

   Hash, not History: these builds are static files behind a single rewrite for
   "/", so /studies/sv-gsc would 404 on a hard refresh. The two in-flight
   screens — designing and review — are deliberately unaddressable: they only
   exist part-way through a submission, and a link that dropped you into one
   would restore the chrome without the answers behind it. */
const SF_ROUTE_PATH = { home: "", studies: "studies", assets: "assets", library: "library", intake: "new" };
const SF_PATH_ROUTE = { "": "home", studies: "studies", assets: "assets", library: "library", "new": "intake" };
const SF_TAB_IDS = ["intake", "insights", "results", "report"];

function sfNormHash(h) {
  return String(h || "").replace(/^#/, "").replace(/^\/+/, "").replace(/\/+$/, "");
}

function sfParseHash(h) {
  const parts = sfNormHash(h).split("?")[0].split("/").filter(Boolean).map(decodeURIComponent);
  if (!parts.length) return { route: "home" };
  if (parts[0] === "studies" && parts[1]) {
    return { route: "study", studyId: parts[1], tab: SF_TAB_IDS.indexOf(parts[2]) >= 0 ? parts[2] : "insights" };
  }
  const r = SF_PATH_ROUTE[parts[0]];
  return { route: r || "home" };
}

/* null means "this screen has no address" — leave whatever is in the bar alone. */
function sfFormatHash(route, study, tab, manual) {
  if (route === "study") return study ? "#/studies/" + encodeURIComponent(study.id) + (tab && tab !== "insights" ? "/" + tab : "") : null;
  if (route === "intake") return manual ? "#/new" : null;
  const p = SF_ROUTE_PATH[route];
  return p == null ? null : (p ? "#/" + p : "#/");
}

/* Studies a link is allowed to name: the seeded rows plus anything published in
   this session. A session study's id is a timestamp, so its link only resolves
   for the person who made it — an unknown id falls back to the list rather than
   to an empty page. */
function sfFindStudy(id, session) {
  const all = [].concat(window.SEED_STUDIES || [], SEED, session || []);
  for (let i = 0; i < all.length; i++) if (all[i] && all[i].id === id) return all[i];
  return null;
}

function SFApp() {
  const [tweaks, setTweak] = window.useTweaks(SF_TWEAKS);
  const [route, setRoute] = sfS("home");
  const [brief, setBrief] = sfS("");
  const [briefFiles, setBriefFiles] = sfS([]);
  const [moment, setMoment] = sfS(null);
  const [tier, setTier] = sfS("standard");
  /* The intake screen owns the decision context; the review screen needs it, so
     it is lifted here on the way through rather than recomputed. `dcAns` is the
     four raw chat answers — the review screen re-runs AT_PLAN on them so its
     numbers and the intake rail's are the same numbers by construction. */
  const [dc, setDc] = sfS(null);
  const [dcAns, setDcAns] = sfS(null);
  /* The country/gender/age the user set on the builder's Audience tab. The
     checkout is now an audience screen too, so it seeds itself from this
     rather than opening a second, subtly different answer to the same
     question. Null until they Check Out; the checkout has its own default. */
  const [aud, setAud] = sfS(null);
  const [busy, setBusy] = sfS(false);
  const [toast, setToast] = sfS(null);
  const [studies, setStudies] = sfS(SEED);
  const [openStudy, setOpenStudy] = sfS(null);
  /* Which tab of the study page is showing. It lives here, not in the page,
     because the address bar names it and a link can arrive already set. */
  const [studyTab, setStudyTab] = sfS("insights");
  const [homeKey, setHomeKey] = sfS(0);
  const [listKey, setListKey] = sfS(0);
  const [manual, setManual] = sfS(false);
  const [landed, setLanded] = sfS(null);
  /* The name follows the moment picked on home, so a Line Adoption demo does
     not open a study called "key account sell-in". It stays editable in the
     crumb; starting a new study is what resets it. */
  const [studyName, setStudyName] = sfS(window.EH.studyFor(null));

  /* The designing beat is a loading state, not a decision point: it advances
     on its timer into the intake screen, where the decision-context questions
     are docked above the composer. */
  sfE(() => {
    if (route !== "designing") return;
    const id = setTimeout(() => setRoute("intake"), Math.max(1, tweaks.designSeconds) * 1000);
    return () => clearTimeout(id);
  }, [route, tweaks.designSeconds]);

  sfE(() => {
    if (!toast) return;
    const id = setTimeout(() => setToast(null), 4500);
    return () => clearTimeout(id);
  }, [toast]);

  /* `tr` only arrives from the Submit Intake modal, where the merchant answered
     "when do you need the results" outright. It seeds the tier so the review
     screen opens on the method that answer implies, exactly as a same-day answer
     in the intake dock does. A composer submission leaves it alone. */
  const start = ({ brief: b, files, moment: mo, tier: tr }) => { setBrief(b); setBriefFiles(files || []); setDc(null); setDcAns(null); setMoment(mo || null); if (tr && SF_TIERS[tr]) setTier(tr); setStudyName(window.EH.studyFor(mo || null)); setManual(false); setRoute("designing"); };
  const goManual = () => { setBrief(""); setBriefFiles([]); setMoment(null); setStudyName(window.EH.studyFor(null)); setManual(true); setRoute("intake"); };
  const goHome = () => { setHomeKey(k => k + 1); setBrief(""); setBriefFiles([]); setMoment(null); setStudyName(window.EH.studyFor(null)); setManual(false); setOpenStudy(null); setRoute("home"); };
  const nav = (id) => {
    if (id === "home") return goHome();
    setOpenStudy(null);
    setRoute(id);
  };

  /* `opt` is the audience option the user confirmed on the review screen. */
  const confirmPublish = (opt) => {
    setBusy(true);
    setTimeout(() => {
      const s = {
        id: "sv-" + Date.now(),
        name: studyName,
        owner: "Dan Leahy",
        updated: "Today · just now",
        mins: -1,
        status: "Live",
        responses: 0,
        profiles: 3,
        badge: "mint",
        cas: ["ca-age", "ca-gender", "ca-activity"]
      };
      setStudies(p => [s, ...p]);
      setListKey(k => k + 1);
      setBusy(false);
      setBrief("");
      setRoute("studies");
      setLanded({ tier, name: s.name, opt: opt || null });
    }, Math.max(0, tweaks.publishSeconds) * 1000);
  };

  const navActive = route === "home" ? "home"
    : (route === "designing" || route === "intake" || route === "review" || route === "studies" || route === "study") ? "studies"
    : route;

  const crumb = route === "designing" ? <React.Fragment><span className="sl">/</span><span>New study · designing</span></React.Fragment>
    : route === "intake" ? <React.Fragment><span className="sl">/</span><button onClick={() => nav("studies")}>Studies</button><span className="sl">/</span><input className="sf-crumb__edit" value={studyName} onChange={e => setStudyName(e.target.value)} onKeyDown={e => { if (e.key === "Enter") e.target.blur(); }} size={Math.max(12, studyName.length)} aria-label="Study name" /></React.Fragment>
    : route === "review" ? <React.Fragment><span className="sl">/</span><button onClick={() => nav("studies")}>Studies</button><span className="sl">/</span><button onClick={() => setRoute("intake")}>{studyName}</button><span className="sl">/</span><b>Review</b></React.Fragment>
    : route === "study" ? <React.Fragment><span className="sl">/</span><button onClick={() => { setOpenStudy(null); setRoute("studies"); }}><i className="ti ti-chevron-left"></i>All studies</button><span className="sl">/</span><b>{openStudy && openStudy.name}</b><i className="ti ti-circle-check-filled sf-crumb__status" title="Closed study" aria-label="Closed study"></i></React.Fragment>
    : null;

  const clickableIds = ["demo-study", "sv-gola", "sv-apparel", "sv-gsc", ...studies.map(s => s.id)];

  /* Which respondent file the study surfaces read. Set before the study page
     mounts (and the page is keyed on the study id) so Raw Results, the
     sentiment benchmarks and the product imagery all resolve against the same
     study rather than whichever one happened to load first. */
  const openStudyPage = (st, tab) => {
    const cfg = window.srpStudyCfg ? window.srpStudyCfg(st) : null;
    if (cfg) {
      window.ACTIVE_STUDY_JSON = cfg.json;
      if (cfg.cfg) window.ACTIVE_STUDY_CFG = cfg.cfg;
      else if (window.__BASE_STUDY_CFG) window.ACTIVE_STUDY_CFG = window.__BASE_STUDY_CFG;
      const prof = cfg.profiles && cfg.profiles();
      window.ACTIVE_PROFILES = prof || window.__BASE_PROFILES || [];
    }
    setStudyTab(SF_TAB_IDS.indexOf(tab) >= 0 ? tab : "insights");
    setOpenStudy(st);
    setRoute("study");
  };

  /* Read the URL on load and whenever the user moves through history. Kept in a
     ref so the listener is registered once and still sees the current studies. */
  const sfApply = React.useRef(null);
  sfApply.current = () => {
    const t = sfParseHash(window.location.hash);
    if (t.route === "study") {
      const st = sfFindStudy(t.studyId, studies);
      if (st) return openStudyPage(st, t.tab);
      setOpenStudy(null);
      return setRoute("studies");
    }
    if (t.route === "intake") return goManual();
    setOpenStudy(null);
    setRoute(t.route);
  };
  sfE(() => {
    if (sfNormHash(window.location.hash)) sfApply.current();
    const on = () => sfApply.current();
    window.addEventListener("hashchange", on);
    return () => window.removeEventListener("hashchange", on);
  }, []);

  /* Write the URL back. Nothing to do when it already says what we mean, which
     is what keeps Back from bouncing straight forward again. The first write of
     the session replaces rather than pushes, so one Back still leaves the demo. */
  const sfWrote = React.useRef(false);
  sfE(() => {
    const h = sfFormatHash(route, openStudy, studyTab, manual);
    if (h == null || sfNormHash(h) === sfNormHash(window.location.hash)) return;
    if (sfWrote.current) window.history.pushState(null, "", h);
    else window.history.replaceState(null, "", h);
    sfWrote.current = true;
  }, [route, openStudy, studyTab, manual]);

  return (
    <React.Fragment>
      <div className="sf-app">
        <div className="sf-top">
          <span className="sf-top__logo"><img className="ua-mark" src="brand/ua-mark.svg" alt="Under Armour" /></span>
          {crumb && <span className="sf-crumb">{crumb}</span>}
          <span className="sf-top__sp"></span>
          <span className="sf-top__user">DL</span>
        </div>
        <div className="sf-body">
          <div className="sf-nav">
            {SF_NAV.map(x => (
              <button key={x.id} className={"sf-nav__b" + (x.id === navActive ? " on" : "")} onClick={() => nav(x.id)}>
                <i className={"ti ti-" + x.icon}></i><em>{x.label}</em>
              </button>
            ))}
          </div>
          <div className="sf-page">
            {route === "home" ? (
              <window.EHHome key={homeKey} bare onStart={start} onBuildManual={goManual} />
            ) : route === "designing" ? (
              <window.IntakeLoading running bare brief={brief} onSkip={() => setRoute("intake")} />
            ) : route === "intake" || route === "review" ? (
              /* The intake screen stays mounted behind the review, hidden rather
                 than unmounted. "Back to the study" has to return you to the tab,
                 the questions and the assets you left — a review gate that resets
                 the work behind it is a gate nobody walks through twice. */
              <React.Fragment>
                <div style={{ display: route === "review" ? "none" : "flex", flex: 1, minHeight: 0 }}>
                  <window.IntakeScreen bare brief={brief} briefFiles={briefFiles} manual={manual} moment={moment} studyName={studyName} initialTab={manual ? "qs" : "what"}
                    onPublish={(t, d, a, au) => { setTier(t); setDc(d || null); setDcAns(a || null); setAud(au || null); setRoute("review"); }} />
                </div>
                {/* The review screen is StudyCheckout: the audience, the Digital
                    Twin panels it scores against, and a live summary. It sizes
                    itself from the audience rather than from AT_PLAN, so what it
                    needs is that audience (`aud`, lifted off the builder's
                    Audience tab) and the moment the study came from, which is
                    what picks the behavioural screen. dc and dcAns are still
                    lifted above for the intake rail; this screen does not read
                    them directly — it reads `tier`, the one fact they resolved
                    to, so a same-day or Directional answer in the dock opens
                    checkout already on Digital Twins instead of defaulting to
                    Mixed and making the merchant re-discover what they just
                    told the chat. */}
                {route === "review" && (
                  <window.StudyCheckout name={studyName} busy={busy} moment={moment} aud={aud} tier={tier}
                    onCancel={() => setRoute("intake")} onConfirm={confirmPublish} />
                )}
              </React.Fragment>
            ) : route === "studies" ? (
              <window.StudiesList
                key={listKey}
                extraSurveys={studies}
                justPublishedId={null}
                clickableIds={clickableIds}
                onOpenStudy={openStudyPage}
                onNewStudy={goHome}
              />
            ) : route === "study" ? (
              <window.SFStudyPage key={openStudy ? openStudy.id : "none"} study={openStudy} tab={studyTab} onTab={setStudyTab} />
            ) : route === "assets" ? (
              <window.AssetsPage onNewStudy={goHome} />
            ) : route === "library" ? (
              <window.LibraryPage />
            ) : null}
          </div>
        </div>
      </div>
      {landed && <SFLanded tier={landed.tier} name={landed.name} opt={landed.opt} onGo={() => { setLanded(null); setRoute("studies"); }} />}
      {toast && <div className="sf-toast"><i className="ti ti-circle-check-filled"></i>{toast}</div>}
      <window.TweaksPanel title="Sales demo">
        <window.TweakSection label="Pacing" />
        <window.TweakSlider label="Designing" value={tweaks.designSeconds} min={2} max={20} step={1} unit="s" onChange={v => setTweak("designSeconds", v)} />
        <window.TweakSlider label="Publishing" value={tweaks.publishSeconds} min={0} max={4} step={0.2} unit="s" onChange={v => setTweak("publishSeconds", v)} />
        <window.TweakSection label="Jump to" />
        <window.TweakRadio label="Screen" value={route === "study" ? "studies" : route} options={["home", "designing", "intake", "review", "studies"]} onChange={setRoute} />
      </window.TweaksPanel>
    </React.Fragment>
  );
}

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