/* ========================================================================
   data-pool.jsx — Data Pools proof-of-concept (grouped SIM Management)
   The estate is split into a shared Data Pool and Individual SIMs.
   SIM Management shows: universal search + scope toggle, then one
   collapsible group card per bucket (pool / individual), each with its
   own search + status filter. Built to extend to multiple pools later.
   ======================================================================== */
const { useState: uP, useMemo: mP } = React;
const PD = window.MILO_DATA;

/* ---------- Pool model (single shared allowance) ---------- */
/* The pool is sized for the estate that shares it, and every date is computed
   from today so the demo reads correctly in any month. */
const POOL_NOW = new Date();
const POOL_RESET = new Date(POOL_NOW.getFullYear(), POOL_NOW.getMonth() + 1, 1);
const POOL = {
  name: "Data Pool",
  sizeGb: 400,
  simMax: 80,
  resetDate: POOL_RESET.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" }),
  resetDateShort: POOL_RESET.toLocaleDateString("en-GB", { day: "numeric", month: "short", year: "numeric" }),
  resetISO: POOL_RESET.toISOString().slice(0, 10)
};
const poolPlanLabel = () => POOL.sizeGb + " GB Pool";
function poolName() {
  try { return localStorage.getItem("mp_pool_name") || POOL.name; } catch (e) { return POOL.name; }
}
/* One generator: simBundleType in sim-manage.jsx. */
function poolBundleType(sim) { return window.simBundleType ? window.simBundleType(sim) : "Voice + Data"; }

/* SIMs NOT in the pool — on their own plans rather than sharing an allowance. */
const INDIVIDUAL_SIM_IDS = new Set([2, 6, 14, 15, 16]);
/* Estate group of a SIM. UK SIMs carry no group field, so pool/individual is
   derived; international and travel SIMs declare their group in the data. */
const simGroup = (s) => s && s.group ? s.group : INDIVIDUAL_SIM_IDS.has(s.id) ? "individual" : "pool";
const groupById = (id) => simGroup(PD.SIMS.find((s) => s.id === id));
const isPooled = (id) => groupById(id) === "pool";
const isEstateGroup = (s) => simGroup(s) === "international" || simGroup(s) === "travel";
const pooledSims = () => PD.SIMS.filter((s) => simGroup(s) === "pool");
const individualSims = () => PD.SIMS.filter((s) => simGroup(s) === "individual");
const altnetSims = () => PD.SIMS.filter((s) => simGroup(s) === "altnet");
const estStatusOf = (s) => window.MP_REQ ? window.MP_REQ.estStatus(s) : s.status;

/* Format GB without a trailing .0 (250.0 → 250, 193.6 → 193.6). */
const fmtGb = (n) => (Math.round(n * 10) % 10 === 0 ? String(Math.round(n)) : n.toFixed(1));

/* Live pool figures derived from the pooled SIMs only. */
function poolStats() {
  const sims = pooledSims();
  const assigned = sims.filter((s) => s.status !== "Terminated").length;
  const used = sims.reduce((a, s) => a + s.used, 0);
  const pct = Math.round(used / POOL.sizeGb * 100);
  const remaining = Math.max(0, POOL.sizeGb - used);
  return { assigned, used, pct, remaining };
}

/* Expose to the forked SIM-detail file (rendered later). */
window.MP_POOL = { name: POOL.name, sizeGb: POOL.sizeGb, label: poolPlanLabel(), resetDate: POOL.resetDate, resetDateShort: POOL.resetDateShort, isPooled };

/* ---------- Reset proximity ---------- */
function daysUntil(iso) {
  const now = new Date();
  const d = new Date(iso + "T00:00:00");
  return Math.max(0, Math.ceil((d - now) / 86400000));
}

/* Effective pool figures. A demo tweak (pool_usage_demo) lets the user
   preview the threshold states without changing the underlying SIM data. */
function effectivePoolStats(tweaks) {
  if (!tweaks) tweaks = window.MP_TWEAKS || {};
  const base = poolStats();
  let demo = tweaks && tweaks.pool_usage_demo;
  if (!demo || demo === "live") {
    try {demo = localStorage.getItem("mp_pool_demo") || demo;} catch (e) {}
  }
  if (!demo || demo === "live") return base;
  const pct = parseInt(demo, 10);
  const used = +(POOL.sizeGb * pct / 100).toFixed(1);
  return { ...base, used, pct, remaining: Math.max(0, POOL.sizeGb - used) };
}

