// Users & Permissions module
// Access tiers expand to a set of allowed actions.
const TIER = {
  none:   [],
  view:   ["View", "Export"],
  edit:   ["View", "Create", "Edit", "Export"],
  manage: ["View", "Create", "Edit", "Approve", "Export"],
  full:   ["View", "Create", "Edit", "Delete", "Approve", "Export"]
};
// `label` is resolved at render time (T() is not available at module scope).
const LEVEL = {
  full:   { key: "usr.levelFull",   cls: "green" },
  manage: { key: "usr.levelManage", cls: "blue" },
  edit:   { key: "usr.levelEdit",   cls: "blue" },
  view:   { key: "usr.levelView",   cls: "amber" },
  none:   { key: "usr.levelNone",   cls: "muted" },
  custom: { key: "usr.levelCustom", cls: "amber" }
};
const STATUS_TONE = { Active: "green", Invited: "blue", Suspended: "red" };

function roleById(id) { return D.roles.find((r) => r.id === id) || D.roles[0]; }
// matrix shape: { [module]: { [subPage]: [actions] } }
function buildMatrix(role) {
  const m = {};
  D.permModules.forEach((mod) => {
    const acts = TIER[role.access[mod]] || [];
    m[mod] = {};
    D.permSubs[mod].forEach((sub) => { m[mod][sub] = [...acts]; });
  });
  return m;
}
function tierOf(acts) {
  for (const k of Object.keys(TIER)) {
    const v = TIER[k];
    if (v.length === acts.length && v.every((a) => acts.includes(a))) return k;
  }
  return "custom";
}
function subSets(mx, mod) { return D.permSubs[mod].map((s) => mx[mod][s]); }
function moduleTier(mx, mod) {
  const sets = subSets(mx, mod);
  const first = sets[0] || [];
  const same = sets.every((s) => s.length === first.length && s.every((a) => first.includes(a)));
  return same ? tierOf(first) : "custom";
}
function parentState(mx, mod, action) {
  const sets = subSets(mx, mod);
  const c = sets.filter((s) => s.includes(action)).length;
  return c === 0 ? "off" : (c === sets.length ? "on" : "partial");
}
// action helpers — "View" is required for any other permission
function addAct(set, a) { if (set.includes(a)) return set; const n = [...set, a]; if (a !== "View" && !n.includes("View")) n.unshift("View"); return n; }
function rmAct(set, a) { return a === "View" ? [] : set.filter((x) => x !== a); }
function toggleAct(set, a) {
  const has = set.includes(a);
  if (a === "View") return has ? [] : ["View"];
  return has ? rmAct(set, a) : addAct(set, a);
}

/* ---------- styled checkbox for the matrix ---------- */
function PmCheck({ state, on, disabled, onClick }) {
  const st = state || (on ? "on" : "off");
  return (
    <button type="button" className={"pm-check " + st + (disabled ? " locked" : "")}
      disabled={disabled} onClick={onClick} aria-pressed={st === "on"}>
      {st === "on" ? <Icon name="check" size={12} stroke={2.8} /> : st === "partial" ? <Icon name="minus" size={12} stroke={2.8} /> : null}
    </button>
  );
}

