// Shared navigation shell for the whole Solo staff admin area. Every
// admin page (Approvals, Customers, Assets, Price List, Orders, Invoices,
// Purchase Orders, ...) renders itself INSIDE <AdminShell> instead of
// duplicating its own header/nav-button row — this is the single,
// scalable nav surface the CRM/ERP/MRP page set builds against going
// forward (replacing the old per-page ad-hoc "Approvals / Customers /
// Assets / Sign out" button rows).
//
// A left sidebar was chosen over a top bar because the nav list will
// keep growing (more CRM/ERP/MRP modules to come) — a sidebar scales to
// more items far better than a horizontal bar squeezed under the public
// TopNav.
//
// THEME UNIFICATION (this pass): AdminShell and ResellerShell now share
// one visual language — strict black-on-white brand palette (no amber/
// orange accent — that's gone from both shells and every nav highlight;
// see portal-icons.jsx's header comment for the same note on
// ResellerShell), a labelled icon next to every nav item (see
// portal-icons.jsx), and the same hover/active motion language (2px
// black bar sliding in from the left, icon + label nudging right a
// touch, background tinting in). Both shells also share the identical
// sidebar skeleton now — width, header block, footer block, sign-out
// button styling — so a staff member who also has reseller access (the
// "Solo staff viewing as a company" case — see routes/portal.ts) sees
// one consistent nav idiom in both areas instead of two unrelated ones.
//
// Loaded before every other admin-*-page.jsx file, and after
// portal-icons.jsx (see index.html) so AdminShell + the icon set are
// both available on window by the time they run.

// GROUPED NAV (this pass — "menu is getting very busy, needs some
// grouping"): 16 flat items was too much to scan at a glance, so the
// sidebar now mirrors a pattern like Teltonika RMS's own nav (grouped
// sections, each collapsible via a chevron, only one open at a time by
// default) — see ShellNavSection below. `ADMIN_NAV_ITEMS` stays a FLAT
// array (unchanged shape: id/label/icon/superAdminOnly/allowedRoles) so
// every existing consumer that walks it flat (role-filtering, id
// look-ups) keeps working untouched; a new sibling constant,
// ADMIN_NAV_GROUPS, layers the visual grouping on top by referencing
// item ids. Approvals stays pinned above the groups, ungrouped — it's
// the default landing page and the single most frequent action, so it
// shouldn't be one click deeper than everything else.
const ADMIN_NAV_ITEMS = [
  { id: "admin-approvals", label: "Approvals", icon: IconApprovals },
  { id: "admin-companies", label: "Customers", icon: IconCustomers },
  { id: "admin-assets", label: "Assets", icon: IconAssets },
  { id: "admin-pricing", label: "Price List", icon: IconPriceList },
  { id: "admin-quotes", label: "Quotes", icon: IconQuote },
  { id: "admin-orders", label: "Orders", icon: IconOrders },
  { id: "admin-invoices", label: "Invoices", icon: IconInvoices },
  { id: "admin-purchase-orders", label: "Purchase Orders", icon: IconPurchaseOrders },
  { id: "admin-spec-sheets", label: "Spec Sheets", icon: IconSpecSheets },
  { id: "admin-user-manuals", label: "User Manuals", icon: IconUserManuals },
  { id: "admin-tickets", label: "Support Tickets", icon: IconTicketList },
  { id: "admin-email-log", label: "Email Log", icon: IconBell },
  { id: "admin-router-sms", label: "Router SMS", icon: IconBell },
  // RUT241 eSIM Auto Provisioning — a closed 3-role area (super_admin /
  // technical_admin / production_admin), never visible to plain "admin"
  // Solo Staff (e.g. Jay) or any customer/reseller — see
  // lib/rut241Roles.ts's header comment for why this is a fixed list
  // rather than the usual "everyone gets read access" admin default.
  // Uses `allowedRoles` rather than `superAdminOnly` since this needs
  // an "any of N specific roles" gate, not a single boolean.
  { id: "admin-rut241-dashboard", label: "RUT241 eSIM", icon: IconRouter, allowedRoles: ["super_admin", "technical_admin", "production_admin"] },
  // Mission Control rearchitecture Phase 1 (§10-13 of the spec) — global
  // hardware templates. Everyone can view (read-only for role "admin",
  // enforced both here via ActionButton's readOnly prop and on the
  // backend via requireSuperAdmin — see routes/admin-device-profiles.ts).
  { id: "admin-device-profiles", label: "Device Profiles", icon: IconDeviceProfile },
  // Solo Vision AI Edge/Cloud (migrations/0059_solo_vision_ai.sql,
  // migrations/0061_asset_category_vision_ai.sql) -- entry-phase asset
  // restructuring (customer: "Edge and Cloud management (Ai) will be two
  // separate areas under assets") folded both management areas directly
  // INTO the Assets page (see admin-assets-page.jsx's ASSET_SECTIONS tab
  // bar) instead of this standalone top-level page. admin-vision-ai.ts's
  // API and the underlying admin-vision-ai-page.jsx component are both
  // unchanged and still reachable -- only this sidebar entry is removed,
  // so re-exposing it as its own page again later (the customer's own
  // "may move later" caveat) is a one-line change, not a rebuild.
  { id: "admin-settings", label: "Settings", icon: IconSettings },
  // Master-admin-only — Jay (role: "admin") can't see the Staff nav item at
  // all, matching the backend's requireSuperAdmin gate on every route in
  // routes/admin-staff.ts (he couldn't do anything on the page even if he
  // guessed the URL, but hiding the nav item avoids a confusing dead end).
  { id: "admin-staff", label: "Staff", icon: IconStaff, superAdminOnly: true },
];

