/* Volaire — /booking part 2: protection slot #1 (Sherpa quote), payment, confirmation, wizard shell */

/* ---------- premium frequency label ---------- */
function freqLabel(frequency, lang) {
  const map = {
    fr: { month: '/mois', year: '/an', quarter: '/trimestre', day: '/jour', 'one-time': '' },
    en: { month: '/mo', year: '/yr', quarter: '/qtr', day: '/day', 'one-time': '' },
    es: { month: '/mes', year: '/año', quarter: '/trimestre', day: '/día', 'one-time': '' },
  };
  return ((map[lang] || map.fr)[frequency]) || '';
}

/* ---------- money formatter honouring the product's currency config ---------- */
function fmtMoney(plan, amount, decimals) {
  if (amount == null || isNaN(amount)) return '';
  const n = decimals != null ? decimals : (plan.decimalsAmount != null ? plan.decimalsAmount : 2);
  const fixed = Number(amount).toFixed(n);
  const parts = fixed.split('.');
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, plan.groupSeparator || '.');
  const num = parts.length > 1 ? parts.join(plan.decimalSeparator || ',') : parts[0];
  const sym = plan.currency === 'EUR' ? '€' : (plan.currency || '');
  return plan.currencyPosition === 'suffix' ? (num + ' ' + sym) : (sym + ' ' + num);
}
function fmtAmount(plan, amount) {
  // Coverage limits: drop decimals when the amount is whole (e.g. € 50.000, € 30).
  return fmtMoney(plan, amount, Number.isInteger(Number(amount)) ? 0 : 2);
}

/* ---------- PlanCard (one priced plan, included + optional coverages) ---------- */
function PlanCard({ plan, selected, busy, onSelect, onToggleOptional }) {
  const { t, lang } = useLang();
  const included = plan.coverages.filter(function (c) { return c.included; });
  const optional = plan.coverages.filter(function (c) { return c.optional; });
  return (
    <div className={'relative rounded-xl transition-colors ' + (selected ? 'border-2 border-cobalt bg-cobalt/5' : 'border border-line bg-white hover:border-muted/40')}>
      {plan.recommended ? <span className="absolute right-4 top-4"><Badge variant="coral">{t('booking.protection.recommended')}</Badge></span> : null}

      {/* Radio header — opt in to this plan */}
      <button role="radio" aria-checked={selected} onClick={onSelect}
        className="flex w-full items-center gap-3 p-5 text-left">
        <span className={'flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 ' + (selected ? 'border-cobalt' : 'border-line')}>
          {selected ? <span className="h-2.5 w-2.5 rounded-full bg-cobalt"></span> : null}
        </span>
        <span className="min-w-0 flex-1">
          <span className="block font-bold" style={plan.color ? { color: plan.color } : undefined}>{plan.title}</span>
        </span>
        <span className="text-right">
          <span className="block text-2xl font-bold tabular-nums tracking-tight text-ink">
            {fmtMoney(plan, plan.premium)}<span className="text-sm font-medium text-muted">{freqLabel(plan.frequency, lang)}</span>
          </span>
        </span>
      </button>

      {included.length ? (
        <div className="px-5 pb-5">
          <ul className="flex flex-col gap-2.5 border-t border-line pt-4">
            {included.map(function (c) {
              return (
                <li key={c.id} className="flex items-center justify-between gap-2">
                  <span className="flex items-center gap-2.5">
                    <Icon name="check" size={16} className="shrink-0 text-success"></Icon>
                    <span className="text-sm font-medium text-ink">{c.title}</span>
                  </span>
                  {c.amount != null && c.amount > 0 ? <span className="text-sm font-bold tabular-nums text-cobalt">{fmtAmount(plan, c.amount)}</span> : null}
                </li>
              );
            })}
          </ul>

          {/* Optional add-ons — only once this plan is selected */}
          {selected && optional.length ? (
            <div className="mt-5 border-t border-line pt-4">
              <p className="text-xs font-bold uppercase tracking-wider text-muted">{t('booking.protection.optionalTitle')}</p>
              <div className="mt-3 flex flex-col gap-2">
                {optional.map(function (c) {
                  return (
                    <label key={c.id} className={'flex cursor-pointer items-center justify-between gap-3 rounded-lg border p-3 ' + (c.selected ? 'border-cobalt bg-cobalt/5' : 'border-line') + (busy ? ' opacity-60' : '')}>
                      <span className="flex items-center gap-2.5">
                        <input type="checkbox" checked={!!c.selected} disabled={busy}
                          className="h-4 w-4 rounded border-line text-cobalt focus:ring-cobalt"
                          onChange={function () { onToggleOptional(c.id); }} />
                        <span className="text-sm font-semibold text-ink">{c.title}</span>
                      </span>
                      {c.price != null ? <span className="text-sm font-bold tabular-nums text-ink">+{fmtMoney(plan, c.price)}</span> : null}
                    </label>
                  );
                })}
              </div>
            </div>
          ) : null}
        </div>
      ) : null}
    </div>
  );
}

