/* ========================================================================
   pages-2.jsx — Users, Subscriptions, Support, Settings
   ======================================================================== */
const { useState: u2, useMemo: m2, useEffect: e2 } = React;
const DD = window.MILO_DATA;
function demoToast(msg, e) {
  if (window.DEMO_TOAST) window.DEMO_TOAST(msg, e);
  else window.alert(msg);
}

/* =====================================================================
   USERS — index
   ===================================================================== */
/* A person's primary number is their UK SIM's number: the earliest assigned
   UK SIM (pool or individual). International and travel numbers never appear
   in the Phone number column. */
function primaryUkSim(sims) {
  const g = window.simGroup || ((s) => s.group || "individual");
  return sims.find((s) => g(s) === "pool" || g(s) === "individual" || g(s) === "altnet") || null;
}
/* Group chips only, each linking to that person's SIM in that group. */
function SimsGroupCell({ sims }) {
  if (!sims.length) return <span style={{ color: "var(--fg-3)" }}>—</span>;
  const g = window.simGroup || ((s) => s.group || "individual");
  const first = (test) => sims.find((s) => test(g(s))) || null;
  const kinds = [
    { kind: "uk", sim: first((k) => k === "pool" || k === "individual" || k === "altnet") },
    { kind: "international", sim: first((k) => k === "international") },
    { kind: "travel", sim: first((k) => k === "travel") }].
    filter((r) => r.sim);
  const Chip = window.GroupKindChip;
  if (!Chip) return null;
  return (
    <span className="mp-sims-cell">
      {kinds.map((r) =>
        <a key={r.kind} className="mp-chip-link" href={"#/sims/" + r.sim.id} onClick={(e) => e.stopPropagation()}>
          <Chip kind={r.kind} />
        </a>)}
    </span>);
}