/* Escalating status thresholds. Returns null below 80%. */
function poolStatusLevel(pct, remaining, context) {
  const reset = POOL.resetDate;
  const reviewCta = context === "sims" ? null : { label: "Request Upgrade", href: "#/subscriptions" };
  const upCta = { label: "Request Upgrade", href: "#/subscriptions" };

  if (pct >= 100) return {
    tone: "blocked", icon: "octagon-x",
    title: "The data pool is used up and data is blocked",
    msg: <>All <strong>{POOL.sizeGb} GB</strong> of the shared pool has been used. Data is now blocked across all SIMs until the pool resets on <strong>{reset}</strong>.</>,
    cta: upCta };

  if (pct >= 95) return {
    tone: "critical", icon: "triangle-alert",
    title: "Over 95% of data pool used",
    msg: <>Once the pool is depleted, data will be blocked for all SIMs until the allowance resets on <strong>{reset}</strong>.</>,
    cta: upCta };

  if (pct >= 90) return {
    tone: "warn", icon: "triangle-alert",
    title: "Over 90% of data pool used",
    msg: <>The shared pool is nearly used up. The data allowance resets on <strong>{reset}</strong>.</>,
    cta: reviewCta };

  if (pct >= 80) return {
    tone: "caution", icon: "info",
    title: "Over 80% of data pool used",
    msg: <>The shared data allowance resets on <strong>{reset}</strong>.</>,
    cta: reviewCta };

  return null;
}

/* Banner strip — Overview dashboard + under the Data Pool card. */
function PoolStatusBanner({ tweaks, context }) {
  const { pct, remaining } = effectivePoolStats(tweaks);
  const level = poolStatusLevel(pct, remaining, context);
  if (!level) return null;
  return (
    <div className={"mp-pool-banner mp-pool-banner--" + level.tone} role="status">
      <div className="mp-pool-banner-ic"><Icon name={level.icon} size={20} /></div>
      <div className="mp-pool-banner-body">
        <div className="mp-pool-banner-title">{level.title}</div>
        <div className="mp-pool-banner-msg">{level.msg}</div>
      </div>
      {level.cta ?
      <a className="mp-pool-banner-cta" href={level.cta.href}>{level.cta.label}<Icon name="arrow-right" size={15} /></a> :
      null}
    </div>);

}

/* ---------- Shared SIM table (used by both groups + universal results) ----------
   variant: "pool" | "individual" | "mixed" (mixed adds a Group column). */
function SimPlanCell({ sim }) {
  if (isEstateGroup(sim)) return <span>{sim.allowance_gb} GB</span>;
  if (isPooled(sim.id)) return <span className="mp-pool-pill"><Icon name="layers" size={12} />{poolPlanLabel()}</span>;
  return <span>{PD.PLANS[sim.plan].data}</span>;
}
function SimDataUsedCell({ sim }) {
  if (isEstateGroup(sim)) {
    const E = window.MP_ESTATE;
    return (
      <div className="mp-sim-data">
        <b>{fmtGb(sim.used)} GB</b>
        <span>of {sim.allowance_gb} GB · {E.monthLabel}</span>
      </div>);
  }
  const plan = PD.PLANS[sim.plan];
  const pooled = isPooled(sim.id);
  const pct = pooled ? Math.round(sim.used / POOL.sizeGb * 100) : plan.limit_gb ? Math.round(sim.used / plan.limit_gb * 100) : null;
  const sub = pooled ? pct + "% of pool" : plan.limit_gb ? pct + "% of " + plan.data : "Unlimited plan";
  return (
    <div className="mp-sim-data">
      <b>{fmtGb(sim.used)} GB</b>
      {pct != null ? <span className="mp-sim-data-bar"><span style={{ width: Math.min(100, pct) + "%" }} /></span> : null}
      <span>{sub}</span>
    </div>);
}
function simActions(sim, user) {
  /* Alternative network SIMs are changed through requests, like international. */
  if (isEstateGroup(sim) || simGroup(sim) === "altnet") return [{ label: "View Details", href: "#/sims/" + sim.id }];
  if (!MP_ALLOW("sim.manage")) return [{ label: "View Details", href: "#/sims/" + sim.id }];
  return [
  { label: "View Details", href: "#/sims/" + sim.id },
  { label: user ? "Edit User" : "Assign User", href: "#/sims/" + sim.id + "/edit" },
  ...(sim.status === "Active" ? [{ label: "Transfer Your Number", href: "#/sims/" + sim.id + "/transfer" }] : []),
  ...(window.MP_ESIM && window.MP_ESIM.isReady(sim) ? [{ label: "Install eSIM", href: "#/sims/" + sim.id }] : []),
  ...(sim.status === "For Activation" ? [{ label: "Activate SIM", onClick: () => { location.hash = "/sims/" + sim.id; } }] : []),
  ...(sim.status === "Suspended" ? [{ label: "Reactivate SIM", onClick: () => { location.hash = "/sims/" + sim.id; } }] : []),
  ...(sim.status === "Terminated" ? [{ note: "SIM is terminated, can't perform any action." }] : [])];
}

