// Apply flow - multi-step modal triggered from every "Apply" CTA on the page.
// Cohort and 1-to-1 each have their own Step 2. notSure skips Step 2 entirely.
//
// Trigger: window.dispatchEvent(new CustomEvent('intensives:openApplyFlow', {
//   detail: { programme: 'cohort'|'oneToOne'|'notSure'|null, subject?: string }
// }))

const NOTIFIER_CONFIG = /*EDITMODE-BEGIN*/{
  "workerUrl": "https://intensives-notifier.iborbit.workers.dev",
  "secret": "2927953690150ea6bf0986531dc8e5f60cd8565c5d4b3bad9a8d6df4bcbd2c3e"
}/*EDITMODE-END*/;

async function subscribeViaWorker({ email, firstName, lastName, fields, tags }) {
  const url = NOTIFIER_CONFIG.workerUrl.replace(/\/$/, '') + '/subscribe';
  const bodyStr = JSON.stringify({ secret: NOTIFIER_CONFIG.secret, email, firstName, lastName, fields, tags });
  try {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: bodyStr,
      keepalive: true,
    });
    return { ok: res.ok };
  } catch (e) {
    const sent = navigator.sendBeacon(url, new Blob([bodyStr], { type: 'application/json' }));
    return { ok: sent };
  }
}

async function submitApplicationViaWorker({ email, firstName, lastName, fields, tags }) {
  const url = NOTIFIER_CONFIG.workerUrl.replace(/\/$/, '') + '/apply';
  const bodyStr = JSON.stringify({ secret: NOTIFIER_CONFIG.secret, email, firstName, lastName, fields, tags });
  try {
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: bodyStr,
      keepalive: true,
    });
    return { ok: res.ok };
  } catch (e) {
    const sent = navigator.sendBeacon(url, new Blob([bodyStr], { type: 'application/json' }));
    return { ok: sent };
  }
}

const PROGRAMME_LABEL = {
  cohort:   "Cohort Intensive",
  oneToOne: "1-to-1 Intensive",
  notSure:  "Not sure yet",
};

const COHORT_SUBJECTS = [
  "Economics",
  "History",
  "English A",
  "Other (request a subject)",
];

const ONE_TO_ONE_COMPONENTS = [
  "History IA", "Economics IA", "Biology IA",
  "Chemistry IA", "Physics IA",
  "Maths AA IA", "Maths AI IA",
  "Latin IA", "Computer Science IA",
  "English HL Essay", "English IO",
  "TOK essay + exhibition",
  "Extended Essay",
];

const PRACTICE_HISTORY = ["Yes", "A little", "No"];

const COHORT_BLOCKERS = [
  "Structure",
  "Technique",
  "Content gaps",
  "Time management",
  "Motivation",
  "Exam stress",
  "Other",
];

const DRAFT_STATES = [
  { value: "pre-draft",   label: "Pre-draft: haven't started, or just have a research question/outline" },
  { value: "mid-draft",   label: "Mid-draft: have a working draft that needs serious work" },
  { value: "near-final",  label: "Near-final: think it's mostly done, want a polish" },
];

const PREDICTED_GRADES = ["3", "4", "5", "6", "7"];
const EXAM_SESSIONS = ["Nov 2026", "May 2027", "Nov 2027", "May 2028", "Nov 2028"];
const COMMITMENT = ["Yes", "I think so", "I'm not sure"];

const INITIAL_FORM = {
  role: "",
  name: "", email: "", programme: "", subject: "",
  predictedGrade: "", examSession: "",
  practiceHistory: "", recentMarks: "", mainBlocker: [], commitment: "",
  schoolDeadline: "", draftState: "", helpFocus: "",
  notes: "",
};

const splitName = (full) => {
  const parts = (full || "").trim().split(/\s+/);
  return { first_name: parts[0] || "", last_name: parts.slice(1).join(" ") };
};

/* ─── Date select ────────────────────────────────────────────────── */