function UsersIndexPage() {
  const usersVersion = (window.MP_USE_USERS || (() => 0))();
  const [query, setQuery] = u2("");
  const [sortField, setSortField] = u2("full_name");
  const [sortDir, setSortDir] = u2("asc");
  const [page, setPage] = u2(1);
  const [simFilter, setSimFilter] = u2("");
  const perPage = 8;

  /* SIM holders, plus any admin users who don't already hold a SIM.
     Only applies where a role model is loaded. */
  const people = m2(() => {
    const admins = window.MP_MEMBERS || [];
    const byEmail = {};
    admins.forEach((a) => { if (a.status !== "removed") byEmail[a.email.toLowerCase()] = a.role; });
    const rows = DD.USERS.map((u) => ({ ...u, role: byEmail[u.email.toLowerCase()] || null }));
    const seen = new Set(DD.USERS.map((u) => u.email.toLowerCase()));
    /* A person deleted from the user list must not be re-added by the admin
       merge below, or deleting them appears to do nothing. */
    const gone = window.MP_USERS ? window.MP_USERS.deletedEmails() : new Set();
    admins.forEach((a) => {
      const em = a.email.toLowerCase();
      if (a.status === "removed" || seen.has(em) || gone.has(em)) return;
      rows.push({
        id: 10000 + a.id, full_name: a.name, email: a.email,
        initials: a.initials, sim_ids: [], role: a.role
      });
    });
    return rows;
  }, [window.MP_MEMBERS, usersVersion]);

  const sorted = m2(() => {
    let rows = people.slice();
    if (query) {
      const q = query.toLowerCase();
      rows = rows.filter((u) => u.full_name.toLowerCase().includes(q) || u.email.toLowerCase().includes(q));
    }
    if (simFilter === "has") rows = rows.filter((u) => u.sim_ids.length > 0);
    if (simFilter === "none") rows = rows.filter((u) => u.sim_ids.length === 0);
    rows.sort((a, b) => {
      const k = sortField;
      const A = k === "phone_number" ? ((primaryUkSim(a.sim_ids.map((id) => DD.SIMS.find((s) => s.id === id)).filter(Boolean)) || {}).msisdn || "") : a[k];
      const B = k === "phone_number" ? ((primaryUkSim(b.sim_ids.map((id) => DD.SIMS.find((s) => s.id === id)).filter(Boolean)) || {}).msisdn || "") : b[k];
      const dir = sortDir === "asc" ? 1 : -1;
      if (typeof A === "string" && typeof B === "string") return A.localeCompare(B) * dir;
      return A > B ? dir : A < B ? -dir : 0;
    });
    return rows;
  }, [people, query, simFilter, sortField, sortDir]);

  const pageRows = sorted.slice((page - 1) * perPage, page * perPage);
  const totalPages = Math.ceil(sorted.length / perPage) || 1;
  const handleSort = (f) => { if (sortField === f) setSortDir(sortDir === "asc" ? "desc" : "asc"); else { setSortField(f); setSortDir("asc"); } };

  return (
    <>
      <PageHead title="User Management" />
      {MP_ALLOW("users.records.manage") ?
      <div className="mp-page-actions">
        <Button variant="primary" icon="user-plus" href="#/users/new">Create New User</Button>
        <Button variant="secondary" icon="upload" href="#/users/import">Import Users</Button>
        {window.MP_CAN ?
          <Button variant="secondary" icon="settings" href="#/settings/users">Manage Admin Roles</Button> : null}
      </div> : null}

      <Card>
        <div className="mp-mem-filters">
          <SearchInput value={query} onChange={(v) => { setQuery(v); setPage(1); }} placeholder="Search name or email..." />
          <Select value={simFilter} onChange={(v) => { setSimFilter(v); setPage(1); }} placeholder="All users"
            options={[
              { value: "has", label: "Has SIMs assigned" },
              { value: "none", label: "No SIMs assigned" }
            ]} />
          {query || simFilter ?
          <div className="mp-clear">
            <Button variant="secondary" size="sm" icon="x" onClick={() => { setQuery(""); setSimFilter(""); setSortField("full_name"); setSortDir("asc"); }}>Clear Filters</Button>
          </div> : null}
        </div>
        <TableScroll className="mp-mem-table-wrap" narrowCards>
          <table className="mp-table">
            <thead>
              <tr>
                <th><SortHeader field="full_name"   sortField={sortField} sortDir={sortDir} onSort={handleSort}>Full Name</SortHeader></th>
                <th><SortHeader field="email"       sortField={sortField} sortDir={sortDir} onSort={handleSort}>Email</SortHeader></th>
                <th><SortHeader field="phone_number" sortField={sortField} sortDir={sortDir} onSort={handleSort}>Phone number</SortHeader></th>
                <th>SIMs</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {pageRows.map((u) => {
                const sims = u.sim_ids.map((id) => DD.SIMS.find((s) => s.id === id)).filter(Boolean);
                const primary = primaryUkSim(sims);
                return (
                  <tr key={u.id}>
                    <td><a href={"#/users/" + u.id} className="mp-assigned"><Avatar initials={u.initials} size={26} tone={u.role ? "role-" + u.role : "mist"} /><span>{u.full_name}</span></a></td>
                    <td style={{ color: "var(--fg-2)" }}>{u.email}</td>
                    <td>
                      {primary ?
                        <a href={"#/sims/" + primary.id} style={{ color: "var(--mp-pine)", fontWeight: 700 }}>{primary.msisdn}</a> :
                        <span style={{ color: "var(--fg-3)" }}>—</span>}
                    </td>
                    <td><SimsGroupCell sims={sims} /></td>
                    <td>
                      <ActionsMenu items={[
                        { label: "View Details", href: "#/users/" + u.id },
                        ...(MP_ALLOW("users.records.manage") ? [
                          { label: "Edit User", href: "#/users/" + u.id + "/edit" },
                          ...(MP_ALLOW("sim.manage") ? [{ label: "Assign a SIM to User", href: "#/users/" + u.id + "/assign-sim" }] : [])] : []),
                        ...(MP_ALLOW("users.records.manage") && sims.length === 0 ? [{ label: "Delete User", href: "#/users/" + u.id + "?delete=1" }] : []),
                      ]} />
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </TableScroll>
        <div className="mp-mem-cards">
          {pageRows.map((u) => {
            const sims = u.sim_ids.map((id) => DD.SIMS.find((s) => s.id === id)).filter(Boolean);
            return (
              <div key={u.id} className="mp-mem-card">
                <div className="mp-mem-card-top">
                  <Avatar initials={u.initials} size={34} tone={u.role ? "role-" + u.role : "mist"} />
                  <div style={{ minWidth: 0, flex: 1 }}>
                    <div className="mp-mem-name"><span>{u.full_name}</span></div>
                    <div className="mp-mem-sub" style={{ overflowWrap: "anywhere" }}>{u.email}</div>
                  </div>
                  <ActionsMenu items={[
                    { label: "View Details", href: "#/users/" + u.id },
                    ...(MP_ALLOW("users.records.manage") ? [
                      { label: "Edit User", href: "#/users/" + u.id + "/edit" },
                      ...(MP_ALLOW("sim.manage") ? [{ label: "Assign a SIM to User", href: "#/users/" + u.id + "/assign-sim" }] : [])] : [])
                  ]} />
                </div>
                <div className="mp-card-facts">
                  <div><span>Phone number</span><strong>{primaryUkSim(sims) ? primaryUkSim(sims).msisdn : "—"}</strong></div>
                  <div><span>SIMs</span><strong><SimsGroupCell sims={sims} /></strong></div>
                </div>

              </div>
            );
          })}
        </div>
        <div style={{ padding: "12px 16px" }}>
          <Pagination page={page} totalPages={totalPages} onChange={setPage} />
        </div>
      </Card>
    </>
  );
}

/* =====================================================================
   USERS — show
   ===================================================================== */
function UserShowPage({ id }) {
  const user = DD.USERS.find((u) => u.id === Number(id));
  const [deleteStep, setDeleteStep] = u2(() => /[?&]delete=1/.test(window.location.hash) ? 1 : 0);
  const [confirmText, setConfirmText] = u2("");
  const ctx = window.useRoles ? window.useRoles() : null;
  (window.MP_USE_USERS || (() => {}))();
  if (!user) return <Empty icon="search" title="Not found" message="That user could not be found." />;
  const sims = user.sim_ids.map((sid) => DD.SIMS.find((s) => s.id === sid)).filter(Boolean);

  const closeDelete = () => { setDeleteStep(0); setConfirmText(""); };
  const confirmReady = confirmText.trim().toLowerCase() === "delete user";

  return (
    <>
      <PageHead title="User Management" subtitle="Here you can see information about a specific user and any SIM cards assigned to that user." />
      <BackLink href="#/users">Back to Users</BackLink>

      <Card>
        <div style={{ padding: 24 }}>
          <div className="mp-glance-head">
            <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "var(--mp-deep-forest)" }}>User Profile</h3>
            {MP_ALLOW("users.records.manage") ?
            <div className="mp-sim-actions">
              {MP_ALLOW("sim.manage") ?
              <Button variant="secondary" size="lg" icon="card-sim" href={"#/users/" + user.id + "/assign-sim"}>
                {sims.length ? "Assign Additional SIM" : "Assign a SIM"}
              </Button> : null}
              {MP_ALLOW("sim.order") ?
              <Button variant="secondary" size="lg" icon="plane" href={"#/sims/travel/new?user=" + user.id}>Add Travel eSIM Plan</Button> : null}
              <Button variant="secondary" size="lg" icon="pencil" href={"#/users/" + user.id + "/edit"}>Edit User Details</Button>
              <Button variant="danger" size="lg" icon="trash-2" onClick={() => setDeleteStep(1)}>Delete User</Button>
            </div> : null}
          </div>

          <div style={{ marginTop: 22 }}>
            <div className="mp-profile-row">
              <Avatar initials={user.initials} size={54} tone={user.role ? "role-" + user.role : "mist"} />
              <div>
                <div className="mp-profile-name">{user.full_name} <span style={{ color: "var(--fg-3)", fontWeight: 500, fontSize: 16 }}>({user.email})</span></div>
                <div className="mp-profile-role">
                  {user.role && window.RoleBadge
                    ? <window.RoleBadge role={user.role} />
                    : <Badge variant="standard-user" icon="user-round">Standard User</Badge>}
                </div>
              </div>
            </div>
          </div>
        </div>
      </Card>

      {sims.length === 0 ? (
        <Card>
          <div className="mp-card-body">
            <Empty icon="card-sim" title="No SIMs assigned" message="This user doesn't have any SIM cards assigned yet." />
          </div>
        </Card>
      ) : (
        sims.map((sim) => <window.UserSimCard key={sim.id} sim={sim} />)
      )}

      {deleteStep === 1 ? (
        <div className="mp-modal-overlay" onClick={closeDelete}>
          <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
            <div className="mp-modal-ic mp-modal-ic--danger"><Icon name="trash-2" size={20} /></div>
            <h3 className="mp-modal-title">Are you sure you want to delete this user?</h3>
            <p className="mp-modal-text">
              This action cannot be reversed. Any SIMs assigned to this user will remain active, and can be reassigned from the SIM management dashboard.
            </p>
            <div className="mp-modal-actions">
              <Button variant="secondary" onClick={closeDelete}>Cancel</Button>
              <Button variant="danger" onClick={() => { setDeleteStep(2); setConfirmText(""); }}>Delete User</Button>
            </div>
          </div>
        </div>
      ) : null}

      {deleteStep === 2 ? (
        <div className="mp-modal-overlay" onClick={closeDelete}>
          <div className="mp-modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 460 }}>
            <div className="mp-modal-ic mp-modal-ic--danger"><Icon name="trash-2" size={20} /></div>
            <h3 className="mp-modal-title">Confirm deletion of {user.full_name}?</h3>
            <div className="mp-field">
              <label className="mp-field-label">To confirm deletion type <strong>delete user</strong> below:</label>
              <input
                className="mp-field-input"
                value={confirmText}
                placeholder="delete user"
                autoFocus
                onChange={(e) => setConfirmText(e.target.value)} />
            </div>
            <div className="mp-modal-actions">
              <Button variant="secondary" onClick={closeDelete}>Cancel</Button>
              <Button
                variant="danger-solid"
                icon="trash-2"
                className={confirmReady ? "" : "is-disabled"}
                onClick={confirmReady ? () => {
                  const gone = user.full_name;
                  closeDelete();
                  if (window.MP_USERS) window.MP_USERS.deleteUser(user.id);
                  if (ctx) ctx.toast({ kind: "ok", title: "User deleted", body: gone + " has been removed from your user list." });
                  window.location.hash = "/users";
                } : undefined}>
                Delete User
              </Button>
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}

const gbpUI = (n) => "£" + Number(n).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ",");

/* =====================================================================
   USERS — new
   ===================================================================== */
function UserNewPage() {
  const [name, setName] = u2("");
  const [email, setEmail] = u2("");
  const [err, setErr] = u2(null);
  const ctx = window.useRoles ? window.useRoles() : null;
  const US = window.MP_USERS;

  const submit = () => {
    const n = name.trim(), e = email.trim();
    if (!n) return setErr("Enter the person's full name.");
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(e)) return setErr("Enter a valid email address.");
    if (US && US.emailTaken(e)) return setErr("Someone on your user list already uses that email address.");
    setErr(null);
    const made = US ? US.createUser(n, e) : null;
    if (ctx) ctx.toast({ kind: "ok", title: "User created", body: n + " has been sent a link to set their password." });
    location.hash = made ? "/users/" + made.id : "/users";
  };

  return (
    <>
      <PageHead title="User Management" />
      <BackLink href="#/users">Back to Users</BackLink>

      <Card style={{ maxWidth: 640 }}>
        <div style={{ padding: 24 }}>
          <h3 style={{ margin: 0, fontSize: 22, fontWeight: 800, letterSpacing: "-0.01em" }}>Create a New User</h3>

          <form onSubmit={(e) => { e.preventDefault(); submit(); }} style={{ display: "flex", flexDirection: "column", gap: 18, marginTop: 22 }}>
            <div className="mp-field">
              <label className="mp-field-label">Full Name</label>
              <input className="mp-field-input" required value={name} onChange={(e) => { setName(e.target.value); setErr(null); }} />
            </div>
            <div className="mp-field">
              <label className="mp-field-label">Email Address</label>
              <input className="mp-field-input" type="email" required value={email} onChange={(e) => { setEmail(e.target.value); setErr(null); }} />
            </div>
            {err ? <div className="mp-field-error">{err}</div> : null}
            <p style={{ fontSize: 13, color: "var(--fg-3)", margin: 0 }}>
              Once you've created the new user, the system will automatically send that user an email with a unique link that will allow them to set their password and access their individual User Account.
            </p>
            <div>
              <Button variant="primary" type="submit">Submit</Button>
            </div>
          </form>
        </div>
      </Card>
    </>
  );
}

/* =====================================================================
   USERS — edit
   ===================================================================== */
function UserEditPage({ id }) {
  const US = window.MP_USERS;
  (window.MP_USE_USERS || (() => {}))();
  const user = DD.USERS.find((u) => u.id === Number(id));
  const ctx = window.useRoles ? window.useRoles() : null;
  const IEF = window.InlineEditField;
  if (!user) return <Empty icon="search" title="Not found" message="That user could not be found." />;

  const saveName = (next) => {
    if (!next) return "Enter the person's full name.";
    US.updateUser(user.id, { full_name: next });
    if (ctx) ctx.toast({ kind: "ok", title: "Name updated" });
  };
  const saveEmail = (next) => {
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(next)) return "Enter a valid email address.";
    if (US.emailTaken(next, user.id)) return "Someone on your user list already uses that email address.";
    US.updateUser(user.id, { email: next });
    if (ctx) ctx.toast({ kind: "ok", title: "Email address updated", body: next + " will be used for sign-in and platform emails." });
  };

  return (
    <>
      <PageHead title="User Management" />
      <BackLink href={"#/users/" + user.id}>Back to User</BackLink>

      <Card style={{ maxWidth: 640 }}>
        <div className="mp-card-body">
          <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 22 }}>
            <Avatar initials={user.initials} size={52} tone="mist" />
            <div>
              <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "var(--mp-deep-forest)" }}>{user.full_name}</h3>
              <div style={{ fontSize: 13.5, color: "var(--fg-3)", marginTop: 2 }}>{user.email}</div>
            </div>
          </div>
          <div className="mp-ie-list">
            <IEF label="Full Name" value={user.full_name}
              modalTitle="Change this person's name?"
              confirmChange="Confirm this change?"
              onSave={saveName} />
            <IEF label="Email Address" value={user.email} type="email"
              modalTitle="Change this person's email address?"
              confirmChange="Confirm this change?"
              onSave={saveEmail} />
          </div>
        </div>
      </Card>
    </>
  );
}

