/* ========================================================================
   travel-buy.jsx — Buy a travel eSIM plan (Story 4)
   Destination first, never a catalogue. Three steps, gated on sim.order.
   Route: #/sims/travel/new  (optionally ?user=<id> for the person-first entry)
   ======================================================================== */
const { useState: uB, useMemo: mB, useRef: rB } = React;
const TV = window.MP_TRAVEL;
const BD = window.MILO_DATA;
const gbpT = (n) => "£" + Number(n).toLocaleString("en-GB");

const WIZ_STEPS = ["Destination", "Plan", "Assign and Confirm"];
const PREMIUM_TIP = "Premium network access: this plan connects to the highest performing network in each country it covers, for reliable signal and faster data.";

/* ---------- Destination type-ahead ---------- */
function DestinationPicker({ tokens, onAdd, onRemove }) {
  const [q, setQ] = uB("");
  const [open, setOpen] = uB(false);
  const results = mB(() => TV.searchDestinations(q).filter((r) => !tokens.some((t) => t.id === r.id)), [q, tokens]);
  return (
    <div className="mp-dest">
      {tokens.length ?
      <div className="mp-dest-chips">
        {tokens.map((t) =>
          <span key={t.id} className={"mp-dest-chip" + (t.kind === "zone" ? " is-zone" : "")}>
            {t.flag ? <span className="mp-country-flag">{t.flag}</span> : <Icon name="globe" size={12} />}
            {t.label}
            <button type="button" aria-label={"Remove " + t.label} onClick={() => onRemove(t.id)}><Icon name="x" size={12} /></button>
          </span>)}
      </div> : null}
      <div className="mp-dest-field">
        <Icon name="search" size={16} />
        <input value={q} placeholder="Type a country, or a zone like Europe"
          onChange={(e) => { setQ(e.target.value); setOpen(true); }}
          onFocus={() => setOpen(true)} />
      </div>
      {open && q.trim() ?
      <div className="mp-dest-menu">
        {results.length === 0 ?
          <div className="mp-dest-none">Nothing matches that name.</div> :
          results.map((r) =>
            <button type="button" key={r.id} className="mp-dest-opt"
              onClick={() => { onAdd(r); setQ(""); setOpen(false); }}>
              <span className="mp-dest-opt-main">
                {r.flag ? <span className="mp-country-flag">{r.flag}</span> : <Icon name="globe" size={14} />}
                {r.label}
              </span>
              {r.kind === "zone" ? <span className="mp-dest-opt-meta">Covers {r.countries} countries</span> : null}
            </button>)}
      </div> : null}
    </div>);
}

/* ---------- Plan card ---------- */
/* The £ cost chip's tooltip pattern, reused for premium network access. */
function PremiumChip() {
  return (
    <span className="mp-premium-chip">
      Premium Network
      <span className="mp-svc-cost" tabIndex={0} aria-label={PREMIUM_TIP}>
        <Icon name="signal-high" size={13} />
        <span className="mp-cost-tip">{PREMIUM_TIP}</span>
      </span>
    </span>);
}

function TravelPlanCard({ plan, selected, onPick }) {
  return (
    <div className={"mp-tplan" + (selected ? " is-selected" : "")} role="button" tabIndex={0}
      onClick={onPick} onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onPick(); } }}>
      <div className="mp-tplan-gb">{plan.allowance_gb} GB</div>
      <div className="mp-tplan-term">{plan.type === "one_off" ?
        "Valid for " + plan.duration_days + " days from first use" :
        "Each month, on a " + plan.term_months + " month term"}</div>
      <div className="mp-tplan-price">{gbpT(plan.price)}{plan.type === "recurring" ? <span> per month</span> : null}</div>
      {plan.premium ? <PremiumChip /> : null}
      <button type="button" className={"mp-plan-btn" + (selected ? " is-selected" : "")}>{selected ? "Selected" : "Choose Plan"}</button>
    </div>);
}