const MONTHS = [
  { v: "01", l: "January" }, { v: "02", l: "February" }, { v: "03", l: "March" },
  { v: "04", l: "April" },   { v: "05", l: "May" },      { v: "06", l: "June" },
  { v: "07", l: "July" },    { v: "08", l: "August" },   { v: "09", l: "September" },
  { v: "10", l: "October" }, { v: "11", l: "November" }, { v: "12", l: "December" },
];

const DateSelectField = ({ value, onChange }) => {
  const curYear = new Date().getFullYear();
  const years = Array.from({ length: 5 }, (_, i) => String(curYear + i));

  const init = value ? value.split("-") : ["", "", ""];
  const [yr, setYr] = React.useState(init[0] || "");
  const [mo, setMo] = React.useState(init[1] || "");
  const [dy, setDy] = React.useState(init[2] || "");

  const daysInMonth = (mo && yr) ? new Date(Number(yr), Number(mo), 0).getDate() : 31;
  const days = Array.from({ length: daysInMonth }, (_, i) => String(i + 1).padStart(2, "0"));

  const emit = (y, m, d) => onChange((y && m && d) ? `${y}-${m}-${d}` : "");

  const handleMonth = (m) => {
    const max = (m && yr) ? new Date(Number(yr), Number(m), 0).getDate() : 31;
    const safeDy = dy && Number(dy) > max ? String(max).padStart(2, "0") : dy;
    setMo(m);
    if (safeDy !== dy) setDy(safeDy);
    emit(yr, m, safeDy);
  };

  const handleDay = (d) => { setDy(d); emit(yr, mo, d); };

  const handleYear = (y) => {
    const max = (mo && y) ? new Date(Number(y), Number(mo), 0).getDate() : 31;
    const safeDy = dy && Number(dy) > max ? String(max).padStart(2, "0") : dy;
    setYr(y);
    if (safeDy !== dy) setDy(safeDy);
    emit(y, mo, safeDy);
  };

  return (
    <div className="apf-date-row">
      <div className="apf-select-wrap">
        <select value={mo} onChange={(e) => handleMonth(e.target.value)}>
          <option value="">Month</option>
          {MONTHS.map(({ v, l }) => <option key={v} value={v}>{l}</option>)}
        </select>
        <Icon name="chevron-down" />
      </div>
      <div className="apf-select-wrap apf-date-day">
        <select value={dy} onChange={(e) => handleDay(e.target.value)}>
          <option value="">Day</option>
          {days.map((d) => <option key={d} value={d}>{Number(d)}</option>)}
        </select>
        <Icon name="chevron-down" />
      </div>
      <div className="apf-select-wrap apf-date-year">
        <select value={yr} onChange={(e) => handleYear(e.target.value)}>
          <option value="">Year</option>
          {years.map((y) => <option key={y} value={y}>{y}</option>)}
        </select>
        <Icon name="chevron-down" />
      </div>
    </div>
  );
};

/* ─── Primitives ──────────────────────────────────────────────────── */

const ApplyField = ({ label, subLabel, optional, children }) => (
  <div className="apf-field">
    <div className="apf-label">
      <span>{label}</span>
      {optional && <em>optional</em>}
    </div>
    {subLabel && <p className="apf-sublabel">{subLabel}</p>}
    {children}
  </div>
);

const ApplyRadioRow = ({ name, options, value, onChange, layout = "row" }) => (
  <div className={`apf-radio apf-radio-${layout}`} role="radiogroup">
    {options.map((opt) => {
      const v = typeof opt === "string" ? opt : opt.value;
      const label = typeof opt === "string" ? opt : opt.label;
      const checked = value === v;
      return (
        <label key={v} className={`apf-radio-opt ${checked ? "checked" : ""}`}>
          <input type="radio" name={name} value={v} checked={checked} onChange={() => onChange(v)} />
          <span>{label}</span>
        </label>
      );
    })}
  </div>
);