/* ---------- ProtectionOffer (live Sherpa quote) ---------- */
function ProtectionOffer({ plans, value, busy, onSelectPlan, onSelectNone, onToggleOptional }) {
  const { t } = useLang();
  return (
    <div role="radiogroup" aria-label={t('booking.protection.stepTitle')} className="flex flex-col gap-3">
      <p className="text-sm text-muted">{t('booking.protection.intro')}</p>
      <div className={'grid gap-3 ' + (plans.length > 1 ? 'sm:grid-cols-2' : '')}>
        {plans.map(function (p) {
          return (
            <PlanCard key={p.name} plan={p} selected={value === p.name} busy={busy}
              onSelect={function () { onSelectPlan(p); }}
              onToggleOptional={onToggleOptional}></PlanCard>
          );
        })}
      </div>
      <button onClick={onSelectNone} aria-pressed={value === 'none'}
        className={'flex w-full items-center gap-3 rounded-xl p-4 text-left transition-colors ' +
          (value === 'none' ? 'border-2 border-cobalt bg-cobalt/5' : 'border border-line bg-white hover:border-muted/40 opacity-90')}>
        <span className={'flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 ' + (value === 'none' ? 'border-cobalt' : 'border-line')}>
          {value === 'none' ? <span className="h-2.5 w-2.5 rounded-full bg-cobalt"></span> : null}
        </span>
        <span>
          <span className="block font-bold text-muted">{t('booking.protection.none')}</span>
          <span className="block text-sm text-muted">{t('booking.protection.none.desc')}</span>
        </span>
      </button>
      <p className="text-xs text-muted">{t('booking.protection.precontractual')}</p>
    </div>
  );
}