// Every ADMIN_NAV_ITEMS id except "admin-approvals" (pinned above the
// groups, see comment above) must appear in exactly one group below —
// enforced at runtime by an assertion right after this array (dev-time
// safety net so a future new nav item can't silently go missing from
// the sidebar just because someone forgot to slot it into a group).
const ADMIN_NAV_GROUPS = [
  {
    id: "customers", label: "Customers", icon: IconCustomers,
    itemIds: ["admin-companies"],
  },
  {
    id: "assets-devices", label: "Assets & Devices", icon: IconAssets,
    itemIds: ["admin-assets", "admin-device-profiles", "admin-rut241-dashboard"],
  },
  {
    id: "sales", label: "Sales", icon: IconQuote,
    itemIds: ["admin-pricing", "admin-quotes", "admin-orders", "admin-invoices", "admin-purchase-orders"],
  },
  {
    id: "support-docs", label: "Support & Docs", icon: IconSpecSheets,
    itemIds: ["admin-spec-sheets", "admin-user-manuals", "admin-tickets"],
  },
  {
    id: "comms-logs", label: "Comms & Logs", icon: IconBell,
    itemIds: ["admin-email-log", "admin-router-sms"],
  },
  {
    id: "system", label: "System", icon: IconSettings,
    itemIds: ["admin-settings", "admin-staff"],
  },
];

if (typeof window !== "undefined" && window.location && window.location.hostname === "localhost") {
  const groupedIds = new Set(ADMIN_NAV_GROUPS.flatMap((g) => g.itemIds));
  const missing = ADMIN_NAV_ITEMS.filter((item) => item.id !== "admin-approvals" && !groupedIds.has(item.id));
  if (missing.length) {
    // eslint-disable-next-line no-console
    console.warn("[admin-shell] nav item(s) missing from ADMIN_NAV_GROUPS:", missing.map((m) => m.id));
  }
}

// MERGED (customer decision): "asset management and mission control is
// the same" — there is no separate Mission Control escape hatch/button
// any more. Mission Control now lives INSIDE the Assets flow: clicking
// an asset row on the Assets page opens unit-management-page.jsx, which
// is Mission Control (see that file's header comment). The standalone
// mission-control.jsx file and its MISSION_CONTROL_ENTRY_ID route are
// kept on disk, unrouted, in case any of their component styling is
// worth reusing later, but neither is reachable from this shell any more.

// Which nav group (if any) contains `page` -- either as a direct item
// id, or (RUT241 only) any of its own sub-page ids sharing the same
// "section active" convention ShellNavButton already used pre-grouping.
function adminNavGroupForPage(page) {
  return ADMIN_NAV_GROUPS.find((g) =>
    g.itemIds.includes(page) || (g.itemIds.includes("admin-rut241-dashboard") && page.startsWith("admin-rut241"))
  );
}

// Persists which groups are open across navigations (AdminShell itself
// remounts on every page change -- each admin-*-page.jsx mounts its own
// fresh <AdminShell>, so local useState alone would reset to closed on
// every click). The group containing the CURRENT page is always forced
// open on top of whatever was saved, so a deep link or a fresh sign-in
// never lands on a page whose group is collapsed.
const ADMIN_NAV_EXPANDED_STORAGE_KEY = "solo-admin-nav-expanded-groups";