/* Group chip in mixed search results — one chip per estate group. */
function GroupChip({ sim }) {
  return <GroupKindChip kind={simGroup(sim)} />;
}
/* Chip by group kind — also used for the SIMs column on User Management. */
function GroupKindChip({ kind }) {
  if (kind === "pool") return <span className="mp-group-chip"><Icon name="layers" size={11} />{poolName()}</span>;
  if (kind === "individual") return <span className="mp-group-chip mp-group-chip--ind"><Icon name="card-sim" size={11} />Individual</span>;
  if (kind === "altnet") return <span className="mp-group-chip mp-group-chip--ind"><Icon name="card-sim" size={11} />Other Network</span>;
  if (kind === "uk") return <span className="mp-group-chip mp-group-chip--ind"><Icon name="card-sim" size={11} />UK</span>;
  if (kind === "international") return <span className="mp-group-chip mp-group-chip--intl"><Icon name="globe" size={11} />International</span>;
  return <span className="mp-group-chip mp-group-chip--travel"><Icon name="plane" size={11} />Travel</span>;
}

function SimTable({ rows, variant = "pool", perPage = 10, bulk }) {
  const [sortField, setSortField] = uP("serial_number");
  const [sortDir, setSortDir] = uP("asc");
  const [page, setPage] = uP(1);
  const handleSort = (f) => {if (sortField === f) setSortDir(sortDir === "asc" ? "desc" : "asc");else {setSortField(f);setSortDir("asc");}};

  const sorted = mP(() => {
    const r = rows.slice();
    const key = (s) => sortField === "serial_number" ? s.serial : sortField === "sim_type" ? s.sim_type : sortField === "assigned_user" ? (PD.USERS.find((u) => u.sim_ids.includes(s.id)) || {}).full_name || "" :
    sortField === "phone_number" ? s.msisdn : sortField === "data_plan" ? (isPooled(s.id) ? poolPlanLabel() : PD.PLANS[s.plan].name) : sortField === "group" ? simGroup(s) :
    sortField === "network" ? s.network || "" :
    sortField === "data_used" ? s.used :
    sortField === "pct_used" ? (s.used / ((PD.PLANS[s.plan] || {}).limit_gb || 999)) :
    sortField === "monthly_spend" ? simMonthly(s) :
    s.status;
    const dir = sortDir === "asc" ? 1 : -1;
    r.sort((a, b) => {const A = key(a), B = key(b);return A > B ? dir : A < B ? -dir : 0;});
    return r;
  }, [rows, sortField, sortDir]);

  const totalPages = Math.ceil(sorted.length / perPage) || 1;
  const safePage = Math.min(page, totalPages);
  const pageRows = sorted.slice((safePage - 1) * perPage, safePage * perPage);
  /* Alternative network SIMs read as individual SIMs plus a Network column. */
  const indLike = variant === "individual" || variant === "altnet";
  const isAlt = variant === "altnet";


  if (rows.length === 0) return (
    <div className="mp-empty" style={{ padding: "26px 0" }}>
      <div className="mp-empty-title">No SIMs match</div>
      <div className="mp-empty-msg">Try a different search or clear the filters.</div>
    </div>);

  return (
    <>
      <TableScroll>
        <table className="mp-table">
          <thead>
            <tr>
              {bulk && bulk.on ? <window.BulkCheckHead bulk={bulk} pageRows={pageRows} /> : null}
              <th><SortHeader field="serial_number" sortField={sortField} sortDir={sortDir} onSort={handleSort}>SIM Serial</SortHeader></th>
              {isAlt ? <th><SortHeader field="network" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Network</SortHeader></th> : null}
              <th><SortHeader field="sim_type" sortField={sortField} sortDir={sortDir} onSort={handleSort}>SIM Type</SortHeader></th>
              <th><SortHeader field="status" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Status</SortHeader></th>
              <th><SortHeader field="assigned_user" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Assigned User</SortHeader></th>
              <th><SortHeader field="phone_number" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Assigned Number</SortHeader></th>
              {variant === "mixed" ? <th><SortHeader field="group" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Group</SortHeader></th> : null}
              {variant !== "pool" ? <th><SortHeader field="data_plan" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Data Plan</SortHeader></th> : null}
              {indLike ?
              <>
                <th><SortHeader field="data_used" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Data Usage</SortHeader></th>
                <th><SortHeader field="pct_used" sortField={sortField} sortDir={sortDir} onSort={handleSort}>% Used</SortHeader></th>
                <th><SortHeader field="monthly_spend" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Monthly Spend</SortHeader></th>
              </> :
              <th><SortHeader field="data_used" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Data Used</SortHeader></th>}
              <th></th>
            </tr>
          </thead>
          <tbody>
            {pageRows.map((sim) => {
              const user = PD.USERS.find((u) => u.sim_ids.includes(sim.id));
              return (
                <tr key={sim.id}>
                  {bulk && bulk.on ? <window.BulkCheckCell bulk={bulk} sim={sim} /> : null}
                  <td className="mp-mono">{sim.serial}</td>
                  {isAlt ? <td>{sim.network}</td> : null}
                  <td><SimTypeBadge type={sim.sim_type} /></td>
                  <td>
                    <span className="mp-status-cell">
                      <StatusBadge status={isAlt ? estStatusOf(sim) : sim.status} sim={sim} />
                      {isAlt && window.RequestRowChip ? <window.RequestRowChip sim={sim} /> : null}
                      {window.AssignmentPendingChip ? <window.AssignmentPendingChip sim={sim} /> : null}
                    </span>
                  </td>
                  <td>{user ? <a href={"#/users/" + user.id} className="mp-assigned"><Avatar initials={user.initials} size={26} tone="mist" /><span>{user.full_name}</span></a> : <span style={{ color: "var(--fg-3)" }}>—</span>}</td>
                  <td className="mp-mono">{sim.msisdn || ""}</td>
                  {variant === "mixed" ? <td><GroupChip sim={sim} /></td> : null}
                  {variant !== "pool" ? <td><SimPlanCell sim={sim} /></td> : null}
                  {indLike ?
                  <>
                    <td>{fmtGb(sim.used)} GB</td>
                    <td>{PD.PLANS[sim.plan].limit_gb ? <PctIndicator pct={sim.used / PD.PLANS[sim.plan].limit_gb * 100} /> : <span className="mp-na">N/A</span>}</td>
                    <td style={{ fontWeight: 700 }}>£{simMonthly(sim).toFixed(2)}</td>
                  </> :
                  <td><SimDataUsedCell sim={sim} /></td>}
                  <td><ActionsMenu items={simActions(sim, user)} /></td>
                </tr>);
            })}
          </tbody>
        </table>
        </TableScroll>
      {totalPages > 1 ?
      <div style={{ padding: "12px 16px" }}>
          <Pagination page={safePage} totalPages={totalPages} onChange={setPage} />
        </div> : null}
    </>);
}

