/* ========================================================================
   assign-sim.jsx — Assign a SIM journey (Story 12)
   Full-page flow: pick the kind, pick the SIM, confirm. The user is visible
   throughout. Travel hands off to the existing purchase journey.
   Loads after estate.jsx, data-pool.jsx, csv-batch.jsx.
   ======================================================================== */
const { useState: uA, useMemo: mA } = React;
const AD = window.MILO_DATA;
const AE = window.MP_ESTATE;

/* ---------- Availability ---------- */
function hasPool() { return window.pooledSims && window.pooledSims().length > 0; }
function hasIndividual() { return window.individualSims && window.individualSims().length > 0; }
function hasAltnet() { return AE && AE.altnetSims && AE.altnetSims().length > 0; }
function hasInternational() { return AE && AE.internationalSims().length > 0; }
function poolAtCap() {
  const stats = window.effectivePoolStats ? window.effectivePoolStats() : null;
  if (!stats) return false;
  const PL = window.POOL || {};
  return stats.assigned >= (PL.simMax || 80);
}

function unassignedOf(group) {
  const g = window.simGroup || ((s) => s.group || "individual");
  return AD.SIMS.filter((s) => {
    if (g(s) !== group) return false;
    if (s.status === "Terminated") return false;
    return !AD.USERS.some((u) => u.sim_ids.includes(s.id));
  });
}
const unassignedPool = () => unassignedOf("pool");
const unassignedIndividual = () => unassignedOf("individual");
const unassignedInternational = () => unassignedOf("international");
const unassignedAltnet = () => unassignedOf("altnet");

/* ---------- Kind tiles ---------- */
const KINDS = [
  { id: "individual", label: "Individual SIM", icon: "card-sim", sub: "A SIM on its own data plan." },
  { id: "altnet", label: "Alternative Network SIM", icon: "card-sim", sub: "A UK SIM on O2 or Vodafone." },
  { id: "pool", label: "Data Pool SIM", icon: "layers", sub: "A SIM sharing the data pool." },
  { id: "travel", label: "Travel eSIM", icon: "plane", sub: "Buy a travel plan for this person." },
  { id: "international", label: "International SIM", icon: "globe", sub: "A non-UK SIM." }
];

function kindAvailability(k) {
  if (k.id === "individual") {
    if (!hasIndividual() && unassignedIndividual().length === 0 && !hasPool()) return "absent";
    if (!hasIndividual()) return "absent";
    return unassignedIndividual().length > 0 ? "available" : "blocked";
  }
  if (k.id === "pool") {
    if (!hasPool()) return "absent";
    if (poolAtCap()) return "blocked_cap";
    return unassignedPool().length > 0 ? "available" : "blocked";
  }
  if (k.id === "altnet") {
    if (!hasAltnet()) return "absent";
    return unassignedAltnet().length > 0 ? "available" : "blocked";
  }
  if (k.id === "international") {
    if (!hasInternational()) return "absent";
    return unassignedInternational().length > 0 ? "available" : "blocked";
  }
  if (k.id === "travel") {
    return MP_ALLOW("sim.order") ? "available" : "absent";
  }
  return "absent";
}

function blockedReason(k, avail) {
  if (k.id === "pool" && avail === "blocked_cap") {
    const PL = window.POOL || {};
    return { text: "The data pool is at its " + (PL.simMax || 80) + " SIM limit.", action: "Add SIMs or Modify Data Pool", icon: "layers" };
  }
  if (k.id === "pool") return { text: "No pool SIMs are available to assign.", action: "Add SIMs or Modify Data Pool", icon: "layers" };
  if (k.id === "individual") return { text: "No individual SIMs are available to assign.", action: "Purchase Additional SIM Plans", icon: "package-plus" };
  if (k.id === "international") return { text: "No international SIMs are available to assign.", action: "Request International SIMs", icon: "globe" };
  if (k.id === "altnet") return { text: "No alternative network SIMs are available to assign.", action: "Request Alternative Network SIMs", icon: "card-sim" };
  return null;
}

