/* ============================================================
   TOP WHEELS Funnel — application / state machine
   - Single formData state object (also mirrored to window.formData)
   - Hooks: window.onStepComplete(stepKey, data) + window.onSubmit(data)
            + CustomEvents 'topwheels:step' / 'topwheels:submit'
   - Three layout DIRECTIONS: a=Split  b=Centered  c=Editorial
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;
const {
  Icon, BrandLogo, Progress, PrimaryBtn,
  WelcomeStep, QualifyStep, InfoStep, DealStep, VehicleStep, LocationStep, OtherPartyStep, BookStep,
  QuestionStep, SellerScreen, NotReadyScreen, NotFitScreen, ThankYouScreen,
} = window;

const STORAGE_KEY = "topwheels_intake_v1";

/* ----- the linear (happy-path) flow, used for progress + rail index ----- */
const FLOW = [
  { key: "welcome",  name: "Welcome",       label: "Start here" },
  { key: "qualify",  name: "Quick Qualify", label: "Quick qualify" },
  { key: "info",     name: "Your Details",  label: "Your details" },
  { key: "deal",     name: "Deal Details",  label: "Deal details" },
  { key: "vehicle",  name: "The Vehicle",   label: "The vehicle" },
  { key: "location", name: "Location",      label: "Location" },
  { key: "other",    name: "The Other Side",label: "The other side" },
  { key: "book",     name: "Book Call",     label: "Book the call" },
];
const FLOW_INDEX = Object.fromEntries(FLOW.map((s, i) => [s.key, i]));

/* ============================================================
   Analytics layer — drop-off + conversion tracking.
   Every funnel moment is pushed to a GTM-style dataLayer AND a single
   window.onFunnelEvent(eventName, detail) hook. Wire either to GA4 / GTM /
   Meta Pixel / your warehouse. No PII is included in analytics events —
   only step keys, indices, and intent. (Lead data flows via onStepComplete
   / onSubmit instead.) Events:
     topwheels_step_view      — a step was shown   (drop-off denominator)
     topwheels_step_complete  — a step was passed  (drop-off numerator)
     topwheels_submit         — intake or question submitted
   ============================================================ */
function stepName(key) {
  const f = FLOW.find((s) => s.key === key);
  return f ? f.name : key;
}
function trackEvent(event, detail) {
  const payload = { event: "topwheels_" + event, ...detail, ts: Date.now() };
  try { (window.dataLayer = window.dataLayer || []).push(payload); } catch (e) {}
  try { window.onFunnelEvent && window.onFunnelEvent("topwheels_" + event, detail || {}); } catch (e) {}
}

/* per-screen header copy (static screens). info + other are role-aware via headFor(). */
const HEAD = {
  qualify:  { eyebrow: "Quick Qualify", title: ["Let's Make Sure ", "We're A Fit."], lead: "Three fast questions so we can route your deal the right way." },
  deal:     { eyebrow: "Deal Details", title: ["The Shape ", "Of The Deal."], lead: "A quick read on structure and status so we know how to coordinate." },
  vehicle:  { eyebrow: "The Vehicle", title: ["What Are ", "We Moving?"], lead: "The basics on the unit. VIN is optional now — it speeds up paperwork later." },
  location: { eyebrow: "Location", title: ["Where In ", "The Country?"], lead: "Your state shapes the paperwork and process — this helps us line up the right docs." },
  question: { eyebrow: "Quick Question", title: ["Drop Your ", "Question."], lead: "Ask away. Leave your contact and a coordinator will follow up directly." },
};

/* role-aware header for the two contact steps */
function headFor(screen, d) {
  if (screen === "info") {
    const r = d.role === "seller" ? "seller" : "buyer";
    return {
      eyebrow: "Your Details",
      title: ["This Part's ", "About You."],
      lead: `You're the ${r}. We capture your details up front so your deal stays recoverable if you step away.`,
    };
  }
  if (screen === "other") {
    const o = d.role === "seller" ? "buyer" : "seller";
    const O = o.charAt(0).toUpperCase() + o.slice(1);
    return {
      eyebrow: `The ${O}`,
      title: ["Loop In ", `The ${O}.`],
      lead: `Your transparency call is with both sides — drop the ${o}'s details so we can bring them in.`,
    };
  }
  return HEAD[screen];
}