/* ---------- step 5: protection — SLOT #1, wired to Sherpa /api/quote ---------- */
function Step5Protection({ draft, dispatch }) {
  const { t } = useLang();
  const [decided, setDecided] = useState(draft.protection ? draft.protection.name : null);
  const [pendingSelection, setPendingSelection] = useState(draft.protection || undefined); // undefined = no decision yet
  const [loading, setLoading] = useState(true);
  const [busy, setBusy] = useState(false); // re-quoting after optional toggle
  const [quoteId, setQuoteId] = useState(null);
  const [plans, setPlans] = useState([]);
  const [selectedOptional, setSelectedOptional] = useState(
    (draft.protection && draft.protection.selectedCoverageIds) || []
  );
  const [error, setError] = useState(null);

  // Build the protection payload stored on the booking draft for a given plan,
  // reflecting the current quote + selected optional coverages.
  function buildSelection(plan, qId, optionalIds) {
    return {
      quoteId: qId, name: plan.name, planName: plan.name, coverageType: plan.name,
      title: plan.title, premium: plan.premium, frequency: plan.frequency,
      selectedCoverageIds: optionalIds.slice(),
    };
  }

  function runQuote(optionalIds, opts) {
    opts = opts || {};
    if (opts.initial) setLoading(true); else setBusy(true);
    setError(null);
    return window.VolaireSherpa.quote(draft, optionalIds).then(function (res) {
      setQuoteId(res.quoteId);
      setPlans(res.plans || []);
      // Keep the current selection's premium/quoteId in sync after a re-quote.
      setPendingSelection(function (prev) {
        if (!prev) return prev;
        const p = (res.plans || []).find(function (x) { return x.name === prev.name; });
        return p ? buildSelection(p, res.quoteId, optionalIds) : prev;
      });
      return res;
    }).catch(function (err) {
      setError(err && err.message ? err.message : String(err));
      if (opts.initial) { setPendingSelection(null); setDecided('none'); }
      throw err;
    }).finally(function () {
      if (opts.initial) setLoading(false); else setBusy(false);
    });
  }

  useEffect(function () {
    let on = true;
    window.VolaireSherpa.quote(draft, selectedOptional).then(function (res) {
      if (!on) return;
      setQuoteId(res.quoteId); setPlans(res.plans || []); setLoading(false);
    }).catch(function (err) {
      if (!on) return;
      setError(err && err.message ? err.message : String(err));
      setPendingSelection(null); setDecided('none'); setLoading(false);
    });
    return function () { on = false; };
  }, []);

  const hasDecision = pendingSelection !== undefined;

  // Selecting / changing protection updates the booking draft immediately so the
  // summary rail (basket) on the right reflects it live — no need to hit Continue.
  function selectPlan(plan) {
    const sel = buildSelection(plan, quoteId, selectedOptional);
    setDecided(plan.name);
    setPendingSelection(sel);
    dispatch({ type: 'ATTACH_PROTECTION', protection: sel });
  }
  function selectNone() {
    setDecided('none');
    setPendingSelection(null);
    dispatch({ type: 'REMOVE_PROTECTION' });
  }
  function toggleOptional(id) {
    const next = selectedOptional.indexOf(id) === -1
      ? selectedOptional.concat([id])
      : selectedOptional.filter(function (x) { return x !== id; });
    setSelectedOptional(next);
    runQuote(next).then(function (res) {
      if (!decided || decided === 'none') return;
      const p = (res.plans || []).find(function (x) { return x.name === decided; });
      if (p) dispatch({ type: 'ATTACH_PROTECTION', protection: buildSelection(p, res.quoteId, next) });
    }).catch(function () { /* surfaced via error state */ });
  }
  function commit() {
    // Draft already carries the live selection; just advance.
    if (pendingSelection) dispatch({ type: 'ATTACH_PROTECTION', protection: pendingSelection });
    else dispatch({ type: 'REMOVE_PROTECTION' });
    dispatch({ type: 'SET_STEP', step: 6 });
  }

  return (
    <div>
      <h1 className="text-2xl font-bold tracking-tight text-ink">{t('booking.protection.stepTitle')}</h1>
      <section id="protection-embed-slot" className="mt-4 min-h-[420px] rounded-xl border border-line bg-white p-6">
        {loading ? (
          <div className="flex min-h-[360px] items-center justify-center" role="status" aria-label="Chargement">
            <span className="h-8 w-8 animate-spin rounded-full border-2 border-line border-t-cobalt"></span>
          </div>
        ) : error && !plans.length ? (
          <div className="flex min-h-[360px] flex-col items-center justify-center gap-3 text-center">
            <Icon name="info" size={28} className="text-muted/60"></Icon>
            <p className="max-w-md text-sm text-muted">{t('booking.protection.unavailable')}</p>
          </div>
        ) : (
          <ProtectionOffer plans={plans} value={decided} busy={busy}
            onSelectPlan={selectPlan} onSelectNone={selectNone} onToggleOptional={toggleOptional}></ProtectionOffer>
        )}
      </section>
      <StepFooter onBack={function () { dispatch({ type: 'SET_STEP', step: 4 }); }}
        onNext={commit} nextDisabled={!hasDecision || loading}></StepFooter>
    </div>
  );
}

