/* ════════════════════════════════════════════════════════════════════════
   MSINDAHA Operations — PAGES
   Dashboard overview, HR portal links, User Management, and the
   sign-in / access screens.
════════════════════════════════════════════════════════════════════════ */

/* ─── Website stats (separate msindaha-web Firebase project) — loaded
   lazily through the existing read-only services. A stalled channel is
   treated as an error after a grace period instead of shimmering forever. */
function useWebsiteOverview(enabled) {
  const [state, setState] = React.useState({ articles: [], contacts: [], aLoaded: false, cLoaded: false, errored: false });
  React.useEffect(() => {
    if (!enabled) return;
    let unsubA = () => {};
    let unsubC = () => {};
    let cancelled = false;
    const timeout = setTimeout(() => !cancelled && setState((s) => (s.aLoaded && s.cLoaded ? s : { ...s, errored: true })), 12000);
    const load =
      window.__websiteServices ||
      (() => Promise.all([import("./js/services/articles.service.js"), import("./js/services/contacts.service.js")]));
    load()
      .then(([articlesSvc, contactsSvc]) => {
        if (cancelled) return;
        unsubA = articlesSvc.subscribeArticles((rows) => setState((s) => ({ ...s, articles: rows, aLoaded: true, errored: false })));
        unsubC = contactsSvc.subscribeContacts((rows) => setState((s) => ({ ...s, contacts: rows, cLoaded: true, errored: false })));
      })
      .catch((err) => {
        console.error("Website overview load error:", err);
        if (!cancelled) setState((s) => ({ ...s, errored: true }));
      });
    return () => {
      cancelled = true;
      clearTimeout(timeout);
      unsubA();
      unsubC();
    };
  }, [enabled]);
  return { ...state, loading: !state.errored && !(state.aLoaded && state.cLoaded) };
}

// Opens the Tickets page with a given set of filters applied.
function openTicketsWith(navigate, patch) {
  try {
    localStorage.setItem(
      TICKET_PREFS_KEY,
      JSON.stringify({ ...TICKET_PREFS_DEFAULTS, ...patch, layout: JSON.parse(localStorage.getItem(TICKET_PREFS_KEY) || "{}").layout || "list" }),
    );
  } catch {}
  navigate("tickets");
}
function openTasksWith(navigate, patch) {
  try {
    localStorage.setItem(TASK_PREFS_KEY, JSON.stringify({ ...TASK_PREFS_DEFAULTS, ...patch }));
  } catch {}
  navigate("tasks");
}

function StatTile({ label, value, sub, icon: Icon, tone = "blue", onClick, loading, i = 0 }) {
  const Tag = onClick ? "button" : "div";
  return (
    <Tag type={onClick ? "button" : undefined} className={cx("stat-card", onClick && "stat-click")} onClick={onClick} style={{ "--i": i }}>
      <span className={cx("stat-icon", `tone-${tone}`)}>
        <Icon />
      </span>
      <span className="stat-lbl">{label}</span>
      <span className="stat-val">{loading ? <Skeleton w={36} h={26} /> : value}</span>
      {sub && <span className="stat-sub">{sub}</span>}
    </Tag>
  );
}

/* One feed of recent events across tickets and tasks. */
function collectActivity(tickets, tasks, limit = 12) {
  const out = [];
  const add = (item, coll) => {
    if (item.createdAt)
      out.push({
        key: `${coll}-${item._id}-created`,
        at: item.createdAt,
        who: item.createdBy,
        text: coll === "tickets" ? "opened" : "created",
        item,
        coll,
      });
    (item.comments || []).forEach((c, i) => {
      if (!c.at) return;
      out.push({
        key: `${coll}-${item._id}-${i}`,
        at: c.at,
        who: c.author,
        text: c.kind === "event" ? c.text.replace(/ this( ticket| task)?\b/, "") : "commented on",
        isComment: c.kind !== "event",
        item,
        coll,
      });
    });
  };
  tickets.forEach((t) => add(t, "tickets"));
  tasks.filter((t) => t.visibility === "shared").forEach((t) => add(t, "tasks"));
  return out.sort((a, b) => b.at.localeCompare(a.at)).slice(0, limit);
}