const CY = (parts) => parts.map((t, i) => i === 1 ? <span className="cy" key={i}>{t}</span> : <React.Fragment key={i}>{t}</React.Fragment>);

/* ============================================================
   validation
   ============================================================ */
const reEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const digits = (s) => (s || "").replace(/\D/g, "");

function validate(key, d) {
  const e = {};
  if (key === "qualify") {
    if (!d.subToStudent) e.subToStudent = "Pick one to continue";
    if (!d.needsHelp) e.needsHelp = "Pick one to continue";
    if (!d.role) e.role = "Pick one to continue";
    if (d.role === "seller" && !d.hasBuyer) e.hasBuyer = "Pick one to continue";
  }
  if (key === "deal") {
    if (!d.termsAgreed) e.termsAgreed = "Pick one to continue";
    if (!d.dealType) e.dealType = "Pick one to continue";
    if (!d.loanCurrent) e.loanCurrent = "Pick one to continue";
  }
  if (key === "info") {
    if (!d.firstName?.trim()) e.firstName = "Required";
    if (!d.lastName?.trim()) e.lastName = "Required";
    if (!d.email?.trim()) e.email = "Required";
    else if (!reEmail.test(d.email)) e.email = "Enter a valid email";
    const dn = digits(d.phone);
    if (!dn) e.phone = "Required";
    else if (d.phoneCc === "+1" && dn.length !== 10) e.phone = "Enter a 10-digit number";
    else if (dn.length < 7) e.phone = "Enter a valid number";
    if (!d.heardAbout) e.heardAbout = "Pick one";
  }
  if (key === "vehicle") {
    if (!digits(d.year) || d.year.length !== 4) e.year = "4-digit year";
    else { const y = +d.year; if (y < 1900 || y > 2027) e.year = "Check the year"; }
    if (!d.make?.trim()) e.make = "Required";
    if (!d.model?.trim()) e.model = "Required";
    /* VIN intentionally NOT validated — fully optional, collected later in TC. */
  }
  if (key === "location") {
    if (!d.vehicleLocation?.trim()) e.vehicleLocation = "Required";
    if (!d.drivingLocation?.trim()) e.drivingLocation = "Required";
  }
  if (key === "other") {
    if (!d.otherFirstName?.trim()) e.otherFirstName = "Required";
    if (!d.otherLastName?.trim()) e.otherLastName = "Required";
    if (!d.otherEmail?.trim()) e.otherEmail = "Required";
    else if (!reEmail.test(d.otherEmail)) e.otherEmail = "Enter a valid email";
  }
  if (key === "question") {
    if (!d.question?.trim()) e.question = "Tell us what you need";
    if (!d.firstName?.trim()) e.firstName = "Required";
    if (!d.email?.trim()) e.email = "Required";
    else if (!reEmail.test(d.email)) e.email = "Enter a valid email";
  }
  return e;
}

/* routing: given current key + data, where to go next */
function nextKey(key, d) {
  switch (key) {
    case "welcome": return "qualify";
    case "qualify":
      if (d.needsHelp === "no") return "notfit";
      if (d.needsHelp === "question") return "question";
      if (d.role === "seller" && d.hasBuyer === "no") return "seller";
      return "info";
    case "info": return "deal";
    case "deal":
      if (d.termsAgreed === "no") return "notready";
      return "vehicle";
    case "vehicle": return "location";
    case "location": return "other";
    case "other": return "book";
    case "question": return "thankyou";
    default: return null;
  }
}

/* which screens allow Continue only once minimally answered */
function canProceed(key, d) {
  if (key === "qualify") return !!(d.subToStudent && d.needsHelp && d.role && (d.role !== "seller" || d.hasBuyer));
  if (key === "deal") return !!(d.termsAgreed && d.dealType && d.loanCurrent);
  return true;
}

const TERMINALS = ["book", "seller", "notready", "notfit", "thankyou"];

/* ============================================================
   App
   ============================================================ */