const ApplyMultiSelect = ({ options, value, onChange, maxSelect = 3 }) => (
  <div className="apf-multiselect">
    {options.map((opt) => {
      const selected = value.includes(opt);
      const atMax = value.length >= maxSelect;
      return (
        <button
          key={opt} type="button"
          className={`apf-chip${selected ? " selected" : ""}${!selected && atMax ? " disabled" : ""}`}
          onClick={() => {
            if (!selected && atMax) return;
            onChange(selected ? value.filter((v) => v !== opt) : [...value, opt]);
          }}
          aria-pressed={selected}
        >
          {opt}
        </button>
      );
    })}
  </div>
);

/* ─── Step 1 ──────────────────────────────────────────────────────── */

const Step1 = ({ form, setForm, onContinue, busy, error }) => {
  const isNotSure  = form.programme === "notSure";
  const isStudent  = form.role === "student";
  const who = isStudent
    ? { Your: "Your",         your: "your",         their: "your", they: "you",  them: "you"  }
    : { Your: "Your child's", your: "your child's", their: "their", they: "they", them: "them" };

  const subjects = form.programme === "cohort"   ? COHORT_SUBJECTS
                 : form.programme === "oneToOne" ? ONE_TO_ONE_COMPONENTS
                 : null;

  const heading = isNotSure    ? "Quick form, then we'll book the call."
                : !form.role   ? "First, who's applying?"
                : isStudent    ? "Tell us about you."
                :                "Tell us about your child.";

  const hasCall = form.programme === "oneToOne" || form.programme === "notSure";

  const intro = !form.role ? null
              : hasCall
                ? (isStudent
                    ? "Takes 60 seconds. At the end you'll book a short call with us to match you with the right coach; bring a parent to it if you can, since they'll usually have the money and logistics questions."
                    : "Takes 60 seconds. At the end you'll book a short call with us to match your child with the right coach.")
                : (isStudent
                    ? "Takes 60 seconds. We review every application personally and reply within 24 hours; bring a parent into the decision if you can, since they'll usually have the money and logistics questions."
                    : "Takes 60 seconds. We review every application personally and reply within 24 hours.");

  return (
    <div className="apf-step">
      <div className="apf-step-head">
        <div>
          <div className="eyebrow">Apply · Step 1 of 2</div>
          <h3 className="apf-h">{heading}</h3>
          {intro && <p className="apf-intro">{intro}</p>}
        </div>
      </div>
      <div className="apf-fields">
        <ApplyField label="Are you the student, or a parent?">
          <ApplyRadioRow
            name="role" value={form.role}
            onChange={(v) => setForm({ ...form, role: v })}
            options={[
              { value: "student", label: "I'm the student" },
              { value: "parent",  label: "I'm a parent" },
            ]}
            layout="row"
          />
        </ApplyField>
        <ApplyField label={isStudent ? "Your full name" : "Your child's full name"}>
          <input type="text" required value={form.name}
            onChange={(e) => setForm({ ...form, name: e.target.value })}
            placeholder={isStudent ? "Your first and last name" : "First and last name of your child"} />
        </ApplyField>
        <ApplyField label="Your email">
          <input type="email" required value={form.email}
            onChange={(e) => setForm({ ...form, email: e.target.value })}
            placeholder={isStudent ? "Your email - this is who we'll contact" : "Parent/guardian email - this is who we'll contact"} />
        </ApplyField>
        <ApplyField label="Which programme">
          <ApplyRadioRow
            name="programme" value={form.programme}
            onChange={(v) => setForm({ ...form, programme: v, subject: "" })}
            options={[
              { value: "cohort",   label: "Cohort Intensive" },
              { value: "oneToOne", label: "1-to-1 Intensive" },
              { value: "notSure",  label: "Not sure yet" },
            ]}
            layout="stack"
          />
        </ApplyField>
        {subjects && (
          <ApplyField label="Which subject">
            <div className="apf-select-wrap">
              <select value={form.subject}
                onChange={(e) => setForm({ ...form, subject: e.target.value })} required>
                <option value="">Select a subject…</option>
                {subjects.map((s) => <option key={s} value={s}>{s}</option>)}
              </select>
              <Icon name="chevron-down" />
            </div>
          </ApplyField>
        )}
        <ApplyField
          label={`${who.Your} current predicted grade in this subject`}
          subLabel={`Subject-specific predicted grade, not ${who.their} overall IB total.`}
        >
          <ApplyRadioRow
            name="predictedGrade" value={form.predictedGrade}
            onChange={(v) => setForm({ ...form, predictedGrade: v })}
            options={PREDICTED_GRADES} layout="row"
          />
        </ApplyField>
        <ApplyField label={`${who.Your} exam session`}>
          <div className="apf-select-wrap">
            <select value={form.examSession}
              onChange={(e) => setForm({ ...form, examSession: e.target.value })} required>
              <option value="">Select an exam session…</option>
              {EXAM_SESSIONS.map((s) => <option key={s} value={s}>{s}</option>)}
            </select>
            <Icon name="chevron-down" />
          </div>
        </ApplyField>
      </div>
      {error && <p className="apf-error">{error}</p>}
      <button type="button" className="btn purple apf-submit" onClick={onContinue} disabled={busy}>
        {busy ? "Submitting…" : isNotSure ? <>Submit and book my call <Icon name="arrow-right" /></> : <>Continue <Icon name="arrow-right" /></>}
      </button>
      <p className="apf-microcopy">Step 1 of 2. Takes 60 seconds.</p>
    </div>
  );
};