/* Search + status filter + table, scoped to one group's rows. */
const STATUS_OPTIONS = [
{ value: "", label: "All statuses" },
{ value: "Active", label: "Active" },
{ value: "Activated", label: "Activated" },
{ value: "For Activation", label: "For Activation" },
{ value: "Suspended", label: "Suspended" },
{ value: "Terminated", label: "Terminated" }];

function filterSims(rows, query, status, assignment) {
  let r = rows;
  if (query) {
    const q = query.toLowerCase();
    r = r.filter((s) =>
    s.serial.toLowerCase().includes(q) || (s.msisdn || "").toLowerCase().includes(q) ||
    (PD.USERS.find((u) => u.sim_ids.includes(s.id)) || {}).full_name?.toLowerCase().includes(q));
  }
  if (status) r = r.filter((s) => estStatusOf(s) === status);
  if (assignment) r = r.filter((s) => {
    const has = !!PD.USERS.find((u) => u.sim_ids.includes(s.id));
    return assignment === "assigned" ? has : !has;
  });
  return r;
}

/* Deep links from other pages:
   #/sims?assignment=unassigned
   #/sims?group=international&country=FR
   #/sims?group=travel
   A bare #/sims resets all of it. */
function hashParams() {
  const q = location.hash.split("?")[1] || "";
  const p = new URLSearchParams(q);
  return {
    assignment: p.get("assignment") === "unassigned" ? "unassigned" : "",
    group: p.get("group") || "",
    country: p.get("country") || "",
    status: p.get("status") || ""
  };
}