/* 8 — plans grouped under their coverage, cheapest first within each group. */
function planGroups(plans, tokens) {
  const order = [];
  const by = {};
  plans.forEach((p) => { if (!by[p.area]) { by[p.area] = []; order.push(p.area); } by[p.area].push(p); });
  order.forEach((a) => by[a].sort((x, y) => x.price - y.price));
  const pos = (a) => TV.isZone(a) ? 1000 + TV.areaCountryCount(a) : tokens.findIndex((t) => t.id === a);
  order.sort((a, b) => pos(a) - pos(b));
  /* Tint by position, not by area: group 1 is always tint 1, so the page has
     the same rhythm for every destination. */
  return order.map((a, i) => ({
    area: a,
    tint: (i % 6) + 1,
    heading: TV.isZone(a) ? TV.areaLabel(a) : TV.areaLabel(a) + " Only",
    sub: TV.isZone(a) ? "Covers " + TV.areaCountryCount(a) + " countries" : "This country only",
    flag: TV.areaFlag(a),
    plans: by[a]
  }));
}

/* ---------- Confirm modal, with the processing state ---------- */
function TravelConfirmModal({ plan, user, stacking, failing, onClose, onDone }) {
  const [phase, setPhase] = uB("ask");
  const go = () => {
    setPhase("working");
    setTimeout(() => {
      if (failing) { setPhase("failed"); return; }
      onDone();
    }, 1400);
  };
  if (phase === "failed") return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 440 }}>
        <div className="mp-modal-ic mp-modal-ic--ember"><Icon name="triangle-alert" size={20} /></div>
        <h3 className="mp-modal-title">The plan could not be bought</h3>
        <p className="mp-modal-sub">Our supplier did not complete the purchase. <strong>Nothing has been charged</strong>, and no travel eSIM or plan has been created.</p>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="rotate-ccw" onClick={() => setPhase("ask")}>Retry</Button>
        </div>
      </div>
    </div>);
  return (
    <div className="mp-modal-overlay" onClick={phase === "working" ? undefined : onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="plane" size={20} /></div>
        <h3 className="mp-modal-title">{stacking ? "Add this travel plan?" : "Provision this travel eSIM?"}</h3>
        <p className="mp-modal-sub">{plan.type === "one_off" ?
          <>You will be charged <strong>{gbpT(plan.price)}</strong> for this plan. The charge applies immediately and appears on your invoice.</> :
          <><strong>{gbpT(plan.price)} per month</strong> will be added to your monthly bill for <strong>{plan.term_months} months</strong>, starting today.</>}</p>
        <p className="mp-modal-sub">{stacking ?
          <>This plan will be added to <strong>{user.full_name}</strong>'s existing travel eSIM.</> :
          <>A new travel eSIM will be created for <strong>{user.full_name}</strong> and they will receive an activation email.</>}</p>
        <p className="mp-modal-sub">{stacking ? "The plan is usually active within the hour." : "The travel eSIM is usually ready within the hour."}</p>
        <div className="mp-modal-actions">
          {phase === "working" ?
            <span className="mp-working"><span className="mp-spin-ring" />{stacking ? "Adding the plan…" : "Setting up your travel eSIM…"}</span> :
            <>
              <Button variant="secondary" onClick={onClose}>Cancel</Button>
              <Button variant="primary" onClick={go}>Confirm</Button>
            </>}
        </div>
      </div>
    </div>);
}