/* ─── Step 2 - Cohort ─────────────────────────────────────────────── */

const Step2Cohort = ({ form, setForm, onBack, onSubmit, busy, error }) => {
  const isStudent = form.role === "student";
  return (
    <div className="apf-step">
      <div className="apf-step-head">
        <button type="button" className="apf-back" onClick={onBack} aria-label="Back to step 1">
          <Icon name="arrow-left" />
        </button>
        <div>
          <div className="eyebrow">Apply · Step 2 of 2</div>
          <h3 className="apf-h">{isStudent ? "Where you are right now." : "Where your child is right now."}</h3>
        </div>
      </div>
      <div className="apf-fields">
        <ApplyField label={isStudent ? "Have you done past-paper practice in this subject before?" : "Has your child done past-paper practice in this subject before?"}>
          <ApplyRadioRow
            name="practiceHistory" value={form.practiceHistory}
            onChange={(v) => setForm({ ...form, practiceHistory: v })}
            options={PRACTICE_HISTORY} layout="row"
          />
        </ApplyField>
        {(form.practiceHistory === "Yes" || form.practiceHistory === "A little") && (
          <ApplyField label={isStudent ? "Roughly what marks have you been getting?" : "Roughly what marks have they been getting?"} optional>
            <input type="text" value={form.recentMarks}
              onChange={(e) => setForm({ ...form, recentMarks: e.target.value })}
              placeholder="e.g. 4s and 5s on Paper 1, struggling on Paper 2" />
          </ApplyField>
        )}
        <ApplyField
          label={isStudent ? "What's the main thing stopping you moving from predicted to target?" : "What's the main thing stopping them moving from predicted to target?"}
          subLabel="Pick up to three."
        >
          <ApplyMultiSelect
            options={COHORT_BLOCKERS} value={form.mainBlocker} maxSelect={3}
            onChange={(next) => setForm({ ...form, mainBlocker: next })}
          />
        </ApplyField>
        <ApplyField label={isStudent ? "Can you commit to one live session plus one drill per week for four weeks?" : "Can your child commit to one live session plus one drill per week for four weeks?"}>
          <ApplyRadioRow
            name="commitment" value={form.commitment}
            onChange={(v) => setForm({ ...form, commitment: v })}
            options={COMMITMENT} layout="row"
          />
        </ApplyField>
        <ApplyField label="Anything else we should know?" optional>
          <textarea data-gramm="false" data-gramm_editor="false"
            rows="2" value={form.notes}
            onChange={(e) => setForm({ ...form, notes: e.target.value })}
            placeholder={isStudent ? "Deadlines, learning differences, anything that helps us match you with the right coach." : "Deadlines, learning differences, anything that helps us match them with the right coach."} />
        </ApplyField>
      </div>
      {error && <p className="apf-error">{error}</p>}
      <button type="button" className="btn purple apf-submit" onClick={onSubmit} disabled={busy}>
        {busy ? "Submitting…" : <>Submit application <Icon name="arrow-right" /></>}
      </button>
      <p className="apf-microcopy">We review every application personally and respond within 24 hours.</p>
    </div>
  );
};