function GroupSimSection({ rows, variant, searchPlaceholder, initialAssignment, initialStatus }) {
  const [query, setQuery] = uP("");
  const [status, setStatus] = uP(initialStatus || "");
  const [assignment, setAssignment] = uP(initialAssignment || "");
  const filtered = mP(() => filterSims(rows, query, status, assignment), [rows, query, status, assignment]);
  const bulk = window.useBulkScope("group-" + variant, filtered, variant);
  return (
    <div className="mp-group-sims">
      <div className="mp-mem-filters">
        <SearchInput value={query} onChange={setQuery} placeholder={searchPlaceholder} />
        <Select value={status} onChange={setStatus} options={STATUS_OPTIONS} />
        <Select value={assignment} onChange={setAssignment} placeholder="All assignments"
          options={[{ value: "assigned", label: "Assigned SIMs" }, { value: "unassigned", label: "Unassigned SIMs" }]} />
        {MP_ALLOW("sim.manage") && variant !== "altnet" ?
          <Button variant="secondary" size="sm" icon="upload" href="#/sims/assign-csv">Assign From CSV</Button> : null}
        <window.BulkToggleButton bulk={bulk} />
        {query || status || assignment ?
        <div className="mp-clear">
          <Button variant="secondary" size="sm" icon="x" onClick={() => { setQuery(""); setStatus(""); setAssignment(""); }}>Clear Filters</Button>
        </div> : null}
      </div>
      <SimTable rows={filtered} variant={variant} bulk={bulk} />
      <window.BulkBar bulk={bulk} tweaks={window.MP_TWEAKS} />
    </div>);
}

/* ---------- Data Pool group card ---------- */
function DataPoolPanel({ tweaks, initialAssignment }) {
  const { assigned, used, pct, remaining } = effectivePoolStats(tweaks);
  const slotsLeft = Math.max(0, POOL.simMax - assigned);
  const [open, setOpen] = uP(!!initialAssignment);
  const [name, setName] = uP(poolName());
  const [renaming, setRenaming] = uP(false);
  const saveName = (v) => {
    const clean = (v || "").trim() || POOL.name;
    try { localStorage.setItem("mp_pool_name", clean); } catch (e) {}
    setName(clean);
    setRenaming(false);
  };
  const [poolChange, setPoolChange] = uP(false);
  const ctx = window.useRoles ? window.useRoles() : null;
  const usedStr = fmtGb(used);
  const remStr = fmtGb(remaining);
  const marks = [0, 0.2, 0.4, 0.6, 0.8, 1];

  return (
    <Card style={{ overflow: "hidden" }}>
      <div className="mp-sim-bar">
        <div>
          <div className="mp-pool-hero-eyebrow mp-pool-name">
            <span>{name}</span>
            {MP_ALLOW("sim.manage") ?
            <button type="button" className="mp-pool-rename" onClick={() => setRenaming(true)} aria-label="Rename this pool"><Icon name="pencil" size={14} /></button> : null}
          </div>
          <h2 className="mp-sim-hero-number">{usedStr} GB / {POOL.sizeGb} GB <span className="mp-pool-hero-tot">· {pct}% used</span></h2>
          <div className="mp-sim-hero-meta">
            <span><strong>{assigned}</strong> SIMs in pool</span>
            <span className="mp-dot-sep">•</span>
            <span>Data allowance resets 1st of the month</span>
          </div>
        </div>
        {MP_ALLOW("sim.order") ?
        <div className="mp-sim-hero-actions">
          <Button variant="secondary" icon="layers" onClick={() => setPoolChange(true)}>Add SIMs or Modify Data Pool</Button>
        </div> : null}
      </div>

      <button
        type="button"
        className={"mp-sim-disclosure" + (open ? " is-open" : "")}
        onClick={() => setOpen((o) => !o)}
        aria-expanded={open}>
        <Icon name="chevron-down" size={16} />
        <span>{open ? "Hide" : "Show"} pool details and SIMs</span>
      </button>

      {open ?
      <div className="mp-sim-details">
          <div className="mp-pool-eyebrow" style={{ marginBottom: 14 }}>Shared data pool usage</div>

          <div className="mp-meter-track">
            <div className="mp-meter-fill" style={{ width: Math.min(100, pct) + "%" }} />
            {[0.2, 0.4, 0.6, 0.8].map((m) => <span key={m} className="mp-meter-tick" style={{ left: m * 100 + "%" }} />)}
          </div>
          <div className="mp-meter-axis">
            {marks.map((m, i) => <span key={m}>{Math.round(POOL.sizeGb * m)}{i === marks.length - 1 ? " GB" : ""}</span>)}
          </div>
          <div className="mp-meter-foot">
            <span><strong>{usedStr} GB</strong> used of {POOL.sizeGb} GB</span>
            <span>{pct}% of pool used</span>
          </div>

          <div className="mp-pool-detail-grid">
            <StatCard
              label="SIMs assigned"
              value={String(assigned)}
              valueColor="var(--mp-deep-forest)"
              hint="SIMs sharing this pool's allowance" />
            <StatCard
              label="Usage resets"
              value={POOL.resetDate}
              valueColor="var(--mp-deep-forest)"
              hint="Data allowance resets monthly" />
          </div>

          <GroupSimSection rows={pooledSims()} variant="pool" searchPlaceholder="Search pool SIMs…" initialAssignment={initialAssignment} />
        </div> :
      null}
      {poolChange && window.RequestPoolChangeModal ?
      <window.RequestPoolChangeModal currentGb={POOL.sizeGb}
        onClose={() => setPoolChange(false)}
        onSent={() => {
          setPoolChange(false);
          if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch to arrange it." });
        }} /> : null}

      {renaming ? <RenamePoolModal current={name === POOL.name ? "" : name} onSave={saveName} onClose={() => setRenaming(false)} /> : null}
    </Card>);

}