function blockedAction(k, avail) {
  if (k.id === "pool" && avail === "blocked_cap" && window.RequestPoolChangeModal) return "pool_change";
  if (k.id === "pool") return "pool_change";
  if (k.id === "individual") return "purchase";
  if (k.id === "international" && window.RequestNewSimsModal) return "intl_request";
  if (k.id === "altnet" && window.RequestAltNetSimsModal) return "altnet_request";
  return null;
}

/* ---------- Step 1: kind choice ---------- */
function KindStep({ selected, onSelect, onAction }) {
  const tiles = KINDS.map((k) => ({ ...k, avail: kindAvailability(k) })).filter((k) => k.avail !== "absent");
  const selectable = tiles.filter((t) => t.avail === "available");
  React.useEffect(() => {
    /* Travel is a navigation, not a selection, so preselect must never fire
       it without a click — auto-navigating away from the page is hostile. */
    if (selectable.length === 1 && !selected && selectable[0].id !== "travel") onSelect(selectable[0].id);
  }, []);

  return (
    <div className={"mp-assign-kinds" + (tiles.length === 5 ? " mp-assign-kinds--5" : "")}>
      {tiles.map((t) => {
        const blocked = t.avail !== "available";
        const reason = blocked ? blockedReason(t, t.avail) : null;
        const action = blocked ? blockedAction(t, t.avail) : null;
        return (
          <div key={t.id} className={"mp-assign-kind" + (blocked ? " is-blocked" : "") + (selected === t.id ? " is-selected" : "")}
            role={blocked ? undefined : "button"} tabIndex={blocked ? undefined : 0}
            onClick={blocked ? undefined : () => onSelect(t.id)}
            onKeyDown={blocked ? undefined : (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onSelect(t.id); } }}>
            <div className="mp-assign-kind-ic"><Icon name={t.icon} size={20} /></div>
            <div className="mp-assign-kind-body">
              <div className="mp-assign-kind-name">{t.label}</div>
              <div className="mp-assign-kind-sub">{blocked ? reason.text : t.sub}</div>
              {blocked && reason.action ?
                <button type="button" className="mp-assign-kind-link" onClick={(e) => { e.stopPropagation(); onAction(action); }}>
                  <Icon name={reason.icon} size={13} />{reason.action}
                </button> : null}
            </div>
            {!blocked && selected === t.id ? <div className="mp-assign-kind-check"><Icon name="check" size={14} /></div> : null}
          </div>);
      })}
    </div>);
}

/* ---------- Step 2: pick the SIM ---------- */
function PoolContext() {
  const stats = window.effectivePoolStats ? window.effectivePoolStats() : null;
  if (!stats) return null;
  const PL = window.POOL || {};
  const name = window.poolName ? window.poolName() : PL.name;
  return (
    <div className="mp-assign-pool-ctx">
      <Icon name="layers" size={15} />
      <span><strong>{name}</strong></span>
      <span className="mp-dot-sep">·</span>
      <span>{AE.estGb(stats.used)} GB of {PL.sizeGb} GB used</span>
      <span className="mp-dot-sep">·</span>
      <span>{stats.assigned} of {PL.simMax} SIMs</span>
    </div>);
}