/* ---------- The journey ---------- */
function TravelBuyPage({ tweaks }) {
  const ctx = window.useRoles ? window.useRoles() : null;
  TV.useTravel();
  const preset = (location.hash.split("?")[1] || "").match(/user=(\d+)/);
  const [step, setStep] = uB(0);
  const [tokens, setTokens] = uB([]);
  const [kind, setKind] = uB("");
  const [ref, setRef] = uB("");
  const [user, setUser] = uB(preset ? preset[1] : "");
  const [confirming, setConfirming] = uB(false);
  const [covFilter, setCovFilter] = uB("");
  React.useEffect(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });

  const type = kind === "ongoing" ? "recurring" : "one_off";
  const plans = mB(() => (kind ? TV.matchingPlans(tokens, type) : []), [tokens, kind]);
  const anyPlans = mB(() => TV.matchingPlans(tokens, "one_off").length > 0 || TV.matchingPlans(tokens, "recurring").length > 0, [tokens]);
  const groups = mB(() => planGroups(plans, tokens), [plans, tokens]);
  const shownGroups = covFilter ? groups.filter((g) => g.area === covFilter) : groups;
  const plan = plans.find((p) => p.catalogue_ref === ref) || null;
  const person = BD.USERS.find((u) => String(u.id) === String(user)) || null;
  const existing = person ? TV.travelEsimFor(person.id) : null;
  const overlap = mB(() => {
    if (!existing || !plan) return null;
    const live = TV.plansFor(existing.id).filter(TV.isLivePlan);
    const clash = live.find((p) => TV.areaMembers(p.area).some((m) => TV.areaMembers(plan.area).indexOf(m) !== -1));
    return clash || null;
  }, [existing, plan]);

  const canNext = step === 0 ? tokens.length > 0 && !!kind && plans.length > 0 :
    step === 1 ? !!plan : !!person;

  const complete = () => {
    const made = TV.purchase({ userId: person.id, ref: plan.catalogue_ref, tokens });
    /* The eSIM has to land on the person's record, or their profile will not
       show it. This was the "worked once, not for Sarah Chen" defect. */
    if (window.MP_USERS) window.MP_USERS.attachSim(person.id, made.esim_id);
    setConfirming(false);
    try { sessionStorage.setItem("mp-travel-toast", plan.allowance_gb + " GB " + TV.areaLabel(plan.area) + " plan added for " + person.full_name + "."); } catch (e) {}
    location.hash = "/sims/" + made.esim_id;
  };

  return (
    <>
      <PageHead title="Add Travel eSIM Plan" subtitle="Tell us where someone is going and we will show the plans that cover it." />
      <BackLink href="#/sims?group=travel">Back to SIMs</BackLink>

      <div className="mp-wiz">
        <ol className="mp-wiz-steps">
          {WIZ_STEPS.map((s, i) =>
            <li key={s} className={i === step ? "is-current" : i < step ? "is-done" : ""}>
              <span className="mp-wiz-dot">{i < step ? <Icon name="check" size={12} /> : i + 1}</span>{s}
            </li>)}
        </ol>

        <Card>
          {step === 0 ?
          <div className="mp-card-body">
            <div className="mp-wiz-title">Where are they going?</div>
            <DestinationPicker tokens={tokens}
              onAdd={(t) => { setTokens(tokens.concat([t])); setRef(""); setCovFilter(""); }}
              onRemove={(id) => { setTokens(tokens.filter((t) => t.id !== id)); setRef(""); setCovFilter(""); }} />
            {tokens.length && !anyPlans ?
            <div className="mp-wiz-note mp-wiz-note--warn">
              <Icon name="triangle-alert" size={15} />
              <span>No plans cover this combination of destinations. Try removing a destination.</span>
            </div> : null}
            {tokens.length ?
            <div className="mp-wiz-block">
              <div className="mp-wiz-title">A single trip, or ongoing travel?</div>
              <div className="mp-choice-grid">
                <button type="button" className={"mp-choice" + (kind === "trip" ? " is-selected" : "")} onClick={() => { setKind("trip"); setRef(""); setCovFilter(""); }}>
                  <span className="mp-choice-name">Single Trip</span>
                  <span className="mp-choice-msg">A plan valid for 7, 15 or 30 days from first use. Charged once.</span>
                </button>
                <button type="button" className={"mp-choice" + (kind === "ongoing" ? " is-selected" : "")} onClick={() => { setKind("ongoing"); setRef(""); setCovFilter(""); }}>
                  <span className="mp-choice-name">Travels Regularly</span>
                  <span className="mp-choice-msg">A monthly allowance that renews, on a 12 month term.</span>
                </button>
              </div>
              {kind && plans.length === 0 ?
              <div className="mp-wiz-note mp-wiz-note--warn">
                <Icon name="triangle-alert" size={15} />
                <span>No plans cover this combination of destinations. Try removing a destination.</span>
              </div> : null}
            </div> : null}
          </div> : null}

          {step === 1 ?
          <div className="mp-card-body">
            <div className="mp-wiz-head">
              <div className="mp-wiz-title" style={{ marginBottom: 0 }}>Choose a plan</div>
              <span className="mp-wiz-count">{plans.length} plan{plans.length === 1 ? "" : "s"} cover {tokens.map((t) => t.label).join(", ")}</span>
            </div>
            {groups.length >= 3 ?
            <div className="mp-cov-chips">
              <button type="button" className={"mp-cov-chip" + (covFilter ? "" : " is-active")} onClick={() => setCovFilter("")}>All Coverage</button>
              {groups.map((g) =>
                <button type="button" key={g.area} className={"mp-cov-chip" + (covFilter === g.area ? " is-active" : "")}
                  onClick={() => setCovFilter(covFilter === g.area ? "" : g.area)}>{g.heading}</button>)}
            </div> : null}
            {shownGroups.map((g) =>
              <div className={"mp-plan-group mp-plan-group--t" + g.tint} key={g.area}>
                <div className="mp-plan-group-head">
                  {g.flag ? <span className="mp-country-flag">{g.flag}</span> : <Icon name="globe" size={15} />}
                  <span className="mp-plan-group-name">{g.heading}</span>
                  <span className="mp-plan-group-sub">{g.sub}</span>
                </div>
                <div className="mp-tplan-grid">
                  {g.plans.map((p) =>
                    <TravelPlanCard key={p.catalogue_ref} plan={p} selected={ref === p.catalogue_ref} onPick={() => setRef(p.catalogue_ref)} />)}
                </div>
              </div>)}
          </div> : null}

          {step === 2 ?
          <div className="mp-card-body">
            <div className="mp-wiz-title">Who is this plan for?</div>
            <div className="mp-field" style={{ maxWidth: 420 }}>
              <label className="mp-field-label">User</label>
              {window.UserSearchPicker ?
                <window.UserSearchPicker candidates={BD.USERS} value={user} onChange={setUser} /> :
                <Select value={user} onChange={setUser} placeholder="Choose a person"
                  options={BD.USERS.map((u) => ({ value: String(u.id), label: u.full_name }))} />}
              {!person ? <div className="mp-field-hint">Choose the person who is travelling.</div> : null}
              {person && !person.email ? <div className="mp-field-error">This person has no email address, so they cannot receive an activation email.</div> : null}
            </div>

            {person ?
            <div className="mp-wiz-block">
              <div className="mp-wiz-note">
                <Icon name={existing ? "layers" : "plus"} size={15} />
                <span>{existing ?
                  <>This plan will be added to <strong>{person.full_name}</strong>'s existing travel eSIM.</> :
                  <>A new travel eSIM will be created for <strong>{person.full_name}</strong> and they will receive an activation email.</>}</span>
              </div>
              {overlap ?
              <div className="mp-wiz-note mp-wiz-note--warn">
                <Icon name="triangle-alert" size={15} />
                <span>An active <strong>{TV.areaLabel(overlap.area)}</strong> plan already covers some of these destinations <a className="mp-wiz-note-link" href={"#/sims/" + overlap.esim_id}>(View Details)</a></span>
              </div> : null}
              <div className="mp-charge">
                <div className="mp-charge-label">What you will be charged</div>
                <p className="mp-charge-msg">{plan.type === "one_off" ?
                  <>You will be charged <strong>{gbpT(plan.price)}</strong> for this plan. The charge applies immediately and appears on your invoice.</> :
                  <><strong>{gbpT(plan.price)} per month</strong> will be added to your monthly bill for <strong>{plan.term_months} months</strong>, starting today.</>}</p>
                <div className="mp-kv-grid" style={{ marginTop: 14 }}>
                  <KvCell label="Coverage" value={TV.areaLabel(plan.area)} />
                  <KvCell label="Allowance" value={plan.allowance_gb + " GB"} />
                  <KvCell label={plan.type === "one_off" ? "Validity" : "Term"}
                    value={plan.type === "one_off" ? plan.duration_days + " days from first use" : plan.term_months + " months"} />
                  <KvCell label="Network" value={plan.premium ? "Premium network" : "Standard network"} />
                </div>
              </div>
            </div> : null}
          </div> : null}

          <div className="mp-wiz-foot">
            {step > 0 ?
              <Button variant="secondary" icon="arrow-left" onClick={() => setStep(step - 1)}>Back</Button> :
              <Button variant="secondary" href="#/sims?group=travel">Cancel</Button>}
            {step < 2 ?
              <Button variant="primary" iconAfter="arrow-right" className={canNext ? "" : "is-disabled"}
                onClick={canNext ? () => setStep(step + 1) : undefined}>Continue</Button> :
              <Button variant="primary" className={canNext ? "" : "is-disabled"}
                onClick={canNext ? () => setConfirming(true) : undefined}>Confirm Travel eSIM Plan</Button>}
          </div>
        </Card>
      </div>

      {confirming && plan && person ?
      <TravelConfirmModal plan={plan} user={person} stacking={!!existing}
        failing={tweaks && tweaks.travel_purchase === "fails"}
        onClose={() => setConfirming(false)} onDone={complete} /> : null}
    </>);
}

Object.assign(window, { TravelBuyPage, PremiumChip, PREMIUM_TIP });