/* ---------- Rename pool modal ---------- */
function RenamePoolModal({ current, onSave, onClose }) {
  const [val, setVal] = uP(current);
  return (
    <div className="mp-modal-overlay" onClick={onClose}>
      <div className="mp-modal mp-modal--form" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
        <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="pencil" size={20} /></div>
        <h3 className="mp-modal-title">Rename {poolName()}</h3>
        <p className="mp-modal-sub">Give this pool a name your team will recognise, like "Finance Team".</p>
        <div className="mp-field">
          <label className="mp-field-label">Name</label>
          <input className="mp-field-input" autoFocus value={val} placeholder={POOL.name}
            onChange={(e) => setVal(e.target.value)}
            onKeyDown={(e) => { if (e.key === "Enter") onSave(val); }} />
          <div className="mp-field-help">Leave blank to go back to {POOL.name}.</div>
        </div>
        <div className="mp-modal-actions">
          <Button variant="secondary" onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon="check" onClick={() => onSave(val)}>Save Name</Button>
        </div>
      </div>
    </div>);
}

/* ---------- Individual SIMs group card ---------- */
function IndividualSimsPanel({ initialAssignment, initialStatus }) {
  const [open, setOpen] = uP(!!initialAssignment || !!initialStatus);
  const rows = individualSims();
  const active = rows.filter((s) => s.status !== "Terminated").length;

  return (
    <Card style={{ overflow: "hidden" }}>
      <div className="mp-sim-bar">
        <div>
          <div className="mp-pool-hero-eyebrow">Individual SIMs</div>
          <h2 className="mp-sim-hero-number">{active} SIMs</h2>
        </div>
        {MP_ALLOW("sim.manage") ?
        <div className="mp-sim-hero-actions">
          <Button variant="secondary" icon="package-plus" onClick={(e) => { if (window.DEMO_TOAST) window.DEMO_TOAST("Purchase Additional SIM Plans opens the ordering flow in the live platform.", e); }}>Purchase Additional SIM Plans</Button>
        </div> : null}
      </div>

      <button
        type="button"
        className={"mp-sim-disclosure" + (open ? " is-open" : "")}
        onClick={() => setOpen((o) => !o)}
        aria-expanded={open}>
        <Icon name="chevron-down" size={16} />
        <span>{open ? "Hide" : "Show"} individual SIMs</span>
      </button>

      {open ?
      <div className="mp-sim-details">
          <GroupSimSection rows={rows} variant="individual" searchPlaceholder="Search individual SIMs…" initialAssignment={initialAssignment} initialStatus={initialStatus} />
        </div> :
      null}
    </Card>);

}

/* ---------- Individual SIMs (Alternative Networks) group card ----------
   UK SIMs on O2 or Vodafone. Same table as Individual SIMs plus Network;
   changes are requests, as with international SIMs. */