/* =====================================================================
   SUBSCRIPTIONS — index
   ===================================================================== */
function SubscriptionsIndexPage() {
  const subscribedIds = new Set(DD.SUBSCRIPTIONS.reduce((a, s) => a.concat(s.sim_ids), []));
  const subscribedSims = DD.SIMS.filter((s) => subscribedIds.has(s.id));
  const totalSims = subscribedSims.length;
  const activeSims = subscribedSims.filter((s) => s.status === "Active" || s.status === "Activated").length;
  const totalMonthly = billedMonthly(subscribedSims);

  return (
    <>
      <PageHead title="Subscription & Billing" />

      <div className="mp-grid-stats-4" style={{ gridTemplateColumns: "repeat(3, 1fr)" }}>
        <StatCard label="Total Subscriptions" value={DD.SUBSCRIPTIONS.length} />
        <StatCard label="SIMs on a Subscription" value={totalSims} hint={activeSims + " active"} />
        <StatCard label="Total Monthly Cost" value={gbpUI(totalMonthly)} />
      </div>

      <Card>
        <div className="mp-card-head">
          <h3 style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <Icon name="credit-card" size={18} />
            <span>Payment & Invoices</span>
          </h3>
        </div>
        <div className="mp-card-body">
          <div style={{ display: "flex", gap: 12, flexWrap: "wrap" }}>
            {MP_ALLOW("billing.config") ? <Button variant="secondary" icon="settings" onClick={(e) => demoToast("Manage Payment Methods opens in Stripe in the live platform.", e)}>Manage Payment Methods</Button> : null}
            <Button variant="secondary" icon="file-text" onClick={(e) => demoToast("View Invoices opens in Stripe in the live platform.", e)}>View Invoices in Stripe</Button>
          </div>
          <p style={{ fontSize: 12.5, color: "var(--fg-3)", marginTop: 12, marginBottom: 0 }}>
            {MP_ALLOW("billing.config")
              ? "Payment details and invoice history are managed securely through Stripe."
              : "Invoice history is available to you. Payment methods and billing configuration are managed by your Account Owner or an Admin."}
          </p>
        </div>
      </Card>

      <div className="mp-subhead" style={{ marginTop: 4 }}>
        <h2 className="mp-subhead-title">Your Subscriptions</h2>
      </div>

      <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
        {DD.SUBSCRIPTIONS.map((sub) => {
          const sims = sub.sim_ids.map((id) => DD.SIMS.find((s) => s.id === id)).filter(Boolean);
          const total = billedMonthly(sims);
          return (
            <a key={sub.id} className="mp-sub-card" href={"#/subscriptions/" + sub.id}>
              <div>
                <div className="mp-sub-card-title">
                  <span>{sub.label || "SUB-" + sub.id}</span>
                  <StatusBadge status={sub.stripe_status === "active" ? "Active" : sub.stripe_status === "trialing" ? "Trialing" : sub.stripe_status} />
                </div>
                <div className="mp-sub-card-meta">
                  {simTypeCounts(sims).map((c) =>
                    <span key={c.type}><Icon name={c.icon} size={13} />{c.count} {c.label}</span>)}
                  <span>ID: SUB-{sub.id}</span>
                </div>
              </div>
              <div className="mp-sub-card-price">
                {gbpUI(total)}
                <small>per month</small>
              </div>
              <Icon name="chevron-right" size={18} className="mp-text-muted" />
            </a>
          );
        })}
      </div>
    </>
  );
}