/* ─── Step 2 - 1-to-1 ────────────────────────────────────────────── */

const Step2OneToOne = ({ form, setForm, onBack, onSubmit, busy, error }) => {
  const isStudent = form.role === "student";
  return (
    <div className="apf-step">
      <div className="apf-step-head">
        <button type="button" className="apf-back" onClick={onBack} aria-label="Back to step 1">
          <Icon name="arrow-left" />
        </button>
        <div>
          <div className="eyebrow">Apply · Step 2 of 2</div>
          <h3 className="apf-h">{isStudent ? "Where you are right now." : "Where your child is right now."}</h3>
        </div>
      </div>
      <div className="apf-fields">
        <ApplyField
          label={isStudent ? "When's your school deadline for this component?" : "When's your child's school deadline for this component?"}
          subLabel="We work backwards from this."
        >
          <DateSelectField
            value={form.schoolDeadline}
            onChange={(v) => setForm({ ...form, schoolDeadline: v })}
          />
        </ApplyField>
        <ApplyField label={isStudent ? "Where are you on it right now?" : "Where are they on it right now?"}>
          <ApplyRadioRow
            name="draftState" value={form.draftState}
            onChange={(v) => setForm({ ...form, draftState: v })}
            options={DRAFT_STATES} layout="stack"
          />
        </ApplyField>
        <ApplyField label={isStudent ? "What's the main thing you want help with?" : "What's the main thing they want help with?"}>
          <textarea data-gramm="false" data-gramm_editor="false"
            rows="3" required value={form.helpFocus}
            onChange={(e) => setForm({ ...form, helpFocus: e.target.value })}
            placeholder="Be specific. Research question, methodology, argument structure, analysis, anything." />
        </ApplyField>
        <ApplyField label="Anything else we should know?" optional>
          <textarea data-gramm="false" data-gramm_editor="false"
            rows="2" value={form.notes}
            onChange={(e) => setForm({ ...form, notes: e.target.value })}
            placeholder={isStudent ? "Deadlines, learning differences, anything that helps us match you with the right coach." : "Deadlines, learning differences, anything that helps us match them with the right coach."} />
        </ApplyField>
      </div>
      {error && <p className="apf-error">{error}</p>}
      <button type="button" className="btn purple apf-submit" onClick={onSubmit} disabled={busy}>
        {busy ? "Submitting…" : <>Submit application <Icon name="arrow-right" /></>}
      </button>
      <p className="apf-microcopy">{isStudent ? "Your next step is a 15-minute call to match you with the right coach and set your personalised guarantee. You'll book it on the next screen." : "Your next step is a 15-minute call to match your child with the right coach and set their personalised guarantee. You'll book it on the next screen."}</p>
    </div>
  );
};

/* ─── Step 2 router ───────────────────────────────────────────────── */

const Step2 = (props) => {
  if (props.form.programme === "cohort")   return <Step2Cohort {...props} />;
  if (props.form.programme === "oneToOne") return <Step2OneToOne {...props} />;
  return null;
};

/* ─── Step 3 - Cohort confirmation ───────────────────────────────── */

const Step3Cohort = ({ name, onClose }) => (
  <div className="apf-step apf-step-confirm">
    <div className="apf-confirm-icon"><Icon name="check" /></div>
    <h3 className="apf-h">Application received.</h3>
    <p className="apf-confirm-body">
      We'll review {name ? name.split(" ")[0] + "'s" : "the"} application and email within 24 hours.
      If it's a fit, we'll send next steps.
    </p>
    <p className="apf-confirm-email-note">
      You should get a confirmation email from steven@iborbit.com. Check your promotions and spam if you haven't got it. It has some extra information on it.
    </p>
    <div className="apf-while-you-wait">
      <div className="eyebrow">While you wait</div>
      <div className="apf-wyw-grid">
        <a className="apf-wyw-tile" href="#guarantee" onClick={onClose}>
          <div className="apf-wyw-label">Read</div>
          <div className="apf-wyw-title">The guarantee</div>
          <div className="apf-wyw-arrow"><Icon name="arrow-right" /></div>
        </a>
        <a className="apf-wyw-tile" href="#coaches" onClick={onClose}>
          <div className="apf-wyw-label">Meet</div>
          <div className="apf-wyw-title">The coaches</div>
          <div className="apf-wyw-arrow"><Icon name="arrow-right" /></div>
        </a>
      </div>
    </div>
    <button type="button" className="btn apf-close-btn" onClick={onClose}>Close</button>
  </div>
);