function loadExpandedGroups(page) {
  const activeGroup = adminNavGroupForPage(page);
  let saved = [];
  try {
    const raw = window.localStorage.getItem(ADMIN_NAV_EXPANDED_STORAGE_KEY);
    const parsed = raw ? JSON.parse(raw) : [];
    if (Array.isArray(parsed)) saved = parsed;
  } catch { /* localStorage unavailable (private mode, etc) -- fall through */ }
  return activeGroup ? Array.from(new Set([...saved, activeGroup.id])) : saved;
}

// `admin`: the signed-in admin user object (id/name/email/role) or null
// while still loading — pages fetch this themselves via /api/admin/me
// (unchanged from before) and pass it straight through.
// `page`: current page id (one of ADMIN_NAV_ITEMS' ids) — highlights the
// active nav entry.
// `title`/`subtitle`: rendered in the shared page-header block. Either
// can be omitted (e.g. a page that wants a fully custom header) and the
// header block won't render at all.
// `actions`: optional ReactNode rendered top-right of the header (e.g. a
// "+ Add unit" button) — mirrors where each page used to put its own
// action button before this refactor.
// `children`: the page's own body content, unchanged.
function AdminShell({ admin, page, onNavigate, title, subtitle, actions, children }) {
  // Relies on `useState` already being in scope from primitives.jsx's
  // top-level `const { useState, ... } = React;` (loaded first -- see
  // index.html) -- same pattern portal-icons.jsx's ShellNavButton uses.
  // Not re-declared here: classic (non-module) <script> tags share one
  // global lexical environment, so a second top-level `const useState`
  // would throw a redeclaration SyntaxError.
  const [expandedGroups, setExpandedGroups] = useState(() => loadExpandedGroups(page));

  const toggleGroup = (groupId) => {
    setExpandedGroups((prev) => {
      const next = prev.includes(groupId) ? prev.filter((id) => id !== groupId) : [...prev, groupId];
      try { window.localStorage.setItem(ADMIN_NAV_EXPANDED_STORAGE_KEY, JSON.stringify(next)); } catch { /* ignore */ }
      return next;
    });
  };

  const handleLogout = async () => {
    try { await fetch("/api/admin/logout", { method: "POST", credentials: "same-origin" }); }
    finally { onNavigate("home"); }
  };

  return (
    <section style={{ background: "#fff", color: "#000", minHeight: "calc(100vh - 88px)", display: "flex" }}>
      <aside
        data-testid="admin-shell-sidebar"
        style={{
          width: 240, flex: "0 0 240px",
          borderRight: "1px solid rgba(0,0,0,0.1)",
          display: "flex", flexDirection: "column",
          position: "sticky", top: 88, height: "calc(100vh - 88px)",
          alignSelf: "flex-start",
        }}
      >
        <div style={{ padding: "30px 26px 22px" }}>
          <div style={{
            fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 15,
            letterSpacing: "0.04em", textTransform: "uppercase", color: "#000",
          }}>Solo Admin</div>
          <div style={{
            fontFamily: "var(--font-body)", fontSize: 10, letterSpacing: "0.2em",
            textTransform: "uppercase", color: "rgba(0,0,0,0.4)", fontWeight: 500, marginTop: 4,
          }}>Staff area</div>
        </div>

        <nav style={{ display: "flex", flexDirection: "column", gap: 1, flex: 1, overflowY: "auto", padding: "4px 12px" }}>
          {(() => {
            const visible = (item) =>
              (!item.superAdminOnly || (admin && admin.role === "super_admin")) &&
              (!item.allowedRoles || (admin && item.allowedRoles.includes(admin.role)));
            const itemsById = Object.fromEntries(ADMIN_NAV_ITEMS.map((item) => [item.id, item]));
            const isActive = (item) =>
              page === item.id || (item.id === "admin-rut241-dashboard" && page.startsWith("admin-rut241"));

            return (
              <>
                {/* Approvals -- pinned above every group, ungrouped (default
                    landing page, most frequent action; see ADMIN_NAV_GROUPS
                    header comment above). */}
                {itemsById["admin-approvals"] && visible(itemsById["admin-approvals"]) && (
                  <ShellNavButton
                    label={itemsById["admin-approvals"].label} Icon={itemsById["admin-approvals"].icon}
                    active={isActive(itemsById["admin-approvals"])}
                    onClick={() => onNavigate("admin-approvals")}
                    testId="admin-nav-admin-approvals" dark={false}
                  />
                )}

                {ADMIN_NAV_GROUPS.map((group) => {
                  const groupItems = group.itemIds.map((id) => itemsById[id]).filter((item) => item && visible(item));
                  if (!groupItems.length) return null; // whole group hidden if every item inside is role-gated out
                  const groupActive = groupItems.some(isActive);
                  const expanded = expandedGroups.includes(group.id);
                  return (
                    <div key={group.id} style={{ marginTop: 2 }}>
                      <ShellNavSection
                        label={group.label} Icon={group.icon} expanded={expanded} active={groupActive}
                        onClick={() => toggleGroup(group.id)}
                        testId={`admin-nav-group-${group.id}`}
                      />
                      {expanded && (
                        <div style={{ display: "flex", flexDirection: "column", gap: 1 }}>
                          {groupItems.map((item) => (
                            <ShellNavButton
                              key={item.id} label={item.label} Icon={item.icon}
                              active={isActive(item)}
                              onClick={() => onNavigate(item.id)}
                              testId={`admin-nav-${item.id}`} dark={false} indent
                            />
                          ))}
                        </div>
                      )}
                    </div>
                  );
                })}
              </>
            );
          })()}
        </nav>

        <div style={{ padding: "0 22px 24px", borderTop: "1px solid rgba(0,0,0,0.1)", paddingTop: 18 }}>
          {admin && (
            <div style={{
              fontFamily: "var(--font-body)", fontSize: 11.5, color: "rgba(0,0,0,0.5)",
              marginBottom: 14, wordBreak: "break-word", lineHeight: 1.5,
            }}>
              Signed in as<br /><span style={{ color: "#000", fontWeight: 500 }}>{admin.email}</span>
            </div>
          )}
          <button
            type="button" onClick={handleLogout} data-testid="admin-nav-logout"
            style={{
              width: "100%", background: "none", border: "1px solid rgba(0,0,0,0.25)",
              color: "rgba(0,0,0,0.75)", cursor: "pointer", padding: "10px 14px",
              fontFamily: "var(--font-body)", fontSize: 11.5, fontWeight: 500,
              letterSpacing: "0.12em", textTransform: "uppercase",
              display: "flex", alignItems: "center", justifyContent: "center", gap: 8,
              transition: "background 140ms, color 140ms, border-color 140ms",
            }}
            onMouseEnter={(e) => { e.currentTarget.style.background = "#000"; e.currentTarget.style.color = "#fff"; e.currentTarget.style.borderColor = "#000"; }}
            onMouseLeave={(e) => { e.currentTarget.style.background = "none"; e.currentTarget.style.color = "rgba(0,0,0,0.75)"; e.currentTarget.style.borderColor = "rgba(0,0,0,0.25)"; }}
          >
            <IconSignOut size={14} />
            Sign out
          </button>
        </div>
      </aside>

      <div style={{ flex: 1, minWidth: 0, padding: "48px 40px 120px" }}>
        <div style={{ maxWidth: 1100, margin: "0 auto" }}>
          {(title || subtitle || actions) && (
            <div style={{
              display: "flex", justifyContent: "space-between", alignItems: "flex-start",
              flexWrap: "wrap", gap: 20, marginBottom: 36,
              borderBottom: "1px solid rgba(0,0,0,0.1)", paddingBottom: 30,
            }}>
              <div>
                {subtitle && (
                  <div style={{
                    fontFamily: "var(--font-body)", fontSize: 10, letterSpacing: "0.28em",
                    textTransform: "uppercase", color: "rgba(0,0,0,0.42)",
                    fontWeight: 500, marginBottom: 12,
                  }}>{subtitle}</div>
                )}
                {title && (
                  <h1 style={{
                    fontFamily: "var(--font-display)", fontWeight: 700,
                    fontSize: "clamp(26px, 3.6vw, 38px)", textTransform: "uppercase",
                    margin: 0, color: "#000",
                  }}>{title}</h1>
                )}
              </div>
              {actions && <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>{actions}</div>}
            </div>
          )}
          {children}
        </div>
      </div>

      <AskSoloAiWidget mode="admin" />
    </section>
  );
}

Object.assign(window, { AdminShell, ADMIN_NAV_ITEMS, ADMIN_NAV_GROUPS });