/* ---------- step 6: payment ---------- */
function Step6Payment({ draft, dispatch }) {
  const { t, lang } = useLang();
  const [method, setMethod] = useState(draft.payment || 'card');
  const [terms, setTerms] = useState(false);
  const [privacy, setPrivacy] = useState(false);
  const [card, setCard] = useState({ number: '', expiry: '', cvc: '', holder: '' });
  const [processing, setProcessing] = useState(false);
  const total = bookingTotal(draft);
  const canPay = terms && privacy && !processing && (method !== 'card' || (card.number && card.expiry && card.cvc && card.holder));

  function pay() {
    if (!canPay) return;
    setProcessing(true);
    // Flight order payment (demo) runs first; the travel-protection policy is
    // then bound separately via Sherpa, mirroring the embed's own bind step.
    L.mockAsync(1500).then(function () {
      // Sign the customer in before binding so the policy's externalClientId
      // matches the one the customer portal uses later (session email).
      if (draft.passenger.createAccount || !L.getSession()) {
        L.setSession({ firstName: draft.passenger.firstName || 'Camille', lastName: draft.passenger.lastName || 'Laurent', email: draft.passenger.email });
      }
      const bindProtection = (draft.protection && draft.protection.quoteId)
        ? window.VolaireSherpa.buy(draft, draft.protection).then(function (res) {
            return Object.assign({}, draft.protection, { policyId: res.policyId, policyNumber: res.policyNumber });
          }).catch(function () {
            showToast(t('booking.protection.bindFailed'));
            return draft.protection; // keep flight booking; protection retry handled in portal
          })
        : Promise.resolve(draft.protection || undefined);

      bindProtection.then(function (protection) {
        const pnr = L.generatePNR();
        const booking = {
          pnr: pnr, status: 'confirmed', tripType: draft.tripType,
          outbound: draft.outbound, inbound: draft.inbound || undefined,
          fareFamily: draft.fareFamily, passenger: draft.passenger,
          seats: draft.seats, extras: draft.extras,
          protection: protection || undefined,
          total: total, bookedAt: new Date().toISOString(),
        };
        L.saveTrip(booking);
        dispatch({ type: 'SET_PAYMENT', payload: { payment: method, termsAccepted: true, privacyAccepted: true } });
        dispatch({ type: 'CONFIRM_BOOKING', pnr: pnr });
        window.location.hash = '/booking?step=success';
        window.scrollTo(0, 0);
      });
    });
  }

  const methods = [
    { v: 'card', l: t('booking.payment.card'), icon: 'card' },
    { v: 'paypal', l: t('booking.payment.paypal'), icon: 'wallet' },
    { v: 'apple-pay', l: t('booking.payment.applePay'), icon: 'phone' },
  ];
  return (
    <div>
      <h1 className="text-2xl font-bold tracking-tight text-ink">{t('booking.payment.title')}</h1>
      <p className="mt-1 text-sm text-muted">{t('booking.payment.note')}</p>
      <div className="mt-4 rounded-xl border border-line bg-white p-5">
        <div role="radiogroup" aria-label={t('booking.payment.title')} className="grid grid-cols-1 gap-2 sm:grid-cols-3">
          {methods.map(function (m) {
            const on = method === m.v;
            return (
              <button key={m.v} role="radio" aria-checked={on}
                className={'flex items-center justify-center gap-2 rounded-lg border px-4 py-3 text-sm font-semibold ' + (on ? 'border-2 border-cobalt bg-cobalt/5 text-cobalt' : 'border-line text-ink hover:border-cobalt/50')}
                onClick={function () { setMethod(m.v); }}>
                <Icon name={m.icon} size={18}></Icon>{m.l}
              </button>
            );
          })}
        </div>
        {method === 'card' ? (
          <div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-4">
            <Field label={t('booking.payment.cardNumber')} className="sm:col-span-4">
              <input className={inputCls + ' tabular-nums'} inputMode="numeric" placeholder="4970 10•• •••• ••••" value={card.number}
                onChange={function (e) { setCard(Object.assign({}, card, { number: e.target.value })); }} />
            </Field>
            <Field label={t('booking.payment.expiry')} className="sm:col-span-1">
              <input className={inputCls + ' tabular-nums'} placeholder="MM/AA" value={card.expiry}
                onChange={function (e) { setCard(Object.assign({}, card, { expiry: e.target.value })); }} />
            </Field>
            <Field label={t('booking.payment.cvc')} className="sm:col-span-1">
              <input className={inputCls + ' tabular-nums'} inputMode="numeric" placeholder="123" value={card.cvc}
                onChange={function (e) { setCard(Object.assign({}, card, { cvc: e.target.value })); }} />
            </Field>
            <Field label={t('booking.payment.holder')} className="sm:col-span-2">
              <input className={inputCls} placeholder="C. LAURENT" value={card.holder}
                onChange={function (e) { setCard(Object.assign({}, card, { holder: e.target.value })); }} />
            </Field>
          </div>
        ) : (
          <p className="mt-4 rounded-lg bg-page px-4 py-3 text-sm text-muted">{method === 'paypal' ? 'PayPal' : 'Apple Pay'} — {lang === 'en' ? 'visual demo' : lang === 'es' ? 'demo visual' : 'démo visuelle'}.</p>
        )}
        <div className="mt-5 flex flex-col gap-2.5 border-t border-line pt-4">
          <label className="flex cursor-pointer items-start gap-2.5 text-sm text-ink">
            <input type="checkbox" checked={terms} required className="mt-0.5 h-4 w-4 rounded border-line text-cobalt focus:ring-cobalt"
              onChange={function (e) { setTerms(e.target.checked); }} />
            <span>{t('booking.payment.terms')} <Link to="/about" className="text-cobalt underline">(CGV)</Link></span>
          </label>
          <label className="flex cursor-pointer items-start gap-2.5 text-sm text-ink">
            <input type="checkbox" checked={privacy} required className="mt-0.5 h-4 w-4 rounded border-line text-cobalt focus:ring-cobalt"
              onChange={function (e) { setPrivacy(e.target.checked); }} />
            <span>{t('booking.payment.privacy')} <Link to="/about" className="text-cobalt underline">→</Link></span>
          </label>
        </div>
        {draft.protection ? (
          <p className="mt-3 flex items-center gap-2 rounded-lg bg-page px-4 py-3 text-sm text-muted">
            <Icon name="shield" size={16} className="shrink-0 text-success"></Icon>
            {t('booking.summary.protection')}{draft.protection.title ? ' · ' + draft.protection.title : ''} : {L.fmtEUR(draft.protection.premium)} — {t('booking.payment.protectionIncluded')}
          </p>
        ) : null}
        <div className="mt-5 flex flex-col items-stretch gap-2 sm:flex-row sm:items-center sm:justify-between">
          <span className="flex items-center gap-1.5 text-xs text-muted"><Icon name="lock" size={14}></Icon>{t('booking.payment.secure')}</span>
          <button onClick={pay} disabled={!canPay}
            className="flex items-center justify-center gap-2 rounded-lg bg-cobalt px-8 py-3.5 text-sm font-bold text-white hover:bg-cobaltDark disabled:cursor-not-allowed disabled:opacity-40">
            {processing ? <span className="h-4 w-4 animate-spin rounded-full border-2 border-white/40 border-t-white"></span> : null}
            {processing ? t('booking.payment.processing') : t('booking.payment.cta') + ' ' + L.fmtEUR(total)}
          </button>
        </div>
      </div>
      <StepFooter onBack={function () { dispatch({ type: 'SET_STEP', step: 5 }); }} onNext={pay} nextDisabled={!canPay}
        nextLabel={t('booking.payment.cta') + ' ' + L.fmtEUR(total)}></StepFooter>
    </div>
  );
}