/* =====================================================================
   SUBSCRIPTIONS — show
   ===================================================================== */
function SubscriptionShowPage({ id }) {
  const sub = DD.SUBSCRIPTIONS.find((s) => s.id === Number(id));
  const [toast, setToast] = u2(null);
  e2(() => {
    try {
      const t = sessionStorage.getItem("mp-upgrade-toast");
      if (t) { setToast(t); sessionStorage.removeItem("mp-upgrade-toast"); }
    } catch (e) {}
  }, []);
  e2(() => {
    if (!toast) return;
    const id = setTimeout(() => setToast(null), 6000);
    return () => clearTimeout(id);
  }, [toast]);
  if (!sub) return <Empty icon="search" title="Not found" message="That subscription could not be found." />;
  const sims = sub.sim_ids.map((sid) => DD.SIMS.find((s) => s.id === sid)).filter(Boolean);
  const typeCounts = simTypeCounts(sims);
  const totalMonthly = billedMonthly(sims);
  const activeCount = sims.filter((s) => s.status === "Active" || s.status === "Activated").length;

  return (
    <>
      <PageHead title={<>Manage This Subscription: SUB-{sub.id} <StatusBadge status={sub.stripe_status === "active" ? "Active" : "Trialing"} /></>}
                subtitle="Manage the data plans assigned to each SIM in this subscription. Upgrade individual lines as your needs change." />
      <div style={{ marginTop: -12, fontSize: 12.5, color: "var(--fg-3)" }}>Subscription ID: SUB-{sub.id}</div>
      {toast ? (
        <div className="mp-toast-inline" role="status">
          <Icon name="circle-check" size={18} />
          <div>
            <strong>Your upgrade is being processed.</strong> {toast} This may take a few minutes to fully activate.
          </div>
        </div>
      ) : null}

      <BackLink href="#/subscriptions">Back to Subscriptions</BackLink>

      <div className="mp-grid-stats-4" style={{ gridTemplateColumns: "repeat(" + (4 + typeCounts.length) + ", 1fr)" }}>
        <StatCard label="Total SIMs"     value={sims.length} hint={activeCount + " active"} />
        {typeCounts.map((c) => <StatCard key={c.type} label={c.label} value={c.count} />)}
        <StatCard label="Monthly Spend"  value={gbpUI(totalMonthly)} />
        <StatCard label="Next Bill"      value={sub.next_bill} />
        <StatCard label="Contract Ends"  value={sub.expires} />
      </div>

      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {sims.map((sim) => {
          const plan = DD.PLANS[sim.plan];
          const metered = !!plan.limit_gb && sim.plan !== "unlimited";
          const usagePct = metered ? Math.round((sim.used / plan.limit_gb) * 100) : 0;
          const user = DD.USERS.find((u) => u.sim_ids.includes(sim.id));
          return (
            <div key={sim.id} className="mp-sim-row">
              <div className="mp-sim-row-left">
                <div style={{ minWidth: 0 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
                    <span className="mp-sim-row-id">{simLabel(sim)}</span>
                    <SimTypeBadge type={sim.sim_type} />
                    <StatusBadge status={sim.status} sim={sim} />
                  </div>
                  <div className="mp-sim-row-sub">
                    {user
                      ? <>Assigned to <a href={"#/users/" + user.id} className="mp-sim-row-user">{user.full_name}</a></>
                      : <span style={{ color: "var(--fg-3)" }}>Unassigned</span>}
                  </div>
                </div>
              </div>
              <div className="mp-sim-row-data">
                {metered ? (
                  <>
                    <div className="mp-sim-row-usage-label">
                      <span>Data used</span>
                      <strong>{sim.used.toFixed(1)} GB / {plan.data}</strong>
                    </div>
                    <ProgressBar pct={usagePct} />
                  </>
                ) : (
                  <div className="mp-sim-row-unlimited">
                    <Icon name="infinity" size={15} />
                    <span>Unlimited data</span>
                  </div>
                )}
              </div>
              <div className="mp-sim-row-price">
                {isBilled(sim) ? <>{gbpUI(simCharge(sim).amount)}<small>{simCharge(sim).recurring ? "/month" : " one-off"}</small></> : <small>Not billed yet</small>}
              </div>
              <div className="mp-sim-row-action">
                {metered ? <Button variant="primary" size="sm" icon="circle-arrow-up" href={"#/subscriptions/" + sub.id + "/upgrade/" + sim.serial}>Upgrade</Button> : null}
              </div>
            </div>
          );
        })}
      </div>
    </>
  );
}

/* =====================================================================
   SUBSCRIPTIONS — upgrade (select plan + SIMs)
   Faithful port of the Rails upgrade flow, reskinned to the MP system.
   ===================================================================== */
const PLAN_GB = { small: 5, big: 25, unlimited: 9999 };
const PLAN_ORDER = ["small", "big", "unlimited"];

function proratedFraction() {
  const now = new Date();
  const start = new Date(now.getFullYear(), now.getMonth(), 1);
  const end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
  const totalDays = Math.round((end - start) / 864e5) + 1;
  const remaining = Math.max(0, Math.round((end - now) / 864e5) + 1);
  return Math.min(remaining, totalDays) / totalDays;
}

function simTypeIcon(type) {
  return type === "eSIM" ? "qr-code" : type === "IoT" ? "cpu" : "card-sim";
}

function SubscriptionUpgradePage({ id, selectedSerial }) {
  const sub = DD.SUBSCRIPTIONS.find((s) => s.id === Number(id));
  const subSims = sub ? sub.sim_ids.map((sid) => DD.SIMS.find((s) => s.id === sid)).filter(Boolean) : [];
  const selectedSim = subSims.find((s) => s.serial === selectedSerial) || subSims.find((s) => DD.PLANS[s.plan].limit_gb);
  const currentData = selectedSim ? PLAN_GB[selectedSim.plan] : 0;

  // SIMs eligible to appear in the list: metered, same-or-higher data than the upgraded SIM.
  const eligibleSims = subSims.filter(
    (s) => PLAN_GB[s.plan] < PLAN_GB.unlimited && PLAN_GB[s.plan] >= currentData
  );

  // First upgrade plan (lowest data amount above current) — auto-selected.
  const firstUpgrade = PLAN_ORDER.find((k) => PLAN_GB[k] > currentData) || PLAN_ORDER[PLAN_ORDER.length - 1];

  const [plan, setPlan] = u2(firstUpgrade);
  const [selected, setSelected] = u2(() => new Set(selectedSim ? [selectedSim.serial] : []));
  const [modalOpen, setModalOpen] = u2(false);
  const [processing, setProcessing] = u2(false);

  if (!sub || !selectedSim) {
    return <Empty icon="search" title="Not found" message="That subscription or SIM could not be found." />;
  }

  const planData = PLAN_GB[plan];
  const planPrice = DD.PLANS[plan].price;

  // A SIM is ineligible for the chosen target if it already has >= that data.
  const isSimEligible = (s) => PLAN_GB[s.plan] < planData;

  // Eligible first, then the upgraded SIM first among those.
  const orderedSims = [...eligibleSims].sort((a, b) => {
    const ae = isSimEligible(a), be = isSimEligible(b);
    if (ae && be) {
      if (a.serial === selectedSim.serial) return -1;
      if (b.serial === selectedSim.serial) return 1;
      return 0;
    }
    return ae ? -1 : 1;
  });

  const eligibleSerials = eligibleSims.filter(isSimEligible).map((s) => s.serial);
  const selectedEligible = [...selected].filter((sn) => eligibleSerials.includes(sn));
  const allSelected = eligibleSerials.length > 0 && eligibleSerials.every((sn) => selected.has(sn));

  const toggleSim = (serial) => {
    setSelected((prev) => {
      const next = new Set(prev);
      next.has(serial) ? next.delete(serial) : next.add(serial);
      return next;
    });
  };
  const selectAll = () => {
    setSelected((prev) => {
      const next = new Set(prev);
      if (allSelected) eligibleSerials.forEach((sn) => next.delete(sn));
      else eligibleSerials.forEach((sn) => next.add(sn));
      return next;
    });
  };
  const clearSelection = () => setSelected(new Set());

  // When the target plan changes, drop any now-ineligible selections.
  e2(() => {
    setSelected((prev) => {
      const next = new Set([...prev].filter((sn) => {
        const s = eligibleSims.find((x) => x.serial === sn);
        return s && PLAN_GB[s.plan] < planData;
      }));
      return next;
    });
  }, [plan]);

  const monthlyIncrease = selectedEligible.reduce((t, sn) => {
    const s = eligibleSims.find((x) => x.serial === sn);
    return t + (planPrice - simMonthly(s));
  }, 0);
  const proratedIncrease = monthlyIncrease > 0 ? monthlyIncrease * proratedFraction() : 0;

  const count = selectedEligible.length;
  const planName = DD.PLANS[plan].name;

  const submit = () => {
    setProcessing(true);
    setTimeout(() => {
      try { sessionStorage.setItem("mp-upgrade-toast", count + " SIM" + (count !== 1 ? "s" : "") + " upgraded to the " + planName + " plan."); } catch (e) {}
      navigate("/subscriptions/" + sub.id);
    }, 1400);
  };

  return (
    <>
      <PageHead title="Upgrade Plan"
                subtitle="Select SIMs and upgrade to higher data allowances. Changes apply immediately." />
      <BackLink href={"#/subscriptions/" + sub.id}>Back to Subscription</BackLink>

      {/* ---- Choose plan ---- */}
      <div className="mp-subhead" style={{ marginTop: 4 }}>
        <h2 className="mp-subhead-title">Choose your new plan</h2>
      </div>
      <div className="mp-plan-grid">
        {PLAN_ORDER.map((key) => {
          const p = DD.PLANS[key];
          const isCurrent = key === selectedSim.plan;
          const isUpgrade = PLAN_GB[key] > currentData;
          const isSelected = isUpgrade && key === plan;
          const isLower = PLAN_GB[key] < currentData;
          const cls = "mp-plan-card" + (isSelected ? " is-selected" : "") + (isCurrent ? " is-current" : "") + (isLower ? " is-disabled" : "");
          return (
            <div key={key} className={cls}
                 onClick={isUpgrade ? () => setPlan(key) : undefined}
                 role={isUpgrade ? "button" : undefined}>
              {isSelected ? <div className="mp-plan-check"><Icon name="check" size={14} /></div> : null}
              <div className="mp-plan-label">
                {isCurrent ? <span className="mp-plan-label-current"><Icon name="check" size={12} />Current Plan</span> : null}
                {isSelected ? <span className="mp-plan-label-new"><Icon name="check" size={12} />New Plan</span> : null}
              </div>
              <div className="mp-plan-body">
                <h3 className="mp-plan-name">{p.data === "Unlimited" ? "Unlimited" : p.data} Data</h3>
                <p className="mp-plan-price">{gbpUI(p.price)}<span>/month</span></p>
                {isUpgrade ? (
                  <button className={"mp-plan-btn" + (isSelected ? " is-selected" : "")}>
                    {isSelected ? "Selected" : "Choose Plan"}
                  </button>
                ) : isCurrent ? (
                  <div className="mp-plan-note">Your current allowance</div>
                ) : (
                  <div className="mp-plan-note">Lower than current</div>
                )}
              </div>
            </div>
          );
        })}
      </div>
      <p className="mp-plan-foot">All plans include unlimited UK calls &amp; texts, plus free EU roaming up to 25% of your data allowance.</p>

      {/* ---- Select SIMs ---- */}
      <Card>
        <div className="mp-card-head">
          <div>
            <h3>Select SIM cards to upgrade</h3>
            <div className="mp-card-head-sub">Choose which SIM cards should receive this upgrade</div>
          </div>
          <Button variant="secondary" size="sm" onClick={selectAll}>
            {allSelected ? "Deselect all (" + eligibleSerials.length + ")" : "Select all eligible (" + eligibleSerials.length + ")"}
          </Button>
        </div>
        <div className="mp-card-body" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {orderedSims.map((s) => {
            const eligible = isSimEligible(s);
            const checked = selected.has(s.serial);
            const user = DD.USERS.find((u) => u.sim_ids.includes(s.id));
            return (
              <div key={s.id}
                   className={"mp-up-sim" + (checked ? " is-checked" : "") + (eligible ? "" : " is-disabled")}
                   onClick={eligible ? () => toggleSim(s.serial) : undefined}
                   role={eligible ? "checkbox" : undefined} aria-checked={checked}>
                <span className={"mp-up-check" + (checked ? " is-checked" : "")}>
                  {checked ? <Icon name="check" size={13} /> : null}
                </span>
                <div className={"mp-up-ic" + (checked ? " is-checked" : "")}>
                  <Icon name={simTypeIcon(s.sim_type)} size={17} />
                </div>
                <div className="mp-up-sim-main">
                  <div className="mp-up-sim-top">
                    <span className="mp-sim-row-id">{simLabel(s)}</span>
                    <SimTypeBadge type={s.sim_type} />
                    <StatusBadge status={s.status} sim={s} />
                  </div>
                  <div className="mp-sim-row-sub">
                    {user
                      ? <>Assigned to {user.full_name}</>
                      : <span style={{ color: "var(--fg-3)" }}>Unassigned</span>}
                  </div>
                </div>
                <div className="mp-up-sim-plan">
                  <div className="mp-up-sim-plan-data">{DD.PLANS[s.plan].data} Data</div>
                  <div className="mp-up-sim-plan-price">{gbpUI(simMonthly(s))}<span>/month</span></div>
                </div>
              </div>
            );
          })}
        </div>
      </Card>

      {/* ---- Sticky summary bar ---- */}
      {count > 0 ? (
        <div className="mp-up-bar-wrap">
          <div className="mp-up-bar">
            <div className="mp-up-bar-left">
              <div className="mp-up-bar-ic"><Icon name="circle-arrow-up" size={18} /></div>
              <div>
                <div className="mp-up-bar-title">Upgrading {count} SIM{count !== 1 ? "s" : ""} to {planName} Data</div>
                <div className="mp-up-bar-est">
                  <Icon name="info" size={12} />
                  Est. pro-rated charge this month: <strong>{gbpUI(proratedIncrease)}</strong>
                </div>
              </div>
            </div>
            <div className="mp-up-bar-right">
              <div className="mp-up-bar-incr">
                <span>Monthly increase</span>
                <strong>{gbpUI(monthlyIncrease)}</strong>
              </div>
              <Button variant="secondary" onClick={clearSelection}>Cancel</Button>
              <Button variant="primary" icon="circle-arrow-up" onClick={() => setModalOpen(true)}>Confirm Upgrade</Button>
            </div>
          </div>
        </div>
      ) : null}

      {/* ---- Confirm modal ---- */}
      {modalOpen ? (
        <div className="mp-modal-overlay" onClick={processing ? undefined : () => setModalOpen(false)}>
          <div className="mp-modal" onClick={(e) => e.stopPropagation()}>
            <div className="mp-modal-ic mp-modal-ic--neutral"><Icon name="circle-arrow-up" size={20} /></div>
            <h3 className="mp-modal-title">Confirm upgrade</h3>
            <p className="mp-modal-text">
              Upgrade {count} SIM card{count !== 1 ? "s" : ""} to the <strong>{planName}</strong> plan.
            </p>
            <div className="mp-modal-figs">
              <div>
                <span>Monthly increase</span>
                <strong>{gbpUI(monthlyIncrease)}</strong>
              </div>
              <div>
                <span>Est. pro-rated charge</span>
                <strong>{gbpUI(proratedIncrease)}</strong>
              </div>
            </div>
            <div className="mp-modal-note">
              <p>Upgrades apply immediately and may take <strong>up to 15 minutes</strong> to fully activate.</p>
              <p>Your next invoice will include an estimated pro-rated charge of <strong>{gbpUI(proratedIncrease)}</strong>. The exact amount may differ slightly. You'll get an email confirmation once complete.</p>
            </div>
            <div className="mp-modal-actions">
              <Button variant="secondary" onClick={() => setModalOpen(false)} className={processing ? "is-disabled" : ""}>Cancel</Button>
              <button className="mp-btn mp-btn--primary mp-btn--md" onClick={processing ? undefined : submit} disabled={processing}>
                {processing
                  ? <><Icon name="loader" size={16} className="mp-spin" /><span>Processing…</span></>
                  : <><Icon name="circle-arrow-up" size={16} /><span>Confirm Upgrade</span></>}
              </button>
            </div>
          </div>
        </div>
      ) : null}
    </>
  );
}

/* =====================================================================
   SUPPORT
   ===================================================================== */
function SupportPage() {
  return (
    <>
      <PageHead title="Support & Help" />

      <div className="mp-page-actions">
        <Button variant="secondary" icon="ticket" href="#/support/tickets">View Support Tickets</Button>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 16 }} className="mp-support-grid">
        <Card>
          <div style={{ padding: 24, paddingBottom: 8 }}>
            <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700 }}>Telecoms Orchestration Platform: Business Customer FAQs</h3>
            <p style={{ fontSize: 12.5, color: "var(--fg-3)", marginTop: 6 }}>Last updated: 10 March 2026</p>
            <p style={{ fontSize: 13.5, color: "var(--fg-2)", marginTop: 10, lineHeight: 1.6 }}>
              Welcome to the platform, Meaningful Planet's self-service platform for managing your organisation's mobile connectivity. Below are answers to the most common questions from business users during onboarding and day-to-day operations.
            </p>
          </div>

          {DD.FAQ.map((group, gi) => (
            <div key={gi} style={{ marginTop: 8 }}>
              <div className="mp-faq-group-title">{group.title}</div>
              {group.elements.map((el, ei) => <FaqItem key={ei} q={el.q} a={el.a} />)}
            </div>
          ))}
        </Card>

        <Card className="mp-help-card">
          <h3 style={{ margin: 0, fontSize: 16, fontWeight: 700 }}>Need More Help?</h3>
          <p style={{ fontSize: 12.5, color: "var(--fg-3)", marginTop: 6 }}>
            Can't find what you're looking for? We're here to help.
          </p>
          <div className="mp-help-list">
            <a className="mp-help-link" href="#/support/tickets/new"><Icon name="ticket" size={16} /><span>Open a Support Ticket</span><Icon name="chevron-right" size={14} style={{ marginLeft: "auto", color: "var(--fg-3)" }} /></a>
            <button type="button" className="mp-help-link" onClick={(e) => window.DEMO_TOAST && window.DEMO_TOAST("Email Support opens your mail client in the live platform.", e)}><Icon name="mail" size={16} /><span>Email Support</span><Icon name="chevron-right" size={14} style={{ marginLeft: "auto", color: "var(--fg-3)" }} /></button>
            <button type="button" className="mp-help-link" onClick={(e) => window.DEMO_TOAST && window.DEMO_TOAST("Call Us dials the team in the live platform.", e)}><Icon name="phone" size={16} /><span>Call Us: 020 4552 9816</span><Icon name="chevron-right" size={14} style={{ marginLeft: "auto", color: "var(--fg-3)" }} /></button>
            <button type="button" className="mp-help-link" onClick={(e) => window.DEMO_TOAST && window.DEMO_TOAST("The Help Centre opens in a new tab in the live platform.", e)}><Icon name="book-open" size={16} /><span>Help Centre</span><Icon name="external-link" size={14} style={{ marginLeft: "auto", color: "var(--fg-3)" }} /></button>
          </div>
        </Card>
      </div>
    </>
  );
}