function AltNetSimsPanel({ initialOpen }) {
  const [open, setOpen] = uP(!!initialOpen);
  const [asking, setAsking] = uP(false);
  const ctx = window.useRoles ? window.useRoles() : null;
  if (window.MP_REQ) window.MP_REQ.useRequests();
  const rows = altnetSims();
  const active = rows.filter((s) => estStatusOf(s) !== "Terminated").length;
  if (!rows.length) return null;
  return (
    <Card style={{ overflow: "hidden" }}>
      <div className="mp-sim-bar">
        <div>
          <div className="mp-pool-hero-eyebrow">Individual SIMs (Alternative Networks)</div>
          <h2 className="mp-sim-hero-number">{active} SIMs</h2>
        </div>
        {MP_ALLOW("sim.order") ?
        <div className="mp-sim-hero-actions">
          <Button variant="secondary" icon="card-sim" onClick={() => setAsking(true)}>Request Alternative Network SIMs</Button>
        </div> : null}
      </div>
      <button type="button" className={"mp-sim-disclosure" + (open ? " is-open" : "")}
        onClick={() => setOpen((o) => !o)} aria-expanded={open}>
        <Icon name="chevron-down" size={16} />
        <span>{open ? "Hide" : "Show"} alternative network SIMs</span>
      </button>
      {open ?
      <div className="mp-sim-details">
        <GroupSimSection rows={rows} variant="altnet" searchPlaceholder="Search alternative network SIMs…" />
      </div> : null}
      {asking && window.RequestAltNetSimsModal ?
      <window.RequestAltNetSimsModal onClose={() => setAsking(false)}
        onSent={() => {
          setAsking(false);
          if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch to arrange your SIMs." });
        }} /> : null}
    </Card>);
}

/* ---------- SIM Management — grouped index ---------- */
/* All groups are always offered. Selecting a group the account doesn't hold
   yet shows a discovery state rather than hiding the option. */
function estateScopes() {
  return [
    { value: "all", label: "All SIMs" },
    { value: "pool", label: "Data Pool" },
    { value: "individual", label: "Individual" },
    { value: "altnet", label: "Alternative Networks" },
    { value: "international", label: "International" },
    { value: "travel", label: "Travel eSIMs" }];
}

/* Discovery state for a group the account doesn't hold yet. */
const GROUP_DISCOVERY = {
  pool: { icon: "layers", title: "No data pool yet",
    msg: "A data pool shares one allowance across your team, so nobody runs out while others have data spare." },
  individual: { icon: "card-sim", title: "No individual SIMs yet",
    msg: "Individual SIMs sit on their own plan, which suits devices with steady, predictable usage." },
  international: { icon: "globe", title: "No international SIMs yet",
    msg: "International SIMs run on a local network in the country your team works in, with a local number and a local allowance." },
  travel: { icon: "plane", title: "No travel eSIMs yet",
    msg: "A travel eSIM adds data abroad alongside someone's main SIM, so their usual number keeps working." }
};
function GroupDiscovery({ kind }) {
  const d = GROUP_DISCOVERY[kind];
  const [asking, setAsking] = uP(false);
  const ctx = window.useRoles ? window.useRoles() : null;
  const canOrder = MP_ALLOW("sim.order");
  return (
    <Card>
      <div className="mp-discovery">
        <div className="mp-discovery-ic"><Icon name={d.icon} size={22} /></div>
        <h3 className="mp-discovery-title">{d.title}</h3>
        <p className="mp-discovery-msg">{d.msg}</p>
        <div className="mp-discovery-cta">
          {canOrder && kind === "international" ?
            <Button variant="primary" icon="globe" onClick={() => setAsking(true)}>Request International SIMs</Button> :
          canOrder && kind === "travel" ?
            <Button variant="primary" icon="plus" href="#/sims/travel/new">Add Travel eSIM Plan</Button> :
            <Button variant="secondary" icon="life-buoy" href="#/support">Contact Support</Button>}
        </div>
      </div>
      {asking && window.RequestNewSimsModal ?
      <window.RequestNewSimsModal onClose={() => setAsking(false)}
        onSent={() => {
          setAsking(false);
          if (ctx) ctx.toast({ kind: "ok", title: "Request sent", body: "The team will be in touch to arrange your SIMs." });
        }} /> : null}
    </Card>);
}

function groupIsEmpty(scope) {
  const E = window.MP_ESTATE;
  if (scope === "pool") return pooledSims().length === 0;
  if (scope === "individual") return individualSims().length === 0;
  if (scope === "altnet") return false;
  if (scope === "international") return !E || E.internationalSims().length === 0;
  if (scope === "travel") return !E || E.travelSims().length === 0;
  return false;
}