function SimPickList({ sims, kind, country, onCountry, onPick }) {
  const [query, setQuery] = uA("");
  const filtered = mA(() => {
    let r = sims;
    if (country) r = r.filter((s) => s.country === country);
    if (query.trim()) {
      const q = query.trim().toLowerCase();
      r = r.filter((s) => s.serial.toLowerCase().includes(q) || (s.msisdn || "").toLowerCase().includes(q) ||
        (s.network || "").toLowerCase().includes(q));
    }
    return r;
  }, [sims, query, country]);

  const countries = kind === "international" ? AE.countrySummary() : [];
  const isIntl = kind === "international";
  const isPool = kind === "pool";
  const isAlt = kind === "altnet";

  return (
    <div className="mp-assign-list">
      <div className="mp-assign-list-bar">
        <div className="mp-assign-search-wrap">
          <SearchInput value={query} onChange={setQuery} placeholder={isIntl || isAlt ? "Search by serial, number or network" : "Search by serial or number"} />
        </div>
        {isIntl && countries.length > 1 ?
          <Select value={country} onChange={onCountry} placeholder="All countries"
            options={countries.map((c) => ({ value: c.code, label: c.name }))} /> : null}
      </div>
      {filtered.length === 0 ?
        <div className="mp-assign-empty"><Empty icon="card-sim" title="No SIMs match" message="Try a different search or clear the filter." /></div> :
        <TableScroll>
          <table className="mp-table">
            <thead>
              <tr>
                <th>SIM Serial</th>
                <th>SIM Type</th>
                <th>Status</th>
                {isIntl ? <th>Country</th> : null}
                {isIntl ? <th>Network</th> : null}
                {isAlt ? <th>Network</th> : null}
                {!isPool && !isIntl ? <th>Plan</th> : null}
                {isIntl ? <th>Local Number</th> : null}
                {isIntl ? <th>Data Plan</th> : null}
                {!isIntl ? <th>Number</th> : null}
                <th></th>
              </tr>
            </thead>
            <tbody>
              {filtered.map((sim) =>
                <tr key={sim.id} className="mp-assign-tr" onClick={() => onPick(sim)}>
                  <td className="mp-mono">{sim.serial}</td>
                  <td><SimTypeBadge type={sim.sim_type} /></td>
                  <td><StatusBadge status={sim.status} sim={sim} /></td>
                  {isIntl ? <td><CountryLabel code={sim.country} /></td> : null}
                  {isIntl ? <td>{sim.network}</td> : null}
                  {isAlt ? <td>{sim.network}</td> : null}
                  {!isPool && !isIntl ? <td>{AD.PLANS[sim.plan] ? AD.PLANS[sim.plan].name : ""}</td> : null}
                  {isIntl ? <td>{sim.msisdn}</td> : null}
                  {isIntl ? <td>{sim.allowance_gb} GB</td> : null}
                  {!isIntl ? <td>{sim.msisdn && sim.msisdn !== "Data only" ? sim.msisdn : ""}</td> : null}
                  <td><Icon name="chevron-right" size={15} /></td>
                </tr>)}
            </tbody>
          </table>
        </TableScroll>}
    </div>);
}


/* ---------- Confirm modal ---------- */
function AssignConfirmModal({ sim, user, onClose, onConfirm }) {
  const isEsim = sim.sim_type === "eSIM";
  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 540 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="card-sim" size={20} /></div>
        <h3 className="mp-modal-title">Assign this SIM to {user.full_name}?</h3>
        <div className="mp-assign-confirm-pair">
          <div className="mp-assign-confirm-item">
            <div className="mp-assign-confirm-label">SIM</div>
            <div className="mp-assign-confirm-value mp-mono">{sim.serial}</div>
            {sim.msisdn && sim.msisdn !== "Data only" ? <div className="mp-assign-confirm-sub">{sim.msisdn}</div> : null}
          </div>
          <div className="mp-assign-confirm-arrow"><Icon name="arrow-right" size={16} /></div>
          <div className="mp-assign-confirm-item">
            <div className="mp-assign-confirm-label">Person</div>
            <div className="mp-assign-confirm-value">{user.full_name}</div>
            <div className="mp-assign-confirm-sub">{user.email}</div>
          </div>
        </div>
        {isEsim ?
        <div className="mp-wiz-note">
          <Icon name="mail" size={15} />
          <span>{user.full_name} will receive an activation email with the eSIM setup instructions.</span>
        </div> : null}
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" onClick={onConfirm}>Assign SIM</Button>
        </div>
      </div>
    </div>);
}

