/* ════════════════════════════════════════════════════════════════════════
   MSINDAHA Operations — SHELL
   Router (#/tab/id — deep links, back/forward), sidebar, topbar, command
   palette, keyboard shortcuts, the data/permission context, auth gate and
   the root render. Loaded last.
════════════════════════════════════════════════════════════════════════ */

const LAST_TAB_KEY = "msindaha_last_tab";
const parseHash = () => {
  const h = (window.location.hash || "").replace(/^#\/?/, "");
  if (!h) return { tab: null, id: null };
  const [tab, ...rest] = h.split("/");
  return { tab: tab || null, id: rest.length ? decodeURIComponent(rest.join("/")) || null : null };
};
const hashFor = (tab, id) => `#/${tab}${id ? `/${encodeURIComponent(id)}` : ""}`;

function useRouter() {
  const [route, setRoute] = React.useState(() => {
    const r = parseHash();
    if (r.tab) return r;
    // Links from the website pages use ?tab=… — honour them once.
    const q = new URLSearchParams(window.location.search).get("tab");
    let last = null;
    try {
      last = localStorage.getItem(LAST_TAB_KEY);
    } catch {}
    return { tab: q || last || "dashboard", id: null };
  });
  React.useEffect(() => {
    // Normalize the URL once: drop the one-shot ?tab=, keep anything else.
    const sp = new URLSearchParams(window.location.search);
    sp.delete("tab");
    const qs = sp.toString();
    window.history.replaceState(
      window.history.state,
      "",
      `${window.location.pathname}${qs ? `?${qs}` : ""}${hashFor(route.tab, route.id)}`,
    );
    const sync = () => {
      const r = parseHash();
      setRoute({ tab: r.tab || "dashboard", id: r.id });
    };
    window.addEventListener("popstate", sync);
    window.addEventListener("hashchange", sync);
    return () => {
      window.removeEventListener("popstate", sync);
      window.removeEventListener("hashchange", sync);
    };
  }, []);
  React.useEffect(() => {
    try {
      localStorage.setItem(LAST_TAB_KEY, route.tab);
    } catch {}
  }, [route.tab]);

  const navigate = React.useCallback((tab, id = null, { replace = false } = {}) => {
    const hash = hashFor(tab, id);
    if (hash !== window.location.hash) {
      if (replace) window.history.replaceState(window.history.state, "", hash);
      else window.history.pushState({ inApp: true }, "", hash);
    }
    setRoute({ tab, id });
  }, []);
  // Closing a detail drawer: step back if we opened it in-app (so Back /
  // Forward behave), otherwise replace (deep link / fresh load).
  const closeDetail = React.useCallback(
    (tab) => {
      if (window.history.state?.inApp) window.history.back();
      else navigate(tab, null, { replace: true });
    },
    [navigate],
  );
  return { route, navigate, closeDetail };
}

/* ═══════════════════════ SIDEBAR ═══════════════════════ */
function NavLink({ item, active, collapsed, onNavigate }) {
  const content = (
    <>
      <item.icon />
      <span className="nav-label">{item.label}</span>
      {item.badge > 0 && <span className={cx("nav-badge", item.badgeTone && `nav-badge-${item.badgeTone}`)}>{item.badge > 99 ? "99+" : item.badge}</span>}
      {item.external && <IC.External />}
    </>
  );
  if (item.href)
    return (
      <a className={cx("nav-item", item.accent && "nav-accent")} href={item.href} title={collapsed ? item.label : undefined}>
        {content}
      </a>
    );
  return (
    <a
      className={cx("nav-item", active && "active")}
      href={hashFor(item.id)}
      title={collapsed ? item.label : undefined}
      aria-current={active ? "page" : undefined}
      onClick={(e) => {
        if (e.ctrlKey || e.metaKey || e.shiftKey || e.button === 1) return;
        e.preventDefault();
        onNavigate(item.id);
      }}
    >
      {content}
    </a>
  );
}

function Sidebar({ collapsed, onToggle, mobileOpen, onCloseMobile, badges, online }) {
  const { route, navigate, role, me, isSuperAdmin } = useApp();
  const groups = [
    {
      label: "Workspace",
      items: [
        { id: "dashboard", label: "Dashboard", icon: IC.Home },
        { id: "tickets", label: "Tickets", icon: IC.Ticket, badge: badges.tickets },
        { id: "tasks", label: "Tasks & Notes", icon: IC.Tasks, badge: badges.tasks },
        { id: "notifications", label: "Notifications", icon: IC.Bell, badge: badges.notifications, badgeTone: "red" },
      ],
    },
    ...(CFG.features.website
      ? [
          {
            label: "Website",
            items: [
              { href: "pages/insights.html", label: "Insights", icon: IC.Blog },
              { href: "pages/contacts.html", label: "Contact messages", icon: IC.Mail },
              { href: "pages/settings.html", label: "Website settings", icon: IC.Gear },
            ],
          },
        ]
      : []),
    {
      label: "Company",
      items: [
        ...(CFG.features.hr ? [{ id: "hr", label: "HR System", icon: IC.Users }] : []),
        ...(isAdminRole(role) ? [{ id: "users", label: "User management", icon: IC.Shield }] : []),
        ...(isSuperAdmin
          ? Object.entries(CFG.dashboards)
              .filter(([d]) => d !== MY_DEPARTMENT)
              .map(([d, url]) => ({ href: url, label: `${deptLabelOf(d)} dashboard`, icon: IC.Layers, accent: true }))
          : []),
      ],
    },
  ].filter((g) => g.items.length);

  return (
    <>
      <aside className={cx("sidebar", collapsed && "collapsed", mobileOpen && "mobile-open")} aria-label="Main navigation">
        <div className="sidebar-brand">
          <span className="brand-mark" aria-hidden="true">
            M
          </span>
          <div className="brand-text">
            <div className="brand-name">MSINDAHA</div>
            <div className="brand-sub">{CFG.deptLabel} Department</div>
          </div>
          <button
            className="icon-btn sm sidebar-toggle"
            onClick={onToggle}
            title={collapsed ? "Expand sidebar" : "Collapse sidebar"}
            aria-label={collapsed ? "Expand sidebar" : "Collapse sidebar"}
          >
            <IC.PanelLeft />
          </button>
        </div>
        <nav className="sidebar-nav">
          {groups.map((g) => (
            <div className="nav-group" key={g.label}>
              <div className="nav-section-label">{g.label}</div>
              {g.items.map((item) => (
                <NavLink
                  key={item.id || item.href}
                  item={item}
                  active={route.tab === item.id}
                  collapsed={collapsed}
                  onNavigate={(id) => {
                    navigate(id);
                    onCloseMobile();
                  }}
                />
              ))}
            </div>
          ))}
        </nav>
        <div className="sidebar-footer">
          <div className="sidebar-user" title={`${me.name} · ${me.email}`}>
            <Avatar name={me.name} email={me.email} size={30} />
            <div className="sidebar-user-text">
              <div className="sidebar-user-name">{me.name}</div>
              <div className="sidebar-user-role">
                {roleLabel(role)}
                {role !== "super-admin" ? ` · ${CFG.deptLabel}` : ""}
              </div>
            </div>
          </div>
          <div className={cx("sidebar-status", !online && "offline")}>
            <span className="live-dot" />
            <span className="sidebar-status-text">{online ? "Live — synced in real time" : "Offline — changes will sync"}</span>
          </div>
        </div>
      </aside>
      <div className={cx("sidebar-scrim", mobileOpen && "show")} onClick={onCloseMobile} />
    </>
  );
}

/* ═══════════════════════ TOPBAR ═══════════════════════ */
const PAGE_TITLES = {
  dashboard: "Dashboard",
  tickets: "Tickets",
  tasks: "Tasks & Notes",
  notifications: "Notifications",
  hr: "HR System",
  users: "User management",
};
function UserMenu({ onShortcuts, onSignOut }) {
  const { me, role, isSuperAdmin, navigate } = useApp();
  return (
    <Dropdown
      width={260}
      placement="bottom-end"
      trigger={({ ref, toggle, open }) => (
        <button ref={ref} className={cx("user-chip", open && "active")} onClick={toggle} aria-label="Account menu">
          <Avatar name={me.name} email={me.email} size={30} title="" />
          <span className="user-chip-text">
            <span className="user-chip-name">{me.name}</span>
            <span className="user-chip-role">{roleLabel(role)}</span>
          </span>
          <IC.ChevronDown />
        </button>
      )}
    >
      {({ close }) => (
        <>
          <div className="user-menu-head">
            <Avatar name={me.name} email={me.email} size={38} />
            <div className="user-menu-id">
              <div className="user-menu-name">{me.name}</div>
              <div className="user-menu-email">{me.email}</div>
              <span className={cx("badge", `tone-${ROLE_TONES[role] || "gray"}`)}>
                {roleLabel(role)}
                {role !== "super-admin" ? ` · ${CFG.deptLabel}` : ""}
              </span>
            </div>
          </div>
          <MenuList>
            <MenuItem
              icon={IC.Bell}
              onSelect={() => {
                close();
                navigate("notifications");
              }}
            >
              Notification settings
            </MenuItem>
            <MenuItem
              icon={IC.Command}
              hint="?"
              onSelect={() => {
                close();
                onShortcuts();
              }}
            >
              Keyboard shortcuts
            </MenuItem>
            {isSuperAdmin &&
              Object.entries(CFG.dashboards)
                .filter(([d]) => d !== MY_DEPARTMENT)
                .map(([d, url]) => (
                  <MenuItem key={d} icon={IC.Layers} onSelect={() => (window.location.href = url)}>
                    Switch to {deptLabelOf(d)}
                  </MenuItem>
                ))}
            <MenuSep />
            <MenuItem
              icon={IC.LogOut}
              danger
              onSelect={() => {
                close();
                onSignOut();
              }}
            >
              Sign out
            </MenuItem>
          </MenuList>
        </>
      )}
    </Dropdown>
  );
}
function Topbar({ onMenu, onSearch, onShortcuts, onSignOut, online }) {
  const { route } = useApp();
  const isMac = /Mac|iPhone|iPad/.test(navigator.platform || "");
  return (
    <header className="topbar">
      <button className="icon-btn topbar-menu" onClick={onMenu} aria-label="Open navigation">
        <IC.Menu />
      </button>
      <div className="topbar-page">{PAGE_TITLES[route.tab]}</div>
      <button className="topbar-search" onClick={onSearch} aria-label="Search or jump to">
        <IC.Search />
        <span className="topbar-search-text">Search tickets, tasks or jump to…</span>
        <span className="kbd-combo">
          <Kbd>{isMac ? "⌘" : "Ctrl"}</Kbd>
          <Kbd>K</Kbd>
        </span>
      </button>
      <div className="topbar-right">
        {!online && (
          <span className="offline-pill" title="Changes are saved locally and will sync when you're back online">
            <IC.WifiOff /> Offline
          </span>
        )}
        <NotificationBell />
        <span className="topbar-sep" />
        <UserMenu onShortcuts={onShortcuts} onSignOut={onSignOut} />
      </div>
    </header>
  );
}

/* ═══════════════════════ COMMAND PALETTE ═══════════════════════ */
function CommandPalette({ open, onClose, onShortcuts }) {
  const app = useApp();
  const { tickets, tasks, navigate, role, me } = app;
  const { mounted, closing } = usePresence(open, 160);
  useLayer(open, onClose);
  const [q, setQ] = React.useState("");
  const [sel, setSel] = React.useState(0);
  const inputRef = React.useRef(null);
  const listRef = React.useRef(null);
  React.useEffect(() => {
    if (open) {
      setQ("");
      setSel(0);
      setTimeout(() => inputRef.current?.focus(), 30);
    }
  }, [open]);

  const go = (tab, id) => () => navigate(tab, id);
  const commands = [
    { label: "New ticket", icon: IC.Plus, run: go("tickets", "new"), hint: "C" },
    { label: "New task", icon: IC.Plus, run: go("tasks", "new") },
    { label: "Go to Dashboard", icon: IC.Home, run: go("dashboard"), hint: "G D" },
    { label: "Go to Tickets", icon: IC.Ticket, run: go("tickets"), hint: "G T" },
    { label: "Go to Tasks & Notes", icon: IC.Tasks, run: go("tasks"), hint: "G K" },
    { label: "Go to Notifications", icon: IC.Bell, run: go("notifications"), hint: "G N" },
    ...(CFG.features.hr ? [{ label: "Go to HR System", icon: IC.Users, run: go("hr") }] : []),
    ...(isAdminRole(role) ? [{ label: "Go to User management", icon: IC.Shield, run: go("users") }] : []),
    ...(CFG.features.website
      ? [
          { label: "Open Insights (website)", icon: IC.Blog, run: () => (window.location.href = "pages/insights.html") },
          { label: "Open Contact messages", icon: IC.Mail, run: () => (window.location.href = "pages/contacts.html") },
        ]
      : []),
    { label: "Keyboard shortcuts", icon: IC.Command, run: onShortcuts, hint: "?" },
  ];
  const s = q.trim().toLowerCase();
  const match = (txt) => s.split(/\s+/).every((w) => txt.toLowerCase().includes(w));
  const tk = s
    ? tickets.rows.filter((t) => match(`${t.displayId} ${t.title} ${t.category || ""}`)).slice(0, 7)
    : tickets.rows.filter((t) => isAssignedToMe(t, me.uid) && ticketIsActive(t)).slice(0, 4);
  const ts = s
    ? tasks.rows.filter((t) => match(`${t.displayId || ""} ${t.title}`)).slice(0, 5)
    : tasks.rows.filter((t) => taskIsMineToDo(t, me.uid) && !taskFinished(t, me.uid)).slice(0, 3);
  const cmds = s ? commands.filter((c) => match(c.label)) : commands;
  const groups = [
    { label: s ? "Tickets" : "Your open tickets", items: tk.map((t) => ({ key: t._id, label: t.title, sub: t.displayId, node: <StatusBadge status={t.status} />, icon: IC.Ticket, run: go("tickets", t._id) })) },
    { label: s ? "Tasks" : "Your tasks", items: ts.map((t) => ({ key: t._id, label: t.title, sub: t.displayId, node: <DueChip due={t.dueDate} done={false} compact />, icon: IC.Tasks, run: go("tasks", t._id) })) },
    { label: "Commands", items: cmds.map((c) => ({ ...c, key: c.label })) },
  ].filter((g) => g.items.length);
  const flat = groups.flatMap((g) => g.items);
  React.useEffect(() => setSel(0), [q]);
  React.useEffect(() => {
    listRef.current?.querySelector(".cmdk-item.active")?.scrollIntoView({ block: "nearest" });
  }, [sel]);
  const run = (item) => {
    if (!item) return;
    onClose();
    setTimeout(() => item.run(), 0);
  };
  if (!mounted) return null;
  let n = -1;
  return (
    <Portal>
      <div className={cx("cmdk-overlay", closing && "closing")} onMouseDown={(e) => e.target === e.currentTarget && onClose()}>
        <div className={cx("cmdk", closing && "closing")} role="dialog" aria-label="Command palette">
          <div className="cmdk-input">
            <IC.Search />
            <input
              ref={inputRef}
              value={q}
              onChange={(e) => setQ(e.target.value)}
              placeholder="Search tickets and tasks, or type a command…"
              onKeyDown={(e) => {
                if (e.key === "ArrowDown") {
                  e.preventDefault();
                  setSel((v) => Math.min(flat.length - 1, v + 1));
                } else if (e.key === "ArrowUp") {
                  e.preventDefault();
                  setSel((v) => Math.max(0, v - 1));
                } else if (e.key === "Enter") {
                  e.preventDefault();
                  run(flat[sel]);
                }
              }}
            />
            <Kbd>Esc</Kbd>
          </div>
          <div className="cmdk-list" ref={listRef}>
            {flat.length === 0 && <div className="cmdk-empty">No results for “{q}”.</div>}
            {groups.map((g) => (
              <div key={g.label} className="cmdk-group">
                <div className="cmdk-group-label">{g.label}</div>
                {g.items.map((item) => {
                  n += 1;
                  const i = n;
                  return (
                    <button
                      key={item.key}
                      className={cx("cmdk-item", i === sel && "active")}
                      onMouseMove={() => i !== sel && setSel(i)}
                      onClick={() => run(item)}
                    >
                      <span className="cmdk-icon">
                        <item.icon />
                      </span>
                      {item.sub && <span className="tk-id">{item.sub}</span>}
                      <span className="cmdk-label">{item.label}</span>
                      {item.node}
                      {item.hint && <span className="cmdk-hint">{item.hint}</span>}
                    </button>
                  );
                })}
              </div>
            ))}
          </div>
          <div className="cmdk-foot">
            <span>
              <Kbd>↑</Kbd>
              <Kbd>↓</Kbd> navigate
            </span>
            <span>
              <Kbd>Enter</Kbd> open
            </span>
            <span>
              <Kbd>Esc</Kbd> close
            </span>
          </div>
        </div>
      </div>
    </Portal>
  );
}

function ShortcutsModal({ open, onClose }) {
  const rows = [
    ["Ctrl / ⌘ + K", "Search & command palette"],
    ["/", "Focus the search box"],
    ["C", "Create a ticket or task (on its page)"],
    ["J / K", "Next / previous item in a detail panel"],
    ["Ctrl + Enter", "Save a form or send a comment"],
    ["Esc", "Close the top-most panel or menu"],
    ["G then D", "Go to Dashboard"],
    ["G then T", "Go to Tickets"],
    ["G then K", "Go to Tasks"],
    ["G then N", "Go to Notifications"],
    ["?", "Show this list"],
  ];
  return (
    <Modal open={open} onClose={onClose} size="sm" icon={IC.Command} title="Keyboard shortcuts">
      <div className="shortcut-list">
        {rows.map(([k, d]) => (
          <div key={k} className="shortcut-row">
            <span>{d}</span>
            <span className="shortcut-keys">
              {k.split(" ").map((part, i) =>
                ["then", "+", "/"].includes(part) ? (
                  <span key={i} className="muted">
                    {part === "then" ? "then" : part}
                  </span>
                ) : (
                  <Kbd key={i}>{part}</Kbd>
                ),
              )}
            </span>
          </div>
        ))}
      </div>
    </Modal>
  );
}

/* ═══════════════════════ SHELL ═══════════════════════ */
const PAGES = {
  dashboard: DashboardOverview,
  tickets: TicketsPage,
  tasks: TasksPage,
  notifications: NotificationsPage,
  hr: HRSystem,
  users: UserManagement,
};

function Shell({ online, onSignOut }) {
  const app = useApp();
  const { route, navigate, me, tickets, tasks } = app;
  const notif = useNotifications();
  const [collapsed, setCollapsed] = useLocalStorage("msindaha_sidebar_collapsed", false);
  const [mobileOpen, setMobileOpen] = React.useState(false);
  const [paletteOpen, setPaletteOpen] = React.useState(false);
  const [shortcutsOpen, setShortcutsOpen] = React.useState(false);
  const mainRef = React.useRef(null);

  React.useEffect(() => {
    if (mainRef.current) mainRef.current.scrollTop = 0;
    setMobileOpen(false);
  }, [route.tab]);

  // Global shortcuts: Ctrl/⌘+K, "?", and "g" sequences.
  React.useEffect(() => {
    let gAt = 0;
    const onKey = (e) => {
      if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setPaletteOpen((o) => !o);
        return;
      }
      if (e.ctrlKey || e.metaKey || e.altKey || isTypingTarget(document.activeElement) || __layers.length) return;
      if (e.key === "?") {
        e.preventDefault();
        setShortcutsOpen(true);
        return;
      }
      if (e.key === "g") {
        gAt = Date.now();
        return;
      }
      if (Date.now() - gAt < 1200) {
        const map = { d: "dashboard", t: "tickets", k: "tasks", n: "notifications" };
        if (map[e.key]) {
          e.preventDefault();
          navigate(map[e.key]);
        }
        gAt = 0;
      }
    };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [navigate]);

  const badges = {
    tickets: tickets.rows.filter((t) => isAssignedToMe(t, me.uid) && ticketIsActive(t)).length,
    tasks: tasks.rows.filter((t) => taskIsMineToDo(t, me.uid) && !taskFinished(t, me.uid)).length,
    notifications: notif.unread,
  };
  const Page = PAGES[route.tab] || DashboardOverview;

  return (
    <div className={cx("app-shell", collapsed && "sidebar-collapsed")}>
      <Sidebar
        collapsed={collapsed}
        onToggle={() => setCollapsed((c) => !c)}
        mobileOpen={mobileOpen}
        onCloseMobile={() => setMobileOpen(false)}
        badges={badges}
        online={online}
      />
      <div className="main-col">
        <Topbar
          onMenu={() => setMobileOpen(true)}
          onSearch={() => setPaletteOpen(true)}
          onShortcuts={() => setShortcutsOpen(true)}
          onSignOut={onSignOut}
          online={online}
        />
        <main className="main" ref={mainRef}>
          <div className="page" key={route.tab}>
            <Page route={route} />
          </div>
        </main>
      </div>
      <CommandPalette open={paletteOpen} onClose={() => setPaletteOpen(false)} onShortcuts={() => setShortcutsOpen(true)} />
      <ShortcutsModal open={shortcutsOpen} onClose={() => setShortcutsOpen(false)} />
    </div>
  );
}

/* ═══════════════════════ WORKSPACE (data + permissions) ═══════════════════════ */
function WorkspaceReady({ user, profile }) {
  const toast = useToast();
  const role = profile.role;
  const me = React.useMemo(
    () => ({
      uid: user.uid,
      email: user.email || "",
      name: profile.name || user.displayName || (user.email || "").split("@")[0] || "User",
    }),
    [user.uid, user.email, profile.name],
  );
  const deptVersion = useDepartments(true);
  const tickets = useCollection("tickets", { dept: MY_DEPARTMENT });
  const tasks = useScopedCollection("tasks", user.uid, MY_DEPARTMENT);
  const notes = useScopedCollection("notes", user.uid, MY_DEPARTMENT);
  const usersCol = useCollection("users", { orderField: null });
  const { route, navigate, closeDetail } = useRouter();
  const online = useOnline();
  const isSuperAdmin = role === "super-admin";

  const allowedTabs = [
    "dashboard",
    "tickets",
    "tasks",
    "notifications",
    ...(CFG.features.hr ? ["hr"] : []),
    ...(isAdminRole(role) ? ["users"] : []),
  ];
  React.useEffect(() => {
    if (!allowedTabs.includes(route.tab)) navigate("dashboard", null, { replace: true });
  }, [route.tab, role]);

  const dataRef = React.useRef({});
  dataRef.current = { tickets: tickets.rows, tasks: tasks.rows };
  // Opening an item from a notification. Items created on the other
  // department's dashboard open there (for Super Admins) when they aren't
  // visible here.
  const openItem = React.useCallback(
    ({ tab, id, dept }) => {
      if (!id) return navigate(tab || "notifications");
      const rows = tab === "tickets" ? dataRef.current.tickets : dataRef.current.tasks;
      const here = rows.some((r) => r._id === id);
      if (!here && dept && dept !== MY_DEPARTMENT && CFG.dashboards[dept]) {
        window.location.href = `${CFG.dashboards[dept]}${hashFor(tab, id)}`;
        return;
      }
      navigate(tab, id);
    },
    [navigate],
  );

  // Once a day: a gentle reminder about overdue / due-today work.
  React.useEffect(() => {
    if (!tickets.loaded || !tasks.loaded) return;
    const key = `msindaha_due_reminder_${user.uid}`;
    const today = todayISO();
    try {
      if (localStorage.getItem(key) === today) return;
      localStorage.setItem(key, today);
    } catch {
      return;
    }
    const mine = [
      ...tickets.rows.filter((t) => isAssignedToMe(t, user.uid) && ticketIsActive(t)),
      ...tasks.rows.filter((t) => taskIsMineToDo(t, user.uid) && !taskFinished(t, user.uid)),
    ];
    const overdue = mine.filter((x) => dueInfo(x.dueDate, false)?.state === "overdue").length;
    const dueToday = mine.filter((x) => dueInfo(x.dueDate, false)?.state === "today").length;
    if (!overdue && !dueToday) return;
    setTimeout(
      () =>
        toast({
          type: overdue ? "warning" : "info",
          title: overdue ? `You have ${plural(overdue, "overdue item")}` : `${plural(dueToday, "item")} due today`,
          msg: overdue && dueToday ? `Plus ${dueToday} due today.` : "Review your work on the dashboard.",
          duration: 10000,
          action: { label: "Review", onClick: () => navigate("dashboard") },
        }),
      1200,
    );
  }, [tickets.loaded, tasks.loaded]);

  const signOut = async () => {
    clearDataCaches();
    try {
      if (window.__fb.websiteAuth) await window.__fb.signOut(window.__fb.websiteAuth).catch(() => {});
      await window.__fb.signOut(window.__fb.auth);
    } catch (e) {
      toast({ type: "error", title: "Couldn't sign out", msg: e.message });
    }
  };

  const ctx = {
    user,
    me,
    profile,
    role,
    canEdit: isEditorRole(role),
    canDelete: isAdminRole(role),
    isSuperAdmin,
    users: usersCol.rows,
    usersLoaded: usersCol.loaded,
    usersApi: usersCol,
    tickets,
    tasks,
    notes,
    route,
    navigate,
    closeDetail,
    toast,
    deptVersion,
  };
  return (
    <AppCtx.Provider value={ctx}>
      <NotificationsProvider uid={user.uid} onOpenItem={openItem}>
        <Shell online={online} onSignOut={signOut} />
      </NotificationsProvider>
    </AppCtx.Provider>
  );
}

function FullLoader({ label = "Loading…", hint, action }) {
  return (
    <div className="loading-screen">
      <span className="boot-mark">M</span>
      <Spinner size={22} />
      <span>{label}</span>
      {hint && <span className="muted">{hint}</span>}
      {action}
    </div>
  );
}

function Workspace({ user }) {
  const profile = useProfile(user);
  const wrongDept = profile && profile.role !== "super-admin" && profile.department !== MY_DEPARTMENT;
  const target = wrongDept ? CFG.dashboards[profile.department] : null;
  React.useEffect(() => {
    // Each department has its own dashboard; only Super Admins see both.
    if (target) window.location.replace(`${target}${window.location.hash}`);
  }, [target]);
  if (profile === undefined) return <FullLoader label="Loading your workspace…" />;
  if (profile === null) return <AccessDenied user={user} />;
  if (wrongDept)
    return target ? (
      <FullLoader label={`Opening the ${deptLabelOf(profile.department)} dashboard…`} />
    ) : (
      <AccessScreen title="No dashboard for your department yet" email={user.email}>
        Your account belongs to <strong>{deptLabelOf(profile.department)}</strong>, which doesn't have a dashboard yet. Ask a Super
        Admin to move you to the right department.
      </AccessScreen>
    );
  return <WorkspaceReady user={user} profile={profile} />;
}

function AuthGate() {
  const [user, setUser] = React.useState(undefined);
  React.useEffect(() => window.__fb.onAuth(window.__fb.auth, (u) => setUser(u ?? null)), []);
  React.useEffect(() => {
    if (user === null && CFG.loginUrl) window.location.replace(CFG.loginUrl);
  }, [user]);
  if (user === undefined) return <FullLoader label="Signing you in…" />;
  if (user === null) return CFG.loginUrl ? <FullLoader label="Redirecting to sign in…" /> : <LoginScreen />;
  return <Workspace key={user.uid} user={user} />;
}

function Root() {
  const [ready, setReady] = React.useState(!!window.__fb);
  const [slow, setSlow] = React.useState(false);
  React.useEffect(() => {
    if (window.__fb) return;
    const onReady = () => setReady(true);
    window.addEventListener("fb-ready", onReady);
    const t = setTimeout(() => setSlow(true), 12000);
    return () => {
      window.removeEventListener("fb-ready", onReady);
      clearTimeout(t);
    };
  }, []);
  if (!ready)
    return (
      <FullLoader
        label={slow ? "Still connecting…" : "Connecting…"}
        hint={slow ? "Check your internet connection." : null}
        action={
          slow && (
            <button className="btn" onClick={() => window.location.reload()}>
              <IC.Refresh /> Retry
            </button>
          )
        }
      />
    );
  return (
    <ToastProvider>
      <ConfirmProvider>
        <AuthGate />
      </ConfirmProvider>
    </ToastProvider>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<Root />);