/* Mixed search results carry selection too, but Export is the only action. */
function MixedResults({ rows }) {
  const bulk = window.useBulkScope("mixed", rows, "mixed");
  return (
    <>
      <Card>
        <div className="mp-mem-filters">
          <window.BulkToggleButton bulk={bulk} />
        </div>
        <SimTable rows={rows} variant="mixed" perPage={20} bulk={bulk} />
      </Card>
      <window.BulkBar bulk={bulk} tweaks={window.MP_TWEAKS} />
    </>);
}

function SimsIndexPage({ tweaks }) {
  const [query, setQuery] = uP("");
  const params = hashParams();
  const groupParam = ["international", "travel", "altnet"].indexOf(params.group) !== -1 ? params.group : "";
  const initScope = params.status ? "individual" : groupParam || "all";
  const [scope, setScope] = uP(initScope);
  React.useEffect(() => { setScope(params.status ? "individual" : groupParam || "all"); }, [groupParam, params.status]);
  const initialAssignment = params.assignment;
  const initialStatus = params.status;
  const searching = query.trim().length > 0;
  const SCOPES = estateScopes();

  const universeRows = mP(() => {
    const base = scope === "all" ? PD.SIMS : PD.SIMS.filter((s) => simGroup(s) === scope);
    return filterSims(base, query.trim(), "");
  }, [query, scope]);

  return (
    <>
      <PageHead title="SIM Management" />

      {/* Universal search across the whole estate — distinct hero panel */}
      <div className={"mp-finder mp-finder--" + ((tweaks && tweaks.finder_style) || "panel")}>
        <div className="mp-finder-main">
          <div className="mp-finder-text">
            <div className="mp-finder-eyebrow">Find a SIM</div>
          </div>
          <div className="mp-finder-input">
            <Icon name="search" size={20} className="mp-finder-input-ic" />
            <input
              className="mp-finder-field"
              type="search"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Search by SIM serial, number or user…" />
            {searching ?
            <button type="button" className="mp-finder-clear" onClick={() => setQuery("")} aria-label="Clear search"><Icon name="x" size={16} /></button> :
            null}
          </div>
        </div>
        <div className="mp-finder-scope">
          <div className="mp-scope" role="group" aria-label="SIM group">
            {SCOPES.map((s) =>
            <button key={s.value} type="button"
            className={"mp-scope-btn" + (scope === s.value ? " is-active" : "")}
            aria-pressed={scope === s.value}
            onClick={() => setScope(s.value)}>{s.label}</button>
            )}
          </div>
        </div>
      </div>

      {searching ?
      <>
          <div className="mp-universal-meta"><strong>{universeRows.length}</strong> SIM{universeRows.length === 1 ? "" : "s"} match{universeRows.length === 1 ? "es" : ""} “{query.trim()}” {scope !== "all" ? "in " + (SCOPES.find((s) => s.value === scope) || {}).label : "across your whole estate"}</div>
          <MixedResults rows={universeRows} />
        </> :
      groupIsEmpty(scope) ? <GroupDiscovery kind={scope} /> :
      <>
          {(scope === "all" || scope === "pool") && <DataPoolPanel tweaks={tweaks} initialAssignment={initialAssignment} key={"p" + initialAssignment} />}
          {(scope === "all" || scope === "pool") && <PoolStatusBanner tweaks={tweaks} context="sims" />}
          {(scope === "all" || scope === "individual") && <IndividualSimsPanel initialAssignment={initialAssignment} initialStatus={initialStatus} key={"i" + initialAssignment + initialStatus} />}
          {(scope === "all" || scope === "altnet") && <AltNetSimsPanel key={"a" + params.group} initialOpen={params.group === "altnet"} />}
          {(scope === "all" || scope === "international") && window.InternationalSimsPanel ?
          <window.InternationalSimsPanel
            key={"n" + params.group + params.country}
            initialOpen={params.group === "international"}
            initialCountry={params.group === "international" ? params.country : ""} /> : null}
          {(scope === "all" || scope === "travel") && window.TravelEsimsPanel ?
          <window.TravelEsimsPanel key={"t" + params.group} initialOpen={params.group === "travel"} /> : null}
        </>}
    </>);

}

/* ---------- Export (overrides pages-1.jsx's SimsIndexPage) ---------- */
Object.assign(window, { SimsIndexPage, DataPoolPanel, IndividualSimsPanel, AltNetSimsPanel, altnetSims, PoolStatusBanner, poolPlanLabel, GroupChip, GroupKindChip, simGroup });