function DashboardOverview() {
  const app = useApp();
  const { me, tickets, tasks, navigate, canEdit, profile } = app;
  const notif = useNotifications();
  const website = useWebsiteOverview(CFG.features.website);
  useNow();
  const tk = tickets.rows;
  const ts = tasks.rows;

  const myTickets = tk.filter((t) => isAssignedToMe(t, me.uid) && ticketIsActive(t));
  const myTasks = ts.filter((t) => taskIsMineToDo(t, me.uid) && !taskFinished(t, me.uid));
  const active = tk.filter(ticketIsActive);
  const unassigned = active.filter(isUnassigned);
  const weekStart = toISODate(startOfWeek(new Date()));
  const resolvedWeek = tk.filter((t) => ticketIsDone(t) && (localDateOf(t.completedAt || t.closedAt) || "") >= weekStart).length;
  const overdueOf = (list, isTask) =>
    list.filter((x) => dueInfo(x.dueDate, isTask ? taskFinished(x, me.uid) : ticketIsFinished(x))?.state === "overdue").length;
  const loading = !tickets.loaded || !tasks.loaded;

  // "My work": everything on my plate, most urgent first.
  const work = [
    ...myTickets.map((t) => ({ kind: "tickets", item: t, status: t.status })),
    ...myTasks.map((t) => ({ kind: "tasks", item: t, status: taskStatusOf(t) })),
  ].sort((a, b) => {
    const da = a.item.dueDate || "9999-99-99";
    const db = b.item.dueDate || "9999-99-99";
    return da.localeCompare(db) || (PRIORITY_RANK[a.item.priority] ?? 2) - (PRIORITY_RANK[b.item.priority] ?? 2);
  });
  const activity = collectActivity(tk, ts, 10);
  const pipeline = TICKET_STATUSES.map((s) => ({ s, n: tk.filter((t) => t.status === s).length }));
  const pipeMax = Math.max(1, ...pipeline.map((x) => x.n));
  const firstName = (me.name || "").split(/[\s.]+/)[0];
  const todayLong = new Date().toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" });

  return (
    <div className="page-dashboard">
      <div className="page-header dash-header">
        <div>
          <div className="dash-date">{todayLong}</div>
          <h2>
            {greeting()}, {capitalize(firstName)}
          </h2>
          <p>
            {loading
              ? "Loading your workspace…"
              : myTickets.length + myTasks.length
                ? `You have ${plural(myTickets.length, "ticket")} and ${plural(myTasks.length, "task")} on your plate.`
                : "Nothing is assigned to you right now."}
          </p>
        </div>
        <div className="page-header-actions">
          <button className="btn" onClick={() => navigate("tasks", "new")}>
            <IC.Plus /> New task
          </button>
          <button className="btn btn-primary" onClick={() => navigate("tickets", "new")}>
            <IC.Plus /> New ticket
          </button>
        </div>
      </div>

      <div className="stat-row stat-row-4">
        <StatTile
          i={0}
          label="Assigned to me"
          value={myTickets.length}
          sub={overdueOf(myTickets) ? `${overdueOf(myTickets)} overdue` : "active tickets"}
          icon={IC.Target}
          tone={overdueOf(myTickets) ? "red" : "blue"}
          loading={loading}
          onClick={() => openTicketsWith(navigate, { view: "mine", status: "active" })}
        />
        <StatTile
          i={1}
          label="Open tickets"
          value={active.length}
          sub={`${unassigned.length} unassigned`}
          icon={IC.Ticket}
          tone="indigo"
          loading={loading}
          onClick={() => openTicketsWith(navigate, { status: "active" })}
        />
        <StatTile
          i={2}
          label="My tasks"
          value={myTasks.length}
          sub={overdueOf(myTasks, true) ? `${overdueOf(myTasks, true)} overdue` : "to do"}
          icon={IC.Tasks}
          tone={overdueOf(myTasks, true) ? "red" : "amber"}
          loading={loading}
          onClick={() => openTasksWith(navigate, { view: "mine", status: "active" })}
        />
        <StatTile
          i={3}
          label="Resolved this week"
          value={resolvedWeek}
          sub="tickets resolved or closed"
          icon={IC.CheckCircle}
          tone="green"
          loading={loading}
          onClick={() => openTicketsWith(navigate, { status: "done", period: { ...EMPTY_PERIOD } })}
        />
      </div>

      <div className="dash-grid">
        <div className="card card-flush">
          <div className="card-head">
            <div className="card-title">
              <IC.Target /> My work
            </div>
            <span className="card-head-meta">{work.length ? plural(work.length, "item") : ""}</span>
          </div>
          {loading && !work.length ? (
            <div className="card-pad">
              <Skeleton w="70%" h={12} />
              <Skeleton w="50%" h={12} style={{ marginTop: 12 }} />
              <Skeleton w="60%" h={12} style={{ marginTop: 12 }} />
            </div>
          ) : work.length === 0 ? (
            <EmptyState compact icon={IC.CheckCircle} title="You're all caught up">
              New assignments will show up here.
            </EmptyState>
          ) : (
            <div className="work-list">
              {work.slice(0, 8).map(({ kind, item, status }) => (
                <button key={`${kind}-${item._id}`} className="work-row" onClick={() => navigate(kind, item._id)}>
                  <span className={cx("work-kind", kind === "tickets" ? "tone-blue" : "tone-amber")}>
                    {kind === "tickets" ? <IC.Ticket /> : <IC.Tasks />}
                  </span>
                  <span className="work-main">
                    <span className="work-title">{item.title}</span>
                    <span className="work-sub">
                      {item.displayId && <span className="tk-id">{item.displayId}</span>}
                      <StatusBadge status={status} kind={kind === "tickets" ? "ticket" : "task"} />
                    </span>
                  </span>
                  <DueChip due={item.dueDate} done={false} compact />
                  <PriorityIcon p={item.priority || "medium"} />
                </button>
              ))}
              {work.length > 8 && (
                <div className="card-foot">
                  <button className="link-btn" onClick={() => openTicketsWith(navigate, { view: "mine", status: "active" })}>
                    View all my tickets <IC.ArrowRight />
                  </button>
                </div>
              )}
            </div>
          )}
        </div>

        <div className="card card-flush">
          <div className="card-head">
            <div className="card-title">
              <IC.Activity /> Recent activity
            </div>
            <span className="live-tag">
              <span className="live-dot" /> Live
            </span>
          </div>
          {activity.length === 0 ? (
            <EmptyState compact icon={IC.Activity} title="Nothing yet">
              Ticket and task updates from your team appear here.
            </EmptyState>
          ) : (
            <div className="feed">
              {activity.map((a) => (
                <button key={a.key} className="feed-row" onClick={() => navigate(a.coll, a.item._id)}>
                  <Avatar name={a.who?.name} email={a.who?.email} size={28} />
                  <span className="feed-body">
                    <span className="feed-text">
                      <b>{a.who?.name || "Someone"}</b> {a.text} <span className="feed-item">{a.item.displayId || a.item.title}</span>
                    </span>
                    {a.isComment && <span className="feed-quote">“{(a.item.comments || []).find((c) => c.at === a.at)?.text?.slice(0, 90)}”</span>}
                    <span className="feed-time" title={fmtDateTime(a.at)}>
                      {timeAgo(a.at)}
                    </span>
                  </span>
                </button>
              ))}
            </div>
          )}
        </div>
      </div>

      <div className="dash-grid dash-grid-b">
        <div className="card">
          <div className="section-head">
            <IC.Layers /> Ticket pipeline
            <span className="section-head-count">{tk.length}</span>
          </div>
          <div className="pipeline">
            {pipeline.map(({ s, n }) => (
              <button key={s} className="pipe-row" onClick={() => openTicketsWith(navigate, { status: s })} title={`${n} ${statusLabel(s)}`}>
                <StatusBadge status={s} />
                <span className="pipe-track">
                  <span className="pipe-fill" style={{ width: n ? `${Math.max(3, (n / pipeMax) * 100)}%` : 0 }} />
                </span>
                <span className="pipe-n">{n}</span>
              </button>
            ))}
          </div>
        </div>

        <div className="card">
          <div className="section-head">
            <IC.Alert /> Needs attention
          </div>
          {(() => {
            const items = [
              ...active
                .filter((t) => dueInfo(t.dueDate, false)?.state === "overdue")
                .map((t) => ({ t, why: "Overdue", tone: "red" })),
              ...(canEdit ? unassigned.map((t) => ({ t, why: "Unassigned", tone: "indigo" })) : []),
              ...active
                .filter((t) => t.priority === "critical" && !isUnassigned(t) && dueInfo(t.dueDate, false)?.state !== "overdue")
                .map((t) => ({ t, why: "Critical", tone: "red" })),
            ];
            const seen = new Set();
            const uniq = items.filter((x) => (seen.has(x.t._id) ? false : seen.add(x.t._id)));
            if (!uniq.length)
              return (
                <EmptyState compact icon={IC.CheckCircle} title="All clear">
                  No overdue, unassigned or critical tickets.
                </EmptyState>
              );
            return (
              <div className="attention-list">
                {uniq.slice(0, 6).map(({ t, why, tone }) => (
                  <button key={t._id} className="attention-row" onClick={() => navigate("tickets", t._id)}>
                    <span className={cx("attention-why", `tone-${tone}`)}>{why}</span>
                    <span className="tk-id">{t.displayId}</span>
                    <span className="attention-title">{t.title}</span>
                    <DueChip due={t.dueDate} done={false} compact />
                  </button>
                ))}
              </div>
            );
          })()}
        </div>
      </div>

      {CFG.features.website && (
        <div className="card website-card">
          <div className="section-head">
            <IC.Globe /> Website
            <span className="section-head-meta">msindaha.com</span>
          </div>
          {website.errored ? (
            <div className="inline-alert">
              <IC.Alert /> Couldn't load website data right now. It will retry when the connection recovers.
            </div>
          ) : (
            <div className="website-stats">
              {[
                { label: "Published articles", value: website.articles.filter((a) => a.status === "published").length, href: "pages/insights.html", icon: IC.Blog, tone: "green" },
                { label: "Drafts", value: website.articles.filter((a) => a.status === "draft").length, href: "pages/insights.html", icon: IC.Edit, tone: "gray" },
                { label: "New messages", value: website.contacts.filter((c) => c.status === "inbox").length, href: "pages/contacts.html", icon: IC.Mail, tone: "blue" },
                { label: "Replied", value: website.contacts.filter((c) => c.status === "replied").length, href: "pages/contacts.html", icon: IC.CheckCheck, tone: "teal" },
              ].map((s) => (
                <a key={s.label} className="mini-stat" href={s.href}>
                  <span className={cx("stat-icon", `tone-${s.tone}`)}>
                    <s.icon />
                  </span>
                  <span>
                    <span className="mini-stat-val">{website.loading ? <Skeleton w={28} h={18} /> : s.value}</span>
                    <span className="mini-stat-lbl">{s.label}</span>
                  </span>
                </a>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
}

/* ═══════════════════════ HR SYSTEM ═══════════════════════ */
const HR_BASE = "https://hrm.msindaha.com";
const hrLink = (employeePath, staffPath) => (role) => `${HR_BASE}/${role === "employee" ? employeePath : staffPath}`;
const HR_FEATURES = [
  {
    title: "Employee records",
    desc: "Profiles, contracts and personal information.",
    icon: IC.IdCard,
    tone: "blue",
    link: hrLink("pages/employee/my-profile.html", "pages/employees/employees.html"),
  },
  {
    title: "Leave management",
    desc: "Leave requests, approvals and remaining balances.",
    icon: IC.CalendarCheck,
    tone: "purple",
    link: hrLink("pages/employee/my-leaves.html", "pages/leaves/leaves.html"),
  },
  {
    title: "Payroll",
    desc: "Salary runs, payslips and payment history.",
    icon: IC.Wallet,
    tone: "green",
    link: hrLink("pages/employee/my-payroll.html", "pages/payroll/payroll.html"),
  },
  {
    title: "Companies",
    desc: "Registered companies and their workspaces.",
    icon: IC.Building,
    tone: "amber",
    link: () => `${HR_BASE}/pages/companies/companies.html`,
  },
];
function HRSystem() {
  const { role } = useApp();
  return (
    <div className="page-hr">
      <div className="page-header">
        <div>
          <h2>HR System</h2>
          <p>Human resources and the employee self-service portal.</p>
        </div>
        <div className="page-header-actions">
          <a className="btn btn-primary" href={`${HR_BASE}/`} target="_blank" rel="noopener noreferrer">
            <IC.External /> Open HR portal
          </a>
        </div>
      </div>
      <div className="hr-hero card">
        <img src="imgs/Logowhite.png" alt="" className="hr-logo" />
        <div>
          <div className="hr-pill">
            <span className="live-dot" /> Connected · hrm.msindaha.com
          </div>
          <h3>HR Management System</h3>
          <p>
            The HR portal opens in a new tab and signs in separately from this dashboard. Each link below takes you straight to the
            section that matches your role.
          </p>
        </div>
      </div>
      <div className="hr-grid">
        {HR_FEATURES.map((f, i) => (
          <a key={f.title} className="hr-feat" href={f.link(role)} target="_blank" rel="noopener noreferrer" style={{ "--i": i }}>
            <span className={cx("hr-feat-icon", `tone-${f.tone}`)}>
              <f.icon />
            </span>
            <span className="hr-feat-body">
              <span className="hr-feat-title">{f.title}</span>
              <span className="hr-feat-desc">{f.desc}</span>
            </span>
            <span className="hr-feat-go">
              <IC.External />
            </span>
          </a>
        ))}
      </div>
    </div>
  );
}

/* ═══════════════════════ USER MANAGEMENT ═══════════════════════ */
const ROLE_TONES = { "super-admin": "purple", admin: "red", supervisor: "amber", employee: "gray" };
const genPassword = () => {
  const chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789";
  const arr = new Uint32Array(12);
  (window.crypto || window.msCrypto).getRandomValues(arr);
  return Array.from(arr, (n) => chars[n % chars.length]).join("");
};

function UserManagement() {
  const app = useApp();
  const { users, usersApi, me, role } = app;
  const toast = useToast();
  const confirm = useConfirm();
  const isSuper = role === "super-admin";
  const [q, setQ] = React.useState("");
  const [fRole, setFRole] = React.useState("all");
  const [fDept, setFDept] = React.useState("all");
  const [tab, setTab] = React.useState("active");
  const [addOpen, setAddOpen] = React.useState(false);
  const [deptOpen, setDeptOpen] = React.useState(false);
  const [renaming, setRenaming] = React.useState(null);

  const active = users.filter((u) => !u.disabled);
  const revoked = users.filter((u) => u.disabled);
  const base = tab === "active" ? active : revoked;
  const list = base
    .filter((u) => fRole === "all" || (u.role || "employee") === fRole)
    .filter((u) => fDept === "all" || (u.role === "super-admin" ? "—" : u.department || "payroll") === fDept)
    .filter((u) => !q.trim() || `${userLabel(u)} ${u.email || ""}`.toLowerCase().includes(q.trim().toLowerCase()))
    .sort((a, b) => userLabel(a).localeCompare(userLabel(b)));
  const counts = {
    total: active.length,
    admins: active.filter((u) => u.role === "admin" || u.role === "super-admin").length,
    supervisors: active.filter((u) => u.role === "supervisor").length,
    employees: active.filter((u) => (u.role || "employee") === "employee").length,
  };

  // Every write re-sends `role`: the rules validate the role of the
  // resulting document, so a legacy profile without one would be rejected.
  const patchUser = async (u, patch, okMsg) => {
    try {
      await usersApi.update(u._id, { role: u.role || "employee", ...patch });
      if (okMsg) toast({ type: "success", title: okMsg, duration: 3000 });
    } catch (e) {
      toast({ type: "error", title: "Couldn't update the user", msg: writeErrorMsg(e) });
    }
  };
  const changeRole = async (u, r) => {
    if (r === (u.role || "employee")) return;
    if (r === "super-admin" || r === "admin") {
      const ok = await confirm({
        title: `Make ${userLabel(u)} ${roleLabel(r)}?`,
        message:
          r === "super-admin"
            ? "Super Admins can see and change everything in every department, including user accounts."
            : "Admins can manage users, delete tickets and change roles in their department.",
        confirmLabel: `Make ${roleLabel(r)}`,
      });
      if (!ok) return;
    }
    patchUser(u, { role: r, ...(r === "super-admin" ? {} : { department: u.department || MY_DEPARTMENT }) }, `${userLabel(u)} is now ${roleLabel(r)}`);
  };
  const revoke = async (u) => {
    const ok = await confirm({
      title: `Revoke access for ${userLabel(u)}?`,
      message: (
        <>
          <strong>{u.email || u._id}</strong> will lose access immediately and be signed out on their next action. You can restore this
          exact account later from the “Revoked” tab.
        </>
      ),
      confirmLabel: "Revoke access",
      danger: true,
    });
    if (ok) patchUser(u, { disabled: true, disabledAt: nowISO() }, `${userLabel(u)}'s access was revoked`);
  };
  const restore = (u) => patchUser(u, { disabled: false, disabledAt: null }, `${userLabel(u)} can sign in again`);

  return (
    <div className="page-users">
      <div className="page-header">
        <div>
          <h2>User Management</h2>
          <p>Create accounts, set roles and departments, and revoke access.</p>
        </div>
        <div className="page-header-actions">
          {isSuper && (
            <button className="btn" onClick={() => setDeptOpen(true)}>
              <IC.Layers /> Add department
            </button>
          )}
          <button className="btn btn-primary" onClick={() => setAddOpen(true)}>
            <IC.UserPlus /> Add user
          </button>
        </div>
      </div>

      <div className="stat-row stat-row-4">
        <StatTile i={0} label="Active users" value={counts.total} icon={IC.Users} tone="blue" />
        <StatTile i={1} label="Admins" value={counts.admins} icon={IC.Shield} tone="red" onClick={() => { setTab("active"); setFRole("admin"); }} />
        <StatTile i={2} label="Supervisors" value={counts.supervisors} icon={IC.Target} tone="amber" onClick={() => { setTab("active"); setFRole("supervisor"); }} />
        <StatTile i={3} label="Employees" value={counts.employees} icon={IC.User} tone="gray" onClick={() => { setTab("active"); setFRole("employee"); }} />
      </div>

      <div className="list-shell">
        <div className="list-tabs">
          <ViewTabs
            value={tab}
            onChange={setTab}
            tabs={[
              { value: "active", label: "Active", count: active.length },
              { value: "revoked", label: "Revoked", count: revoked.length },
            ]}
          />
        </div>
        <div className="list-toolbar">
          <SearchInput value={q} onChange={setQ} placeholder="Search by name or email…" />
          <FilterMenu
            label="Role"
            icon={IC.Shield}
            value={fRole}
            onChange={setFRole}
            options={[{ value: "all", label: "All roles" }, ...["super-admin", "admin", "supervisor", "employee"].map((r) => ({ value: r, label: roleLabel(r) }))]}
          />
          <FilterMenu
            label="Department"
            icon={IC.Layers}
            value={fDept}
            onChange={setFDept}
            options={[{ value: "all", label: "All departments" }, ...DEPARTMENTS.map((d) => ({ value: d.id, label: d.label }))]}
          />
        </div>

        {list.length === 0 ? (
          <EmptyState icon={IC.Users} title={tab === "revoked" ? "No revoked accounts" : "No users match"}>
            {tab === "revoked" ? "Accounts you revoke can be restored from here." : "Try a different search or filter."}
          </EmptyState>
        ) : (
          <div className="user-table">
            <div className="user-head">
              <span>User</span>
              <span>Role</span>
              <span>Department</span>
              <span>Joined</span>
              <span />
            </div>
            {list.map((u, i) => {
              const isMe = u._id === me.uid;
              const r = u.role || "employee";
              // Only a Super Admin may change or revoke another Super Admin.
              const locked = isMe || (r === "super-admin" && !isSuper);
              return (
                <div key={u._id} className={cx("user-row", isMe && "is-me", u.disabled && "revoked")} style={{ "--i": Math.min(i, 14) }}>
                  <div className="user-cell-main">
                    <Avatar name={userLabel(u)} email={u.email} size={36} />
                    <div className="user-id">
                      <div className="user-name">
                        {userLabel(u)}
                        {isMe && <span className="you-tag">you</span>}
                      </div>
                      <div className="user-email" title={u.email}>
                        {u.email || u._id}
                      </div>
                    </div>
                  </div>
                  <div>
                    {u.disabled || locked ? (
                      <span className={cx("badge", `tone-${ROLE_TONES[r]}`)}>{roleLabel(r)}</span>
                    ) : (
                      <select className="inline-select" value={r} onChange={(e) => changeRole(u, e.target.value)} aria-label="Role">
                        <option value="employee">Employee</option>
                        <option value="supervisor">Supervisor</option>
                        <option value="admin">Admin</option>
                        {(isSuper || r === "super-admin") && <option value="super-admin">Super Admin</option>}
                      </select>
                    )}
                  </div>
                  <div>
                    {r === "super-admin" ? (
                      <span className="muted">All departments</span>
                    ) : u.disabled || isMe ? (
                      <span>{deptLabelOf(u.department || "payroll")}</span>
                    ) : (
                      <select
                        className="inline-select"
                        value={u.department || "payroll"}
                        onChange={(e) => patchUser(u, { department: e.target.value }, `${userLabel(u)} moved to ${deptLabelOf(e.target.value)}`)}
                        aria-label="Department"
                      >
                        {DEPARTMENTS.map((d) => (
                          <option key={d.id} value={d.id}>
                            {d.label}
                          </option>
                        ))}
                      </select>
                    )}
                  </div>
                  <div className="muted" title={fmtDateTime(u.createdAt)}>
                    {u.disabled ? `Revoked ${u.disabledAt ? fmtDateShort(u.disabledAt) : ""}` : u.createdAt ? fmtDate(u.createdAt) : "—"}
                  </div>
                  <div className="user-actions">
                    {u.disabled ? (
                      <button className="btn btn-sm" onClick={() => restore(u)}>
                        <IC.Reopen /> Restore
                      </button>
                    ) : (
                      <>
                        {(!locked || isMe) && (
                          <button className="icon-btn" title="Rename" aria-label="Rename" onClick={() => setRenaming(u)}>
                            <IC.Edit />
                          </button>
                        )}
                        {!locked && (
                          <button className="icon-btn danger" title="Revoke access" aria-label="Revoke access" onClick={() => revoke(u)}>
                            <IC.Ban />
                          </button>
                        )}
                      </>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </div>

      <AddUserModal open={addOpen} onClose={() => setAddOpen(false)} />
      <AddDepartmentModal open={deptOpen} onClose={() => setDeptOpen(false)} />
      <RenameUserModal user={renaming} onClose={() => setRenaming(null)} onSave={(u, name) => patchUser(u, { name }, "Name updated")} />
    </div>
  );
}

function RenameUserModal({ user, onClose, onSave }) {
  const [name, setName] = React.useState("");
  React.useEffect(() => {
    if (user) setName(user.name || "");
  }, [user?._id]);
  const save = async () => {
    if (!name.trim()) return;
    await onSave(user, name.trim());
    onClose();
  };
  return (
    <Modal
      open={!!user}
      onClose={onClose}
      size="sm"
      icon={IC.Edit}
      title="Rename user"
      subtitle={user?.email}
      footer={
        <>
          <button className="btn btn-ghost" onClick={onClose}>
            Cancel
          </button>
          <button className="btn btn-primary" onClick={save} disabled={!name.trim()}>
            Save
          </button>
        </>
      }
    >
      <Field label="Display name">
        <input
          className="form-input"
          value={name}
          onChange={(e) => setName(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && save()}
          data-autofocus
          placeholder="e.g. Sara Ahmed"
        />
      </Field>
    </Modal>
  );
}

function AddUserModal({ open, onClose }) {
  const app = useApp();
  const { role } = app;
  const toast = useToast();
  const isSuper = role === "super-admin";
  const blank = () => ({ name: "", email: "", password: genPassword(), role: "employee", department: MY_DEPARTMENT });
  const [form, setForm] = React.useState(blank);
  const [showPw, setShowPw] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState("");
  const [created, setCreated] = React.useState(null);
  React.useEffect(() => {
    if (open) {
      setForm(blank());
      setErr("");
      setCreated(null);
      setBusy(false);
    }
  }, [open]);
  const set = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value }));
  const cleanErr = (e) =>
    ({
      "auth/email-already-in-use":
        "This email is already registered. If it belonged to a removed employee, restore them from the “Revoked” tab instead.",
      "auth/weak-password": "Password must be at least 6 characters.",
      "auth/invalid-email": "That email address isn't valid.",
    })[e.code] ||
    e.message?.replace("Firebase: ", "").replace(/\s*\(auth\/[^)]+\)\s*\.?$/, "").trim() ||
    "Couldn't create the account.";

  const submit = async () => {
    const email = form.email.trim();
    if (!form.name.trim()) return setErr("Enter the person's full name.");
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) return setErr("Enter a valid email address.");
    if (form.password.length < 6) return setErr("The temporary password must be at least 6 characters.");
    setErr("");
    setBusy(true);
    try {
      const uid = await window.__fb.createUserAsAdmin(email, form.password);
      await window.__fb.setDoc(window.__fb.doc(window.__fb.db, "users", uid), {
        name: form.name.trim(),
        email,
        role: form.role,
        department: form.role === "super-admin" ? null : form.department,
        createdAt: nowISO(),
      });
      setCreated({ name: form.name.trim(), email, password: form.password });
    } catch (e) {
      setErr(cleanErr(e));
    } finally {
      setBusy(false);
    }
  };
  const copyCreds = async () => {
    const ok = await copyText(`Dashboard: ${location.origin}${location.pathname}\nEmail: ${created.email}\nTemporary password: ${created.password}`);
    toast({ type: ok ? "success" : "error", title: ok ? "Sign-in details copied" : "Couldn't copy", duration: 2500 });
  };

  return (
    <Modal
      open={open}
      onClose={onClose}
      icon={IC.UserPlus}
      title={created ? "Account created" : "Add user"}
      subtitle={created ? "Share these sign-in details with the new user." : "They'll sign in with this email and temporary password."}
      dirty={!created && !busy && !!(form.name || form.email)}
      footer={
        created ? (
          <>
            <button className="btn" onClick={copyCreds}>
              <IC.Copy /> Copy details
            </button>
            <button className="btn btn-primary" onClick={onClose}>
              Done
            </button>
          </>
        ) : (
          <>
            <button className="btn btn-ghost" onClick={onClose} disabled={busy}>
              Cancel
            </button>
            <button className="btn btn-primary" onClick={submit} disabled={busy}>
              {busy ? <Spinner size={14} /> : <IC.Check />} Create account
            </button>
          </>
        )
      }
    >
      {created ? (
        <div className="creds">
          <div className="creds-row">
            <span>Name</span>
            <b>{created.name}</b>
          </div>
          <div className="creds-row">
            <span>Email</span>
            <b>{created.email}</b>
          </div>
          <div className="creds-row">
            <span>Temporary password</span>
            <b className="mono">{created.password}</b>
          </div>
          <div className="form-hint">This password is shown only once — copy it now.</div>
        </div>
      ) : (
        <div className="form-stack">
          {err && <div className="auth-err">{err}</div>}
          <Field label="Full name" required>
            <input className="form-input" value={form.name} onChange={set("name")} placeholder="e.g. Sara Ahmed" data-autofocus />
          </Field>
          <Field label="Email" required>
            <input className="form-input" type="email" value={form.email} onChange={set("email")} placeholder="name@msindaha.com" />
          </Field>
          <Field label="Temporary password" required hint="Generated for you — at least 6 characters.">
            <div className="input-group">
              <input className="form-input mono" type={showPw ? "text" : "password"} value={form.password} onChange={set("password")} />
              <button type="button" className="icon-btn" title={showPw ? "Hide" : "Show"} onClick={() => setShowPw((s) => !s)}>
                {showPw ? <IC.EyeOff /> : <IC.Eye />}
              </button>
              <button type="button" className="icon-btn" title="Generate a new password" onClick={() => setForm((f) => ({ ...f, password: genPassword() }))}>
                <IC.Refresh />
              </button>
            </div>
          </Field>
          <div className="form-grid">
            <Field label="Role">
              <select className="form-select" value={form.role} onChange={set("role")}>
                <option value="employee">Employee</option>
                <option value="supervisor">Supervisor</option>
                <option value="admin">Admin</option>
                {isSuper && <option value="super-admin">Super Admin</option>}
              </select>
            </Field>
            {form.role !== "super-admin" && (
              <Field label="Department">
                <select className="form-select" value={form.department} onChange={set("department")}>
                  {DEPARTMENTS.map((d) => (
                    <option key={d.id} value={d.id}>
                      {d.label}
                    </option>
                  ))}
                </select>
              </Field>
            )}
          </div>
        </div>
      )}
    </Modal>
  );
}

function AddDepartmentModal({ open, onClose }) {
  const toast = useToast();
  const [label, setLabel] = React.useState("");
  const [err, setErr] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => {
    if (open) {
      setLabel("");
      setErr("");
    }
  }, [open]);
  const submit = async () => {
    const l = label.trim();
    const id = l.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
    if (!id) return setErr("Enter a department name (English letters or numbers).");
    if (DEPARTMENTS.some((d) => d.id === id)) return setErr("That department already exists.");
    setBusy(true);
    try {
      const { db, doc, setDoc } = window.__fb;
      await setDoc(doc(db, "departments", id), { label: l, createdAt: nowISO() });
      if (!DEPARTMENTS.some((d) => d.id === id)) DEPARTMENTS.push({ id, label: l });
      toast({ type: "success", title: `${l} department added`, duration: 3000 });
      onClose();
    } catch (e) {
      setErr(writeErrorMsg(e));
    } finally {
      setBusy(false);
    }
  };
  return (
    <Modal
      open={open}
      onClose={onClose}
      size="sm"
      icon={IC.Layers}
      title="Add department"
      footer={
        <>
          <button className="btn btn-ghost" onClick={onClose} disabled={busy}>
            Cancel
          </button>
          <button className="btn btn-primary" onClick={submit} disabled={busy || !label.trim()}>
            {busy ? <Spinner size={14} /> : <IC.Plus />} Add department
          </button>
        </>
      }
    >
      {err && <div className="auth-err">{err}</div>}
      <Field label="Department name" hint="It becomes available for users, tickets and tasks immediately.">
        <input
          className="form-input"
          value={label}
          onChange={(e) => setLabel(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && submit()}
          placeholder="e.g. Human Resources"
          data-autofocus
        />
      </Field>
    </Modal>
  );
}

/* ═══════════════════════ SIGN-IN ═══════════════════════ */
// Client-side speed bump on top of Firebase Auth's own server throttling.
const LOGIN_THROTTLE_KEY = "msindaha_login_throttle";
const LOGIN_MAX_ATTEMPTS = 5;
const LOGIN_BASE_LOCKOUT_MS = 30000;
const LOGIN_MAX_LOCKOUT_MS = 30 * 60000;
const readLoginThrottle = (key) => {
  try {
    const all = JSON.parse(localStorage.getItem(LOGIN_THROTTLE_KEY) || "{}");
    return all[key] || { attempts: 0, lockedUntil: 0, lockoutMs: LOGIN_BASE_LOCKOUT_MS };
  } catch {
    return { attempts: 0, lockedUntil: 0, lockoutMs: LOGIN_BASE_LOCKOUT_MS };
  }
};
const writeLoginThrottle = (key, entry) => {
  try {
    const all = JSON.parse(localStorage.getItem(LOGIN_THROTTLE_KEY) || "{}");
    all[key] = entry;
    localStorage.setItem(LOGIN_THROTTLE_KEY, JSON.stringify(all));
  } catch {}
};

function LoginScreen() {
  const [email, setEmail] = React.useState("");
  const [pass, setPass] = React.useState("");
  const [show, setShow] = React.useState(false);
  const [caps, setCaps] = React.useState(false);
  const [err, setErr] = React.useState("");
  const [loading, setLoading] = React.useState(false);

  const cleanErr = (e) =>
    ({
      "auth/invalid-credential": "Incorrect email or password.",
      "auth/user-not-found": "No account found with this email.",
      "auth/wrong-password": "Incorrect password.",
      "auth/invalid-email": "That email address isn't valid.",
      "auth/too-many-requests": "Too many attempts. Please wait a moment and try again.",
      "auth/user-disabled": "This account has been disabled. Contact your administrator.",
      "auth/network-request-failed": "Network error — check your connection.",
    })[e.code] ||
    e.message?.replace("Firebase: ", "").replace(/\s*\(auth\/[^)]+\)\s*\.?$/, "").trim() ||
    "Something went wrong.";

  // Mirror the session into the msindaha-web project (Insights/Contacts/
  // Settings live there). Best-effort — never blocks the main sign-in.
  const mirrorWebsiteSignIn = async () => {
    if (!window.__fb.websiteAuth) return;
    try {
      await window.__fb.signIn(window.__fb.websiteAuth, email.trim(), pass);
    } catch (e) {
      if (e.code === "auth/user-not-found" || e.code === "auth/invalid-credential") {
        try {
          await window.__fb.createWebsiteAccount(window.__fb.websiteAuth, email.trim(), pass);
        } catch (e2) {
          console.error("Website-project backfill failed:", e2);
        }
        return;
      }
      console.error("Website-project sign-in failed:", e);
    }
  };

  const submit = async (e) => {
    e.preventDefault();
    setErr("");
    const key = email.trim().toLowerCase();
    const throttle = readLoginThrottle(key);
    if (throttle.lockedUntil > Date.now()) {
      setErr(`Too many failed attempts. Try again in ${Math.ceil((throttle.lockedUntil - Date.now()) / 1000)}s.`);
      return;
    }
    setLoading(true);
    try {
      await window.__fb.signIn(window.__fb.auth, email.trim(), pass);
      writeLoginThrottle(key, { attempts: 0, lockedUntil: 0, lockoutMs: LOGIN_BASE_LOCKOUT_MS });
      mirrorWebsiteSignIn();
    } catch (error) {
      const attempts = throttle.attempts + 1;
      if (attempts >= LOGIN_MAX_ATTEMPTS) {
        const lockoutMs = throttle.lockoutMs || LOGIN_BASE_LOCKOUT_MS;
        writeLoginThrottle(key, { attempts: 0, lockedUntil: Date.now() + lockoutMs, lockoutMs: Math.min(lockoutMs * 2, LOGIN_MAX_LOCKOUT_MS) });
        setErr(`Too many failed attempts. Try again in ${Math.ceil(lockoutMs / 1000)}s.`);
      } else {
        writeLoginThrottle(key, { ...throttle, attempts });
        setErr(cleanErr(error));
      }
      setLoading(false);
    }
  };
  const capsCheck = (e) => setCaps(!!e.getModifierState?.("CapsLock"));

  return (
    <div className="login-split">
      <div className="login-hero" style={{ backgroundImage: 'url("imgs/login-bg.jpg")' }}>
        <div className="login-hero-content">
          <div className="login-hero-eyebrow">MSINDAHA · Internal use only</div>
          <div>
            <div className="login-hero-heading">Internal Ticketing &amp; Operations Management</div>
            <p className="login-hero-sub">
              One workspace for the Payroll and Audit departments to manage tickets, tasks and day-to-day operations — for authorized
              staff only.
            </p>
            <ul className="login-points">
              <li>
                <IC.CheckCircle /> Assign, track and resolve tickets in real time
              </li>
              <li>
                <IC.CheckCircle /> Delegate tasks and follow every update
              </li>
              <li>
                <IC.CheckCircle /> Instant notifications when something needs you
              </li>
            </ul>
          </div>
          <div className="login-signature">
            <div className="login-signature-name">
              Abdulhadi Abu Ashebah <span className="login-signature-role">IT Specialist</span>
            </div>
            <div className="login-signature-tag">Together towards success</div>
          </div>
        </div>
      </div>

      <div className="login-form-panel">
        <div className="auth-card">
          <div className="auth-logos">
            <img src="imgs/payroll-logo.png" alt="Payroll Department" />
            <span className="auth-logos-sep" />
            <img src="imgs/audit-logo.png" alt="Audit Department" />
          </div>
          <h1 className="auth-title">Welcome back</h1>
          <p className="auth-sub">Sign in to the Payroll &amp; Audit dashboards.</p>

          {err && (
            <div className="auth-err" role="alert">
              <IC.Alert /> {err}
            </div>
          )}

          <form onSubmit={submit} noValidate>
            <Field label="Email">
              <input
                className="form-input input-lg"
                type="email"
                autoComplete="username"
                placeholder="you@msindaha.com"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                required
                autoFocus
              />
            </Field>
            <Field label="Password" error={caps ? "Caps Lock is on." : null}>
              <div className="input-affix">
                <input
                  className="form-input input-lg"
                  type={show ? "text" : "password"}
                  autoComplete="current-password"
                  placeholder="••••••••"
                  value={pass}
                  onChange={(e) => setPass(e.target.value)}
                  onKeyUp={capsCheck}
                  onKeyDown={capsCheck}
                  required
                />
                <button type="button" className="icon-btn" onClick={() => setShow((s) => !s)} aria-label={show ? "Hide password" : "Show password"}>
                  {show ? <IC.EyeOff /> : <IC.Eye />}
                </button>
              </div>
            </Field>
            <button className="btn btn-primary btn-lg btn-block" type="submit" disabled={loading || !email || !pass}>
              {loading ? (
                <>
                  <Spinner size={15} /> Signing in…
                </>
              ) : (
                "Sign in"
              )}
            </button>
          </form>
          <p className="auth-foot">Accounts are created by your administrator. Contact them if you don't have one yet.</p>
        </div>
      </div>
    </div>
  );
}

function AccessScreen({ icon: Icon = IC.Lock, title, children, email }) {
  return (
    <div className="auth-wrap">
      <div className="auth-card auth-card-center">
        <span className="access-icon">
          <Icon />
        </span>
        <h1 className="auth-title">{title}</h1>
        <div className="auth-sub">{children}</div>
        {email && <div className="access-email">{email}</div>}
        <button className="btn btn-block" onClick={() => window.__fb.signOut(window.__fb.auth)}>
          <IC.LogOut /> Sign out
        </button>
      </div>
    </div>
  );
}
function AccessDenied({ user }) {
  return (
    <AccessScreen title="Access restricted" email={user.email}>
      This account hasn't been granted access to the {CFG.deptLabel} dashboard, or its access was revoked. Ask your administrator to add
      you in User Management.
    </AccessScreen>
  );
}