const DEFAULT_DATA = {
  subToStudent: "", needsHelp: "", role: "", hasBuyer: "",
  firstName: "", lastName: "", email: "", phone: "", phoneCc: "+1", heardAbout: "",
  termsAgreed: "", dealType: "", loanCurrent: "",
  year: "", make: "", model: "", trim: "", vin: "",
  vehicleLocation: "", drivingLocation: "",
  otherFirstName: "", otherLastName: "", otherEmail: "",
  question: "",
};

function App() {
  const params = new URLSearchParams(location.search);
  const compare = !!window.__COMPARE;
  const embed = compare || params.get("embed") === "1";
  const urlDir = window.__FORCE_DIR || params.get("dir");

  const [dir] = useState("c"); // Editorial is the one and only direction

  // Load any saved progress once. localStorage survives refresh AND closing
  // the tab, so a returning lead resumes exactly where they left off.
  const saved = (() => {
    if (compare) return null;
    try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || "null"); }
    catch (e) { return null; }
  })();

  const [data, setData] = useState(() =>
    saved?.data ? { ...DEFAULT_DATA, ...saved.data } : { ...DEFAULT_DATA }
  );
  const [screen, setScreen] = useState(() => {
    const s = saved?.screen;
    // resume on the saved step (but never on a one-shot terminal end-screen)
    if (s && s !== "thankyou" && s !== "notfit" && s !== "notready" && s !== "seller") return s;
    return "welcome";
  });
  const [history, setHistory] = useState(() => Array.isArray(saved?.history) ? saved.history : []);
  const [errors, setErrors] = useState({});
  const [transDir, setTransDir] = useState("fwd");
  const stageRef = useRef(null);

  // mirror to window.formData + persist progress (data, current step, history)
  useEffect(() => {
    if (compare) return;
    window.formData = data;
    try { localStorage.setItem(STORAGE_KEY, JSON.stringify({ data, screen, history })); } catch (e) {}
  }, [data, screen, history]);

  const set = useCallback((field, value) => {
    setData((d) => ({ ...d, [field]: value }));
    setErrors((er) => (er[field] ? { ...er, [field]: undefined } : er));
  }, []);

  const fireStep = (key) => {
    const idx = FLOW_INDEX[key];
    try { window.onStepComplete && window.onStepComplete(key, window.formData); } catch (e) {}
    trackEvent("step_complete", { step: key, stepIndex: idx ?? null, stepName: stepName(key) });
    window.dispatchEvent(new CustomEvent("topwheels:step", { detail: { step: key, data: window.formData } }));
  };
  const fireSubmit = (kind) => {
    const payload = { ...window.formData, _intent: kind };
    try { window.onSubmit && window.onSubmit(payload); } catch (e) {}
    trackEvent("submit", { intent: kind });
    window.dispatchEvent(new CustomEvent("topwheels:submit", { detail: payload }));
  };

  // Fire a "step view" whenever a screen is shown — this is what powers
  // drop-off analytics (how many SAW step N vs completed it).
  useEffect(() => {
    if (compare) return;
    trackEvent("step_view", { step: screen, stepIndex: FLOW_INDEX[screen] ?? null, stepName: stepName(screen) });
  }, [screen]);

  const goNext = () => {
    const errs = validate(screen, data);
    if (Object.keys(errs).filter((k) => errs[k]).length) {
      setErrors(errs);
      scrollToFirstError();
      return;
    }
    fireStep(screen);
    const nk = nextKey(screen, data);
    if (!nk) return;
    if (nk === "book") fireSubmit("intake");
    if (nk === "thankyou") fireSubmit("question");
    setTransDir("fwd");
    setHistory((h) => [...h, screen]);
    setScreen(nk);
    setErrors({});
    if (stageRef.current) stageRef.current.scrollTop = 0;
  };

  // After a failed validation, bring the first problem into view and focus it.
  // Critical on mobile, where the missing field is often below the fold.
  const scrollToFirstError = () => {
    requestAnimationFrame(() => {
      const stage = stageRef.current;
      if (!stage) return;
      const errEl = stage.querySelector(".ferror");
      if (!errEl) return;
      const block = errEl.closest(".qblock, .field") || errEl.parentElement;
      const top = block.getBoundingClientRect().top
        - stage.getBoundingClientRect().top + stage.scrollTop - 28;
      try { stage.scrollTo({ top: Math.max(0, top), behavior: "smooth" }); }
      catch (e) { stage.scrollTop = Math.max(0, top); }
      const input = block.querySelector("input, select, textarea");
      if (input) { try { input.focus({ preventScroll: true }); } catch (e) {} }
    });
  };

  const goBack = () => {
    setHistory((h) => {
      if (!h.length) return h;
      const prev = h[h.length - 1];
      setTransDir("back");
      setScreen(prev);
      setErrors({});
      if (stageRef.current) stageRef.current.scrollTop = 0;
      return h.slice(0, -1);
    });
  };

  // jump straight to an already-completed flow step (left-rail navigation)
  const goTo = (key) => {
    if (!(key in FLOW_INDEX) || !(screen in FLOW_INDEX)) return;
    const idx = FLOW_INDEX[key];
    if (idx >= FLOW_INDEX[screen]) return; // only jump backward to completed steps
    setTransDir("back");
    setHistory(FLOW.slice(0, idx).map((f) => f.key));
    setScreen(key);
    setErrors({});
    if (stageRef.current) stageRef.current.scrollTop = 0;
  };

  const restart = () => {
    setTransDir("back");
    setData({ ...DEFAULT_DATA });
    setScreen("welcome");
    setHistory([]);
    setErrors({});
    try { localStorage.removeItem(STORAGE_KEY); } catch (e) {}
  };

  // keyboard: Enter advances on non-terminal steps (not inside textarea)
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === "Enter" && !e.shiftKey && e.target.tagName !== "TEXTAREA") {
        if (!TERMINALS.includes(screen)) { e.preventDefault(); goNext(); }
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  });

  /* ---------- content for the active screen ---------- */
  const renderContent = () => {
    switch (screen) {
      case "welcome":  return <WelcomeStep />;
      case "qualify":  return <QualifyStep data={data} set={set} errors={errors} />;
      case "info":     return <InfoStep data={data} set={set} errors={errors} />;
      case "deal":     return <DealStep data={data} set={set} errors={errors} />;
      case "vehicle":  return <VehicleStep data={data} set={set} errors={errors} />;
      case "location": return <LocationStep data={data} set={set} errors={errors} />;
      case "other":    return <OtherPartyStep data={data} set={set} errors={errors} />;
      case "book":     return <BookStep data={data} />;
      case "question": return <QuestionStep data={data} set={set} errors={errors} />;
      case "seller":   return <SellerScreen />;
      case "notready": return <NotReadyScreen />;
      case "notfit":   return <NotFitScreen />;
      case "thankyou": return <ThankYouScreen data={data} />;
      default: return null;
    }
  };

  const head = headFor(screen, data);
  const isFlow = screen in FLOW_INDEX;
  const showProgress = isFlow && screen !== "welcome";
  const flowIdx = isFlow ? FLOW_INDEX[screen] : (screen === "question" ? 1.5 : null);
  const proceedable = canProceed(screen, data);

  /* ---------- footer nav per screen ---------- */
  const renderFoot = () => {
    if (screen === "welcome") {
      return (
        <div className="foot">
          <PrimaryBtn variant="primary" size="lg" icon="arrow-right" onClick={goNext}>Start intake</PrimaryBtn>
          <span className="spacer" />
          <span className="foot-hint">~3 MIN · YOUR INFO STAYS PRIVATE</span>
        </div>
      );
    }
    if (screen === "book") {
      return (
        <div className="foot">
          <button className="btn btn-back" onClick={goBack}><Icon name="arrow-right" style={{ transform: "rotate(180deg)" }} />Back</button>
          <span className="spacer" />
          <span className="foot-hint">PICK A TIME ABOVE TO CONFIRM</span>
        </div>
      );
    }
    if (["seller", "notready", "notfit", "thankyou"].includes(screen)) {
      return (
        <div className="foot">
          <button className="btn btn-back" onClick={goBack}><Icon name="arrow-right" style={{ transform: "rotate(180deg)" }} />Back</button>
          <span className="spacer" />
          <button className="btn btn-ghost" onClick={restart}>Start over</button>
        </div>
      );
    }
    // mid-flow + question
    const isQuestion = screen === "question";
    return (
      <div className="foot">
        <button className="btn btn-back" onClick={goBack}><Icon name="arrow-right" style={{ transform: "rotate(180deg)" }} />Back</button>
        <span className="spacer" />
        <PrimaryBtn variant="primary" icon={isQuestion ? "mail" : "arrow-right"}
          onClick={goNext}>
          {isQuestion ? "Send question" : "Continue"}
        </PrimaryBtn>
      </div>
    );
  };

  /* ---------- header block (eyebrow / title / lead) ---------- */
  const StepHeader = () => head ? (
    <React.Fragment>
      <div className="step-eyebrow">{head.eyebrow}</div>
      <h2 className="step-title">{CY(head.title)}</h2>
      <p className="step-lead">{head.lead}</p>
    </React.Fragment>
  ) : null;

  /* ---------- Editorial left rail (oversized numeral + clickable index) ---------- */
  const renderAsideC = () => {
    const numTxt = isFlow ? String(flowIdx + 1).padStart(2, "0") : "·";
    return (
      <aside className="aside aside-edi">
        <div className="aside-top">
          <BrandLogo href="https://topwheels.io/" />
        </div>
        <div className="aside-body">
          <div className="edi-num" key={screen}>{numTxt}</div>
          <div className="edi-label">{head ? head.eyebrow : (FLOW.find((f) => f.key === screen)?.name || "Intake")}</div>
        </div>
        <ol className="edi-index">
          {FLOW.map((s) => {
            const idx = FLOW_INDEX[s.key];
            const here = s.key === screen;
            const done = isFlow && idx < flowIdx;
            const cls = here ? "active" : done ? "done clickable" : "locked";
            const jump = done ? () => goTo(s.key) : undefined;
            return (
              <li
                key={s.key}
                className={cls}
                onClick={jump}
                role={done ? "button" : undefined}
                tabIndex={done ? 0 : undefined}
                aria-current={here ? "step" : undefined}
                onKeyDown={done ? (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); goTo(s.key); } } : undefined}
              >
                <span className="dot" />
                <span className="edi-i-num">
                  {done ? <Icon name="check" style={{ width: 12, height: 12 }} /> : String(idx + 1).padStart(2, "0")}
                </span>
                <span className="edi-i-name">{s.label}</span>
                {done && <Icon name="arrow-right" className="edi-i-go" />}
                {!here && !done && <Icon name="x" className="edi-i-lock" style={{ opacity: 0 }} />}
              </li>
            );
          })}
        </ol>
        <div className="aside-foot">
          <span className="trust-line"><Icon name="shield" /> PRIVATE · NEVER SOLD · ~3 MIN</span>
        </div>
      </aside>
    );
  };

  const stepWrapClass = `step ${["info", "vehicle", "other"].includes(screen) ? "wide" : ""}`;

  return (
    <div className={`app dir-${dir} ${transDir === "back" ? "dir-back" : ""}`}>
      <div className="fx-glow g1" />
      <div className="fx-glow g2" />

      {renderAsideC()}

      <div className="main">
        {/* mobile header (compact brand + trust) */}
        <div className="mobile-head">
          <BrandLogo href="https://topwheels.io/" />
          <span className="trust-line"><Icon name="shield" /> ~3 MIN</span>
        </div>

        {showProgress && <Progress index={flowIdx} total={FLOW.length} name={FLOW[flowIdx]?.name}
          saved={!compare && !!(data.subToStudent || data.needsHelp || data.role || data.firstName || data.email)} />}
        {screen === "question" && (
          <div className="progress-wrap"><div className="progress-meta">
            <span className="progress-label">QUICK QUESTION</span>
            <span className="progress-name">no commitment</span>
          </div></div>
        )}

        <div className="stage" ref={stageRef}>
          <div className={stepWrapClass} key={screen}>
            {head && <StepHeader />}
            {renderContent()}
          </div>
        </div>

        {renderFoot()}
      </div>
    </div>
  );
}

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