/* ---------- The page ---------- */
function AssignSimPage({ userId }) {
  const user = AD.USERS.find((u) => u.id === Number(userId));
  const ctx = window.useRoles ? window.useRoles() : null;
  const [kind, setKind] = uA(null);
  const [country, setCountry] = uA("");
  const [picked, setPicked] = uA(null);
  const [modal, setModal] = uA(null);
  React.useEffect(() => { if (window.lucide) { try { window.lucide.createIcons(); } catch (e) {} } });

  /* The ROUTE_CAPS matcher cannot match parameterised paths, so the guard
     lives here rather than in the route table. */
  if (!MP_ALLOW("sim.manage")) return (
    <>
      <PageHead title="Assign a SIM" />
      <Card><div className="mp-card-body"><Empty icon="shield-check" title="Permission denied" message="You do not have permission to assign SIMs." /></div></Card>
    </>);
  if (!user) return (
    <>
      <PageHead title="Assign a SIM" />
      <BackLink href="#/users">Back to Users</BackLink>
      <Card><div className="mp-card-body"><Empty icon="user-x" title="Person not found" /></div></Card>
    </>);

  const sims = kind === "pool" ? unassignedPool() : kind === "individual" ? unassignedIndividual() :
    kind === "international" ? unassignedInternational() : kind === "altnet" ? unassignedAltnet() : [];

  const doAssign = () => {
    if (!picked || !user) return;
    if (window.MP_USERS) window.MP_USERS.attachSim(user.id, picked.id);
    else if (user.sim_ids.indexOf(picked.id) === -1) user.sim_ids.push(picked.id);
    picked.user_id = user.id;
    if (picked.sim_type === "eSIM" && window.MP_ESIM) window.MP_ESIM.sendActivationEmail(picked.id);
    setPicked(null);
    if (ctx) ctx.toast({ kind: "ok", title: "SIM assigned", body: picked.serial + " is now assigned to " + user.full_name + "." });
    location.hash = "/users/" + user.id;
  };

  const handleAction = (action) => {
    if (action === "pool_change") setModal("pool_change");
    else if (action === "intl_request") setModal("intl_request");
    else if (action === "altnet_request") setModal("altnet_request");
    else if (action === "purchase") { if (window.DEMO_TOAST) window.DEMO_TOAST("Purchase Additional SIM Plans opens the ordering flow in the live platform."); }
  };

  return (
    <>
      <PageHead title="Assign a SIM" />
      <BackLink href={"#/users/" + user.id}>Back to {user.full_name}</BackLink>

      <Card>
        <div className="mp-card-body">
          <div className="mp-assign-user">
            <Avatar initials={user.initials} size={36} tone="mist" />
            <div>
              <div className="mp-assign-user-name">{user.full_name}</div>
              <div className="mp-assign-user-email">{user.email}</div>
            </div>
          </div>
          <h4 className="mp-assign-step-title">What type of SIM do you want to assign?</h4>
          <KindStep selected={kind} onSelect={(k) => {
            if (k === "travel") { location.hash = "/sims/travel/new?user=" + user.id; return; }
            setKind(k); setCountry(""); setPicked(null);
          }} onAction={handleAction} />

          {kind && kind !== "travel" ?
          <>
            <h4 className="mp-assign-step-title" style={{ marginTop: 32 }}>Pick the SIM</h4>
            {kind === "pool" ? <PoolContext /> : null}
            <SimPickList sims={sims} kind={kind} country={country}
              onCountry={setCountry} onPick={setPicked} />
          </> : null}
        </div>
      </Card>

      {picked ?
      <AssignConfirmModal sim={picked} user={user}
        onClose={() => setPicked(null)} onConfirm={doAssign} /> : null}

      {modal === "pool_change" && window.RequestPoolChangeModal ?
      <window.RequestPoolChangeModal currentGb={window.POOL ? window.POOL.sizeGb : 400}
        onClose={() => setModal(null)}
        onSent={() => { setModal(null); if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch to arrange it." }); }} /> : null}
      {modal === "altnet_request" && window.RequestAltNetSimsModal ?
      <window.RequestAltNetSimsModal
        onClose={() => setModal(null)}
        onSent={() => { setModal(null); if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch to arrange your SIMs." }); }} /> : null}
      {modal === "intl_request" && window.RequestNewSimsModal ?
      <window.RequestNewSimsModal
        onClose={() => setModal(null)}
        onSent={() => { setModal(null); if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch with options and pricing." }); }} /> : null}
    </>);
}

Object.assign(window, { AssignSimPage });