/* ─── Step 3 - 1-to-1 confirmation ───────────────────────────────── */

const Step3OneToOne = ({ name, email, onClose }) => {
  React.useEffect(() => {
    (function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://app.cal.com/embed/embed.js", "init");
    Cal("init", "1-to-1", { origin: "https://app.cal.com" });
    Cal.ns["1-to-1"]("inline", {
      elementOrSelector: "#cal-embed-1to1",
      config: { layout: "month_view", useSlotsViewOnSmallScreen: "true", theme: "light" },
      calLink: "iborbit/1-to-1",
      prefill: { name, email },
    });
    Cal.ns["1-to-1"]("ui", {
      theme: "light",
      cssVarsPerTheme: { light: { "cal-brand": "#4e49a6" }, dark: { "cal-brand": "#4e49a6" } },
      hideEventTypeDetails: false,
      layout: "month_view",
    });
  }, []);
  const firstName = name ? name.split(" ")[0] : "them";
  return (
    <div className="apf-step apf-step-confirm">
      <h3 className="apf-h">Now book your call.</h3>
      <p className="apf-confirm-body">
        15 minutes. We'll match {firstName} with the right coach and put their guarantee in writing.
      </p>
      <p className="apf-confirm-email-note">
        You should get a confirmation email from steven@iborbit.com. Check your promotions and spam if you haven't got it. It has some extra information on it.
      </p>
      <div id="cal-embed-1to1" style={{ width: "100%", height: 760, overflow: "scroll" }} />
      <p className="apf-cal-fallback">
        Can't see the calendar? <a href="https://cal.com/iborbit/1-to-1" target="_blank" rel="noreferrer">Book directly →</a>
      </p>
      <p className="apf-cal-note">We'll send a calendar invite and a short prep doc once you book.</p>
      <button type="button" className="btn apf-close-btn" onClick={onClose}>Close</button>
    </div>
  );
};

/* ─── Step 3 - Not sure confirmation ─────────────────────────────── */

const Step3NotSure = ({ name, email, onClose }) => {
  React.useEffect(() => {
    (function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if (typeof namespace === "string") { cal.ns[namespace] = cal.ns[namespace] || api; p(cal.ns[namespace], ar); p(cal, ["initNamespace", namespace]); } else p(cal, ar); return; } p(cal, ar); }; })(window, "https://app.cal.com/embed/embed.js", "init");
    Cal("init", "match", { origin: "https://app.cal.com" });
    Cal.ns.match("inline", {
      elementOrSelector: "#cal-embed-not-sure",
      config: { layout: "month_view", useSlotsViewOnSmallScreen: "true", theme: "light" },
      calLink: "iborbit/match",
      prefill: { name, email },
    });
    Cal.ns.match("ui", {
      theme: "light",
      cssVarsPerTheme: { light: { "cal-brand": "#4e49a6" }, dark: { "cal-brand": "#4e49a6" } },
      hideEventTypeDetails: false,
      layout: "month_view",
    });
  }, []);
  const firstName = name ? name.split(" ")[0] : "them";
  return (
    <div className="apf-step apf-step-confirm">
      <h3 className="apf-h">Now book your call.</h3>
      <p className="apf-confirm-body">
        15 minutes. We'll figure out which programme fits {firstName} and what happens next.
      </p>
      <p className="apf-confirm-email-note">
        You should get a confirmation email from steven@iborbit.com. Check your promotions and spam if you haven't got it. It has some extra information on it.
      </p>
      <div id="cal-embed-not-sure" style={{ width: "100%", height: 760, overflow: "scroll" }} />
      <p className="apf-cal-fallback">
        Can't see the calendar? <a href="https://cal.com/iborbit/match" target="_blank" rel="noreferrer">Book directly →</a>
      </p>
      <p className="apf-cal-note">We'll send a calendar invite and a short prep doc once you book.</p>
      <button type="button" className="btn apf-close-btn" onClick={onClose}>Close</button>
    </div>
  );
};