/* ---------- confirmation ---------- */
function Confirmation({ draft, dispatch }) {
  const { t, lang } = useLang();
  const trip = L.findTrip(draft.pnr) || null;
  if (!trip) return null;
  return (
    <div className="mx-auto max-w-2xl">
      <div className="rounded-xl border border-line bg-white p-6 text-center sm:p-8">
        <span className="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-success/10 text-success"><Icon name="check" size={28}></Icon></span>
        <h1 className="mt-4 text-2xl font-bold tracking-tight text-ink">{t('booking.confirm.title')}</h1>
        <p className="mt-2 text-sm text-muted">{t('booking.confirm.reference')}</p>
        <p className="text-3xl font-bold tabular-nums tracking-widest text-cobalt">{trip.pnr}</p>
        <div className="mt-5 flex flex-col gap-2 text-left">
          <FlightRecapStatic f={trip.outbound} seat={(trip.seats.find(function (s) { return s.flightId === 'out'; }) || {}).seat} lang={lang}></FlightRecapStatic>
          {trip.inbound ? <FlightRecapStatic f={trip.inbound} seat={(trip.seats.find(function (s) { return s.flightId === 'in'; }) || {}).seat} lang={lang}></FlightRecapStatic> : null}
        </div>
        <p className="mt-4 text-sm text-muted">{t('booking.confirm.emailNote')} <span className="font-semibold text-ink">{trip.passenger.email || 'camille.laurent@example.fr'}</span></p>
        <p className="mt-1 flex items-center justify-center gap-1.5 text-xs font-medium text-success"><Icon name="check" size={14}></Icon>{t('booking.confirm.freeCancel')}</p>
        {trip.protection ? (
          <p className="mt-4 flex items-start gap-2 rounded-lg bg-cobalt/5 px-4 py-3 text-left text-sm text-ink">
            <Icon name="shield" size={16} className="mt-0.5 shrink-0 text-cobalt"></Icon>
            {t('booking.confirm.protectionNote')}
          </p>
        ) : null}
        <div className="mt-6 flex flex-col justify-center gap-2 sm:flex-row">
          <button onClick={function () { const pnr = trip.pnr; dispatch({ type: 'RESET' }); window.VolaireDraft.clearDraft(); navigate('/account/trips/' + pnr); }}
            className="rounded-lg bg-cobalt px-6 py-3 text-sm font-bold text-white hover:bg-cobaltDark">{t('booking.confirm.viewTrip')}</button>
          <button onClick={function () { dispatch({ type: 'RESET' }); window.VolaireDraft.clearDraft(); navigate('/'); }}
            className="rounded-lg border border-line px-6 py-3 text-sm font-semibold text-ink hover:border-cobalt">{t('booking.confirm.backHome')}</button>
        </div>
      </div>
    </div>
  );
}
function FlightRecapStatic({ f, seat, lang }) {
  return (
    <div className="flex items-center justify-between gap-3 rounded-lg border border-line bg-page/60 px-4 py-3">
      <span className="text-sm font-bold tabular-nums text-ink">{L.fmtTime(f.departTime)} {f.origin} → {L.fmtTime(f.arriveTime)} {f.destination}</span>
      <span className="text-xs capitalize text-muted">{L.fmtDateShort(f.departTime, lang)} · {f.flightNumber}{seat ? ' · ' + seat : ''}</span>
    </div>
  );
}