function FaqItem({ q, a }) {
  const [open, setOpen] = u2(false);
  return (
    <div className={"mp-faq-item" + (open ? " is-open" : "")}>
      <button className="mp-faq-trigger" onClick={() => setOpen((v) => !v)}>
        <span>{q}</span>
        <Icon name="chevron-down" size={16} />
      </button>
      <div className="mp-faq-body">
        <div style={{ paddingTop: 2 }}>{a}</div>
      </div>
    </div>
  );
}

/* =====================================================================
   SETTINGS
   ===================================================================== */
function SettingsPage() {
  const [tab, setTab] = u2("profile");
  const [name, setName] = u2(DD.CURRENT_USER.full_name);
  const [email, setEmail] = u2(DD.CURRENT_USER.email);

  return (
    <>
      <PageHead title="Settings" />

      <div className="mp-page-tabs" role="tablist">
        <button role="tab" className={"mp-page-tab" + (tab === "profile" ? " is-active" : "")} onClick={() => setTab("profile")}>Profile</button>
      </div>

      <Card style={{ maxWidth: 900 }}>
        <div style={{ padding: "28px 32px 24px" }}>
          <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "var(--mp-deep-forest)" }}>User Profile</h3>
          <p style={{ fontSize: 13.5, color: "var(--fg-3)", marginTop: 6, lineHeight: 1.55 }}>Update your personal information and preferences</p>
        </div>
        <form onSubmit={(e) => e.preventDefault()} style={{ padding: "0 32px 24px" }}>
          <div className="mp-form-grid-2">
            <div className="mp-field">
              <label className="mp-field-label">Full name</label>
              <input className="mp-field-input" required value={name} onChange={(e) => setName(e.target.value)} />
            </div>
            <div className="mp-field">
              <label className="mp-field-label">Email</label>
              <input className="mp-field-input" type="email" required value={email} onChange={(e) => setEmail(e.target.value)} />
            </div>
          </div>
        </form>
        <div className="mp-form-footer">
          <Button variant="primary" size="lg" type="submit">Save Changes</Button>
        </div>
      </Card>

      <Card style={{ maxWidth: 900 }}>
        <div style={{ padding: "28px 32px 24px" }}>
          <h3 style={{ margin: 0, fontSize: 18, fontWeight: 700, color: "var(--mp-deep-forest)" }}>Two Factor Authentication</h3>
          <p style={{ fontSize: 13.5, color: "var(--fg-3)", marginTop: 6, lineHeight: 1.55 }}>
            Currently, you have Two Factor Authentication <strong style={{ color: "var(--fg-1)" }}>{DD.CURRENT_USER.otp_enabled ? "enabled" : "disabled"}</strong>.
          </p>
        </div>
        <div style={{ padding: "0 32px 28px" }}>
          <Button variant="primary">{DD.CURRENT_USER.otp_enabled ? "Disable" : "Enable"}</Button>
        </div>
      </Card>
    </>
  );
}

/* ---------- Export ---------- */
Object.assign(window, {
  UsersIndexPage, UserShowPage, UserNewPage, UserEditPage,
  SubscriptionsIndexPage, SubscriptionShowPage, SubscriptionUpgradePage,
  SupportPage, SettingsPage,
});