/* ─── Step 3 router ───────────────────────────────────────────────── */

const Step3 = ({ name, email, programme, onClose }) => {
  if (programme === "cohort")   return <Step3Cohort name={name} onClose={onClose} />;
  if (programme === "oneToOne") return <Step3OneToOne name={name} email={email} onClose={onClose} />;
  return <Step3NotSure name={name} email={email} onClose={onClose} />;
};

/* ─── Modal shell + state machine ─────────────────────────────────── */

const ApplyFlowModal = () => {
  const [open, setOpen] = React.useState(false);
  const [step, setStep] = React.useState(1);
  const [form, setForm] = React.useState({ ...INITIAL_FORM });
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    const handler = (e) => {
      const detail = e.detail || {};
      setForm((prev) => ({
        ...INITIAL_FORM,
        programme: detail.programme || prev.programme || "",
        subject:   detail.subject   || prev.subject   || "",
      }));
      setStep(1);
      setError("");
      setOpen(true);
    };
    window.addEventListener('intensives:openApplyFlow', handler);
    return () => window.removeEventListener('intensives:openApplyFlow', handler);
  }, []);

  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') closeModal(); };
    if (open) {
      document.addEventListener('keydown', onKey);
      document.body.style.overflow = 'hidden';
    }
    return () => {
      document.removeEventListener('keydown', onKey);
      document.body.style.overflow = '';
    };
  }, [open]);

  const closeModal = () => { setOpen(false); };

  const validateStep1 = () => {
    if (!form.role) return "Please select who's applying.";
    if (!form.name.trim()) return "Please enter the student's name.";
    if (!form.email.trim() || !/^[^@]+@[^@]+\.[^@]+$/.test(form.email)) return "Please enter a valid email.";
    if (!form.programme) return "Please pick a programme.";
    if ((form.programme === "cohort" || form.programme === "oneToOne") && !form.subject) return "Please pick a subject.";
    if (!form.predictedGrade) return "Please select the predicted grade.";
    if (!form.examSession) return "Please select the exam session.";
    return null;
  };

  const validateStep2Cohort = () => {
    if (!form.practiceHistory) return "Please tell us about practice history so far.";
    if (form.mainBlocker.length === 0) return "Please pick at least one main blocker.";
    if (!form.commitment) return "Please indicate whether the weekly commitment works.";
    return null;
  };

  const validateStep2OneToOne = () => {
    if (!form.schoolDeadline) return "Please enter the school deadline.";
    const today = new Date().toISOString().split("T")[0];
    if (form.schoolDeadline < today) return "School deadline cannot be in the past.";
    if (!form.draftState) return "Please select the current draft state.";
    if (!form.helpFocus.trim()) return "Please describe what you want help with.";
    return null;
  };

  const buildFields = () => {
    const shared = {
      ...splitName(form.name),
      applicant_role: form.role,
      programme_interest: PROGRAMME_LABEL[form.programme] || form.programme,
      predicted_grade: form.predictedGrade,
      exam_session: form.examSession,
      application_notes: form.notes,
      signup_source: 'intensives-apply-step2',
      apply_completed: 'true',
    };
    if (form.programme === "cohort") {
      return {
        ...shared,
        subject_interest: form.subject,
        practice_history: form.practiceHistory,
        recent_marks: form.recentMarks,
        main_blocker: form.mainBlocker.join(", "),
        weekly_commitment: form.commitment,
      };
    }
    if (form.programme === "oneToOne") {
      return {
        ...shared,
        component_type: form.subject,
        school_deadline: form.schoolDeadline,
        draft_state: form.draftState,
        help_focus: form.helpFocus,
      };
    }
    return shared;
  };

  const buildTags = () => {
    const audienceTag = form.role === "student" ? "ib-student-new" : "audience-parent";
    const base = [audienceTag, 'intensives-apply-completed'];
    if (form.programme === "cohort")   return [...base, 'apply-cohort'];
    if (form.programme === "oneToOne") return [...base, 'apply-one-to-one'];
    if (form.programme === "notSure")  return [...base, 'apply-not-sure'];
    return base;
  };

  const onContinue = async () => {
    const err = validateStep1();
    if (err) { setError(err); return; }
    setError("");

    if (form.programme === "notSure") {
      setBusy(true);
      const { first_name: firstName, last_name: lastName } = splitName(form.name);
      const fields = {
        first_name: firstName,
        applicant_role: form.role,
        programme_interest: PROGRAMME_LABEL.notSure,
        predicted_grade: form.predictedGrade,
        exam_session: form.examSession,
        signup_source: 'intensives-apply-notsure',
        apply_completed: 'true',
      };
      const tags = ['apply-not-sure', 'intensives-apply-completed', form.role === 'student' ? 'ib-student-new' : 'audience-parent'];
      const result = await submitApplicationViaWorker({ email: form.email, firstName, lastName, fields, tags });
      setBusy(false);
      if (result.ok) {
        setStep(3);
      } else {
        setError("Something went wrong. Please try again or email us directly.");
      }
      return;
    }

    const { first_name: firstName1, last_name: lastName1 } = splitName(form.name);
    const step1Fields = {
      first_name: firstName1,
      applicant_role: form.role,
      programme_interest: PROGRAMME_LABEL[form.programme] || form.programme,
      subject_interest: form.subject,
      predicted_grade: form.predictedGrade,
      exam_session: form.examSession,
      signup_source: 'intensives-apply-step1',
      apply_completed: 'false',
    };
    const step1Tags = ['intensives-apply-started', form.role === 'student' ? 'ib-student-new' : 'audience-parent'];
    subscribeViaWorker({ email: form.email, firstName: firstName1, lastName: lastName1, fields: step1Fields, tags: step1Tags });
    setStep(2);
  };

  const onSubmit = async () => {
    const err = form.programme === "cohort"
      ? validateStep2Cohort()
      : validateStep2OneToOne();
    if (err) { setError(err); return; }
    setError("");
    setBusy(true);
    const fields = buildFields();
    const tags = buildTags();
    const { first_name: firstName2, last_name: lastName2 } = splitName(form.name);
    const result = await submitApplicationViaWorker({ email: form.email, firstName: firstName2, lastName: lastName2, fields, tags });
    setBusy(false);
    if (result.ok) {
      setStep(3);
    } else {
      setError("Something went wrong submitting your application. Please try again or email us directly.");
    }
  };

  if (!open) return null;

  return (
    <div className="apply-backdrop">
      <div className={`apply-modal${step === 3 && form.programme !== "cohort" ? " apf-modal-wide" : ""}`} role="dialog" aria-modal="true">
        <button className="apf-close" onClick={closeModal} aria-label="Close">
          <Icon name="x" />
        </button>
        {step === 1 && (
          <Step1 form={form} setForm={setForm} onContinue={onContinue} busy={busy} error={error} />
        )}
        {step === 2 && (
          <Step2
            form={form} setForm={setForm}
            onBack={() => { setStep(1); setError(""); }}
            onSubmit={onSubmit} busy={busy} error={error}
          />
        )}
        {step === 3 && (
          <Step3
            name={form.name} email={form.email}
            programme={form.programme}
            onClose={() => { setOpen(false); }}
          />
        )}
      </div>
    </div>
  );
};

const openApplyFlow = (detail = {}) => {
  window.dispatchEvent(new CustomEvent('intensives:openApplyFlow', { detail }));
};

Object.assign(window, { ApplyFlowModal, openApplyFlow });