/* ---------- wizard shell ---------- */
function BookingPage() {
  const { t } = useLang();
  const route = useRoute();
  const [draft, dispatch] = useBookingDraft();
  const liveRef = useRef(null);
  const isSuccess = draft.step === 'success' && route.query.step === 'success';

  useEffect(function () {
    if (liveRef.current) liveRef.current.textContent = typeof draft.step === 'number' ? t(STEP_KEYS[draft.step - 1]) : '';
  }, [draft.step]);

  if (!draft.outbound) {
    return (
      <main className="mx-auto max-w-6xl px-4 py-16 text-center">
        <span className="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-cobalt/10 text-cobalt"><Icon name="plane" size={26}></Icon></span>
        <h1 className="mt-4 text-2xl font-bold tracking-tight text-ink">{t('booking.empty.title')}</h1>
        <p className="mt-2 text-sm text-muted">{t('booking.empty.body')}</p>
        <Link to="/" className="mt-5 inline-block rounded-lg bg-cobalt px-6 py-3 text-sm font-bold text-white hover:bg-cobaltDark">{t('booking.empty.cta')}</Link>
      </main>
    );
  }

  if (draft.step === 'success' || isSuccess) {
    return <main className="mx-auto max-w-6xl px-4 py-10"><Confirmation draft={draft} dispatch={dispatch}></Confirmation></main>;
  }

  const steps = { 1: Step1Flights, 2: Step2Passenger, 3: Step3Seats, 4: Step4Options, 5: Step5Protection, 6: Step6Payment };
  const StepComp = steps[draft.step] || Step1Flights;

  return (
    <main className="mx-auto max-w-6xl px-4 pb-32 pt-6 lg:pb-10">
      <span className="sr-only" aria-live="polite" ref={liveRef}></span>
      <div className="sticky top-[105px] z-30 -mx-1 bg-page/95 px-1 py-2 backdrop-blur md:top-[118px]">
        <div className="rounded-xl border border-line bg-white px-4 py-2.5">
          <ProgressBar step={draft.step} onJump={function (n) { dispatch({ type: 'SET_STEP', step: n }); }}></ProgressBar>
        </div>
      </div>
      <div className="mt-5 grid gap-6 lg:grid-cols-[1fr_320px]">
        <div data-screen-label={'Booking step ' + draft.step}>
          <StepComp draft={draft} dispatch={dispatch}></StepComp>
        </div>
        <SummaryRail draft={draft}></SummaryRail>
      </div>
    </main>
  );
}

Object.assign(window, { ProtectionOffer, PlanCard, freqLabel, fmtMoney, fmtAmount, Step5Protection, Step6Payment, Confirmation, BookingPage, FlightRecapStatic });