function Users({ go }) {
  const { useState } = React;
  const [tab, setTab] = useState("users");
  const [users, setUsers] = useState(D.users);

  const [matrices, setMatrices] = useState(() => {
    const all = {};
    D.roles.forEach((r) => { all[r.id] = buildMatrix(r); });
    return all;
  });

  /* ---- users tab state ---- */
  const [q, setQ] = useState("");
  const [statusFilter, setStatusFilter] = useState("all");
  const [open, setOpen] = useState(null);
  const [invite, setInvite] = useState(false);
  const [inv, setInv] = useState({ email: "", role: "Viewer", msg: "" });

  /* ---- roles tab state ---- */
  const [selRole, setSelRole] = useState("admin");
  const [expanded, setExpanded] = useState({});

  const memberCount = (rid) => users.filter((u) => u.role === rid).length;
  const roleName = (rid) => roleById(rid).name;

  const counts = {
    total: users.length,
    active: users.filter((u) => u.status === "Active").length,
    invited: users.filter((u) => u.status === "Invited").length,
    admins: users.filter((u) => u.role === "owner" || u.role === "admin").length
  };

  const statusTabs = [
    { id: "all", label: T("common.all"), n: users.length },
    { id: "Active", label: TV("Active"), n: counts.active },
    { id: "Invited", label: TV("Invited"), n: counts.invited },
    { id: "Suspended", label: TV("Suspended"), n: users.filter((u) => u.status === "Suspended").length }
  ];

  const filtered = users.filter((u) => {
    if (statusFilter !== "all" && u.status !== statusFilter) return false;
    const s = q.trim().toLowerCase();
    if (!s) return true;
    return (u.name + " " + u.email + " " + roleName(u.role)).toLowerCase().includes(s);
  });

  /* ---- user actions ---- */
  const setUserRole = (id, rid) => {
    setUsers((us) => us.map((u) => (u.id === id ? { ...u, role: rid } : u)));
    setOpen((o) => (o && o.id === id ? { ...o, role: rid } : o));
    notify(T("usr.roleUpdatedTo", { role: TV(roleName(rid)) }));
  };
  const setUserStatus = (id, status) => {
    setUsers((us) => us.map((u) => (u.id === id ? { ...u, status } : u)));
    setOpen((o) => (o && o.id === id ? { ...o, status } : o));
    notify(status === "Suspended" ? T("usr.userSuspended") : T("usr.userReactivated"));
  };
  const removeUser = (id) => { setUsers((us) => us.filter((u) => u.id !== id)); setOpen(null); notify(T("usr.userRemoved")); };
  const sendInvite = () => {
    const email = inv.email.trim();
    if (!email) { notify(T("usr.errEnterEmail")); return; }
    const rid = (D.roles.find((r) => r.name === inv.role) || D.roles[D.roles.length - 1]).id;
    const name = email.split("@")[0].split(/[._]/).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join(" ");
    const id = "U-" + String(users.length + 12).padStart(2, "0");
    setUsers((us) => [...us, { id, name, email, role: rid, status: "Invited", twofa: false, last: "—", joined: "2026" }]);
    setInvite(false);
    setInv({ email: "", role: "Viewer", msg: "" });
    notify(T("usr.invitationSentTo", { email: email }));
  };

  /* ---- permission actions ---- */
  const role = roleById(selRole);
  const matrix = matrices[selRole];
  const locked = role.locked;

  const updateModule = (mod, fn) =>
    setMatrices((prev) => {
      const next = {};
      D.permSubs[mod].forEach((s) => { next[s] = fn(prev[selRole][mod][s], s); });
      return { ...prev, [selRole]: { ...prev[selRole], [mod]: { ...prev[selRole][mod], ...next } } };
    });

  const toggleSub = (mod, sub, action) => {
    if (locked) return;
    setMatrices((prev) => ({
      ...prev,
      [selRole]: { ...prev[selRole], [mod]: { ...prev[selRole][mod], [sub]: toggleAct(prev[selRole][mod][sub], action) } }
    }));
  };
  const toggleModule = (mod, action) => {
    if (locked) return;
    const want = parentState(matrix, mod, action) !== "on";   // turn all on unless already all on
    updateModule(mod, (set) => (want ? addAct(set, action) : rmAct(set, action)));
  };
  const setModuleTier = (mod, tier) => {
    if (locked) return;
    updateModule(mod, () => [...TIER[tier]]);
  };
  const resetRole = () => { setMatrices((prev) => ({ ...prev, [selRole]: buildMatrix(role) })); notify(T("usr.roleReset", { role: TV(role.name) })); };
  const grantedCount = D.permModules.filter((m) => subSets(matrix, m).some((s) => s.length > 0)).length;

  const allOpen = D.permModules.every((m) => expanded[m]);
  const toggleAll = () => { const v = !allOpen; const e = {}; D.permModules.forEach((m) => { e[m] = v; }); setExpanded(e); };

  return (
    <div className="page" data-screen-label="Users & Permissions">
      <KpiBar>
        <Stat label={T("usr.totalUsers")} value={String(counts.total)} sub={T("usr.activeSeatsN", { n: counts.active })} />
        <Stat label={TV("Active")} value={String(counts.active)} sub={T("usr.signedInThisMonth")} />
        <Stat label={T("usr.pendingInvites")} value={String(counts.invited)} sub={T("usr.awaitingFirstSignIn")} />
        <Stat label={T("usr.administrators")} value={String(counts.admins)} sub={T("usr.ownerPlusAdmins")} />
      </KpiBar>

      <Tabs active={tab} onChange={setTab} tabs={[
        { id: "users", label: T("usr.users"), count: users.length },
        { id: "roles", label: T("usr.rolesAndPermissions"), count: D.roles.length }
      ]} />

      {tab === "users" ? (
        <><div className="toolbar page-toolbar">
            <div className="toolbar-left">
              <Chips options={statusTabs.map((s) => ({ id: s.id, label: s.label, count: s.n }))}
                active={statusFilter} onChange={setStatusFilter} />
            </div>
            <div className="toolbar-right">
              <div className="searchbox">
                <Icon name="search" size={15} />
                <input placeholder={T("usr.searchPeople")} value={q} onChange={(e) => setQ(e.target.value)} />
              </div>
              <Btn variant="primary" icon="plus" onClick={() => setInvite(true)}>{T("usr.inviteUser")}</Btn>
            </div>
          </div>
        <section className="card">
          <DataTable tableId="users" rowKey={(r) => r.id} rows={filtered} onRow={(r) => setOpen(r)}
            empty={T("usr.noPeopleMatch")} cols={[
              { k: "name", label: T("usr.user"), render: (r) => (
                  <span className="cellwho">
                    <Avatar name={r.name} size={30} />
                    <span className="who2"><b>{r.name}</b><small>{r.email}</small></span>
                  </span>
                ) },
              { k: "role", label: T("usr.role"), w: "150px", render: (r) => {
                  const ro = roleById(r.role);
                  return <span className="rolepill">{ro.locked ? <Icon name="lock" size={12} /> : <span className={"roledot " + r.role}></span>}{TV(ro.name)}</span>;
                } },
              { k: "status", label: T("common.status"), w: "120px", render: (r) => <Badge tone={STATUS_TONE[r.status]}>{r.status}</Badge> },
              { k: "twofa", label: T("usr.twoFa"), w: "70px", align: "center", render: (r) => (
                  r.twofa
                    ? <span className="twofa on" title={T("usr.twoFactorEnabled")}><Icon name="shield" size={15} /></span>
                    : <span className="twofa off" title={T("usr.twoFactorOff")}><Icon name="minus" size={15} /></span>
                ) },
              { k: "last", label: T("usr.lastActive"), w: "120px", align: "right", render: (r) => <span className="dim mono">{TV(r.last)}</span> }
            ]} />
        </section></>
      ) : null}

      {tab === "roles" ? (
        <div className="roles-grid">
          <section className="card pad">
            <SectionHead title={T("usr.roles")} action={<Btn small icon="plus" onClick={() => notify(T("usr.newRoleComingSoon"))}>{T("usr.newRole")}</Btn>} />
            <ul className="role-list">
              {D.roles.map((r) => (
                <li key={r.id}>
                  <button className={"role-card" + (selRole === r.id ? " on" : "")} onClick={() => setSelRole(r.id)}>
                    <span className={"role-mark " + r.id}>{r.locked ? <Icon name="lock" size={13} /> : <Icon name="shield" size={13} />}</span>
                    <span className="role-card-main">
                      <b>{TV(r.name)}</b>
                      <small>{TP("usr.memberCount", memberCount(r.id))}</small>
                    </span>
                    <Icon name="chevR" size={15} />
                  </button>
                </li>
              ))}
            </ul>
          </section>

          <section className="card">
            <div className="role-pad">
              <div className="role-head">
                <div className="role-head-id">
                  <div className="role-head-title">
                    <span className={"role-mark lg " + role.id}>{locked ? <Icon name="lock" size={16} /> : <Icon name="shield" size={16} />}</span>
                    <div>
                      <h3 className="display">{TV(role.name)}</h3>
                      <p className="role-head-meta">{TP("usr.memberCount", memberCount(role.id))} · {T("usr.accessToModules", { granted: grantedCount, total: D.permModules.length })}</p>
                    </div>
                  </div>
                  <div className="btnrow">
                    <Btn small onClick={resetRole} disabled={locked}>{T("common.reset")}</Btn>
                    <Btn small variant="primary" onClick={() => notify(T("usr.permissionsSaved", { role: TV(role.name) }))} disabled={locked}>{T("common.saveChanges")}</Btn>
                  </div>
                </div>
                <p className="role-desc">{TV(role.desc)}</p>
                {locked ? (
                  <div className="role-locked"><Icon name="lock" size={14} />{T("usr.ownerRoleLocked")}</div>
                ) : null}
              </div>
            </div>

            <div className="pm-bar">
              <span className="pm-bar-hint">{T("usr.matrixHint")}</span>
              <button className="pm-expand" onClick={toggleAll}>
                <Icon name="chevD" size={13} style={{ transform: allOpen ? "rotate(180deg)" : "none" }} />
                {allOpen ? T("common.collapseAll") : T("common.expandAll")}
              </button>
            </div>

            <div className="pm-scroll">
              <div className="pm" style={{ "--cols": D.permActions.length }}>
                <div className="pm-row pm-head">
                  <span className="pm-mod">{T("usr.moduleAndPages")}</span>
                  {D.permActions.map((a) => <span key={a} className="pm-cell">{TV(a)}</span>)}
                </div>
                {D.permModules.map((mod) => {
                  const isOpen = !!expanded[mod];
                  const lv = LEVEL[moduleTier(matrix, mod)];
                  return (
                    <React.Fragment key={mod}>
                      <div className={"pm-row pm-parent" + (isOpen ? " open" : "")}>
                        <div className="pm-mod">
                          <button className="pm-twist" onClick={() => setExpanded((e) => ({ ...e, [mod]: !e[mod] }))} aria-label={isOpen ? T("common.collapse") : T("common.expand")} aria-expanded={isOpen}>
                            <Icon name="chevR" size={14} style={{ transform: isOpen ? "rotate(90deg)" : "none" }} />
                          </button>
                          <button className="pm-mod-name-btn" onClick={() => setExpanded((e) => ({ ...e, [mod]: !e[mod] }))}>
                            <span className="pm-mod-name">{TV(mod)}</span>
                            <span className="pm-sub-count">{D.permSubs[mod].length}</span>
                          </button>
                          <span className={"pm-level " + lv.cls}>{T(lv.key)}</span>
                        </div>
                        {D.permActions.map((a) => (
                          <span key={a} className="pm-cell">
                            <PmCheck state={parentState(matrix, mod, a)} disabled={locked} onClick={() => toggleModule(mod, a)} />
                          </span>
                        ))}
                      </div>
                      {isOpen ? D.permSubs[mod].map((sub) => (
                        <div key={sub} className="pm-row pm-sub">
                          <span className="pm-mod pm-submod"><span className="pm-sub-name">{TV(sub)}</span></span>
                          {D.permActions.map((a) => (
                            <span key={a} className="pm-cell">
                              <PmCheck on={matrix[mod][sub].includes(a)} disabled={locked} onClick={() => toggleSub(mod, sub, a)} />
                            </span>
                          ))}
                        </div>
                      )) : null}
                    </React.Fragment>
                  );
                })}
              </div>
            </div>
          </section>
        </div>
      ) : null}

      {/* ---- user detail drawer ---- */}
      <Drawer open={!!open} onClose={() => setOpen(null)}
        title={open ? open.name : ""} sub={open ? open.email : ""}
        footer={open ? (
          <div className="je-foot">
            <Btn icon="key" onClick={() => notify(T("usr.resetLinkSent", { email: open.email }))}>{T("usr.resetPassword")}</Btn>
            <div className="btnrow">
              {open.status === "Suspended"
                ? <Btn icon="check" onClick={() => setUserStatus(open.id, "Active")}>{T("usr.reactivate")}</Btn>
                : <Btn icon="ban" onClick={() => setUserStatus(open.id, "Suspended")}>{T("usr.suspend")}</Btn>}
              <Btn variant="primary" onClick={() => setOpen(null)}>{T("common.done")}</Btn>
            </div>
          </div>
        ) : null}>
        {open ? (() => {
          const ro = roleById(open.role);
          const mx = matrices[open.role];
          return (
            <div>
              <div className="udetail">
                <Avatar name={open.name} size={52} />
                <div className="udetail-id">
                  <b>{open.name}</b>
                  <span className="dim">{open.email}</span>
                  <span className="udetail-tags">
                    <Badge tone={STATUS_TONE[open.status]}>{open.status}</Badge>
                    <span className={"twofa-tag" + (open.twofa ? " on" : "")}>
                      <Icon name={open.twofa ? "shield" : "minus"} size={13} />{open.twofa ? T("usr.twoFaOn") : T("usr.twoFaOff")}
                    </span>
                  </span>
                </div>
              </div>

              <div className="formsec">{T("usr.access")}</div>
              <Field label={T("usr.role")}>
                <SearchSelect options={D.roles.map((r) => r.name)} value={ro.name}
                  onChange={(name) => { const r = D.roles.find((x) => x.name === name); if (r) setUserRole(open.id, r.id); }} />
              </Field>
              <p className="formhint" style={{ marginTop: -4 }}>{TV(ro.desc)}</p>

              <div className="formsec">{T("usr.modulePermissions")}</div>
              <ul className="access-list">
                {D.permModules.map((mod) => {
                  const lv = LEVEL[moduleTier(mx, mod)];
                  return (
                    <li key={mod} className="access-row">
                      <span>{TV(mod)}</span>
                      <span className={"pm-level " + lv.cls}>{T(lv.key)}</span>
                    </li>
                  );
                })}
              </ul>

              <div className="formsec">{T("usr.dangerZone")}</div>
              <button className="udanger" onClick={() => removeUser(open.id)}>
                <Icon name="trash" size={15} />
                <span><b>{T("usr.removeFromWorkspace")}</b><small>{T("usr.removeWarning")}</small></span>
              </button>
            </div>
          );
        })() : null}
      </Drawer>

      {/* ---- invite modal ---- */}
      <Modal open={invite} onClose={() => setInvite(false)} title={T("usr.inviteAUser")}
        sub={T("usr.inviteSub")}
        footer={(
          <div className="je-foot">
            <span></span>
            <div className="btnrow">
              <Btn onClick={() => setInvite(false)}>{T("common.cancel")}</Btn>
              <Btn variant="primary" icon="send" onClick={sendInvite}>{T("usr.sendInvite")}</Btn>
            </div>
          </div>
        )}>
        <Field label={T("usr.emailAddress")}>
          <Input type="email" placeholder="name@northgate.co" value={inv.email}
            onChange={(e) => setInv({ ...inv, email: e.target.value })} autoFocus />
        </Field>
        <Field label={T("usr.role")}>
          <SearchSelect options={D.roles.filter((r) => !r.locked).map((r) => r.name)} value={inv.role}
            onChange={(v) => setInv({ ...inv, role: v })} />
        </Field>
        <p className="formhint" style={{ marginTop: -4 }}>{TV((D.roles.find((r) => r.name === inv.role) || {}).desc)}</p>
        <Field label={T("usr.personalNoteOptional")}>
          <textarea className="input area" rows={3} placeholder={T("usr.welcomeMessagePlaceholder")}
            value={inv.msg} onChange={(e) => setInv({ ...inv, msg: e.target.value })}></textarea>
        </Field>
      </Modal>
    </div>
  );
}
window.Users = Users;
