// ELS HRM — Module 02: RBAC — Chi tiết vai trò (C) + Tạo vai trò mới (B)
// FLAT: bỏ kế thừa · sàn EMPLOYEE khóa · guardrail · scope theo quyền.

const CARD = "rounded-xl border border-border bg-card shadow-xs";
const INPUT = "h-9 w-full rounded-md border border-input bg-transparent px-3 text-base text-foreground shadow-xs placeholder:text-muted-foreground transition-colors focus:border-primary focus:outline-none focus:ring-[3px] focus:ring-ring";

const BASELINE_OWN_DOMAINS = new Set(['employees','leave','attendance','timesheet']);

// ─── Audit "Lịch sử thay đổi" — helper + meta (đồng bộ field BE trả) ─────────────
// Route GET /roles/:id/audit-logs trả CẢ hai nhóm action của vai trò (SDS 24_role-audit):
//   · Cấu hình vai trò: ROLE_CREATED/ROLE_UPDATED/ROLE_DELETED (metadata mang diff/ảnh chụp quyền)
//   · Gán/thu hồi cho user: ROLE_ASSIGNED/ROLE_REVOKED/PRIMARY_ROLE_CHANGED (targetUser + vai trò trước/sau + lý do)
const AUDIT_CONFIG_ACTIONS = ['ROLE_CREATED','ROLE_UPDATED','ROLE_DELETED'];
const AUDIT_ACTION_META = {
  ROLE_CREATED:         { label:'Tạo vai trò',       variant:'success', icon:'plus-circle', token:'success'     },
  ROLE_UPDATED:         { label:'Sửa quyền',          variant:'info',    icon:'edit',        token:'info'        },
  ROLE_DELETED:         { label:'Xoá vai trò',        variant:'danger',  icon:'trash',       token:'destructive' },
  ROLE_ASSIGNED:        { label:'Gán vai trò',        variant:'success', icon:'user-check',  token:'success'     },
  ROLE_REVOKED:         { label:'Thu hồi vai trò',    variant:'danger',  icon:'x-circle',    token:'destructive' },
  PRIMARY_ROLE_CHANGED: { label:'Đổi vai trò chính',  variant:'warning', icon:'star',        token:'warning'     },
};

// permLabel — mã quyền thô → nhãn thân thiện tiếng Việt (giữ mã gốc hiển thị kèm bên dưới).
function permLabel(code) {
  const dm = code.match(/^data:([a-z_]+):([a-z]+)$/);
  if (dm) {
    const dom = DATA_DOMAINS.find(d => d.domain === dm[1]);
    const sc  = SCOPE_META[dm[2]];
    return `${dom ? dom.label : dm[1]}: ${sc ? sc.label : dm[2]}`;
  }
  const p = SCREEN_PERMS.find(x => x.code === code) || ACTION_PERMS.find(x => x.code === code);
  return p ? p.label : code;
}

// Chip 1 mã quyền được thêm(+)/bớt(−) trong diff của ROLE_UPDATED.
function PermDiffChip({ code, kind }) {
  const add = kind === 'add';
  const color = add ? 'var(--color-success)' : 'var(--color-destructive)';
  const soft  = add ? 'var(--color-success-soft)' : 'var(--color-destructive-soft)';
  return (
    <div className="flex items-start gap-1.5">
      <span className="mt-px shrink-0 font-bold leading-5" style={{ color }}>{add ? '+' : '−'}</span>
      <div className="min-w-0">
        <span className="inline-flex items-center rounded-md px-2 py-0.5 text-xs font-semibold"
          style={{ background:soft, color }}>{permLabel(code)}</span>
        <div className="mt-px font-mono text-2xs text-muted-foreground">{code}</div>
      </div>
    </div>
  );
}

// Nội dung giữa của một dòng audit, khác nhau theo action.
function AuditContent({ ev }) {
  if (ev.action === 'ROLE_UPDATED') {
    const added   = (ev.metadata && ev.metadata.permissionsAdded)   || [];
    const removed = (ev.metadata && ev.metadata.permissionsRemoved) || [];
    if (added.length === 0 && removed.length === 0)
      return <span className="text-muted-foreground">Cập nhật thông tin vai trò (không đổi tập quyền).</span>;
    return (
      <div className="flex flex-col gap-1.5">
        {added.map(c => <PermDiffChip key={'a'+c} code={c} kind="add" />)}
        {removed.map(c => <PermDiffChip key={'r'+c} code={c} kind="remove" />)}
      </div>
    );
  }
  if (ev.action === 'ROLE_CREATED') {
    const n = ((ev.metadata && ev.metadata.permissionsSnapshot) || []).length;
    return <span className="text-foreground">Tạo vai trò · gồm <strong>{n}</strong> quyền lúc khởi tạo.</span>;
  }
  if (ev.action === 'ROLE_DELETED') {
    const n = ((ev.metadata && ev.metadata.permissionsSnapshot) || []).length;
    return <span className="text-foreground">Xoá vai trò · có <strong>{n}</strong> quyền lúc xoá.</span>;
  }
  if (ev.action === 'PRIMARY_ROLE_CHANGED') {
    return (
      <div className="flex flex-col gap-1">
        <div className="flex items-center gap-1.5">
          <Icon name="user" size={12} style={{ color:'var(--color-muted-foreground)' }} />
          <span className="font-medium text-foreground">{ev.targetUserName}</span>
        </div>
        <div className="flex items-center gap-2">
          <span className="text-muted-foreground">{ev.previousRoleName || '—'}</span>
          <Icon name="arrow-right" size={12} style={{ color:'var(--color-muted-foreground)' }} />
          <span className="font-medium text-foreground">{ev.newRoleName || '—'}</span>
        </div>
      </div>
    );
  }
  // ROLE_ASSIGNED / ROLE_REVOKED
  return (
    <div className="flex flex-col gap-1">
      <div className="flex items-center gap-1.5">
        <Icon name="arrow-right" size={12} style={{ color:'var(--color-muted-foreground)' }} />
        <span className="font-medium text-foreground">{ev.targetUserName}</span>
      </div>
      {ev.justification && <div className="text-muted-foreground">Lý do: {ev.justification}</div>}
    </div>
  );
}

// Một dòng sự kiện audit (icon tròn + badge + thời điểm + nội dung + người thực hiện/IP).
function AuditRow({ ev, last }) {
  const m = AUDIT_ACTION_META[ev.action] || { label:'Thay đổi', variant:'neutral', icon:'info', token:'primary' };
  return (
    <div className={"flex gap-3 py-3 " + (last ? "" : "border-b border-border")}>
      <div className="grid size-8 shrink-0 place-items-center rounded-full"
        style={{ background:`var(--color-${m.token}-soft)` }}>
        <Icon name={m.icon} size={14} style={{ color:`var(--color-${m.token})` }} />
      </div>
      <div className="min-w-0 flex-1">
        <div className="flex items-center justify-between gap-2">
          <Badge variant={m.variant}>{m.label}</Badge>
          <span className="shrink-0 font-mono text-2xs text-muted-foreground">{ev.createdAt}</span>
        </div>
        <div className="mt-1.5 text-xs"><AuditContent ev={ev} /></div>
        <div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-1 text-2xs text-muted-foreground">
          <span className="flex items-center gap-1.5">
            <Avatar name={ev.requestorName || 'Hệ thống'} size="sm" />
            Thực hiện bởi <strong className="font-semibold text-foreground">{ev.requestorName || 'Hệ thống'}</strong>
          </span>
          {ev.ipAddress && (
            <span className="flex items-center gap-1">
              <Icon name="globe" size={11} /><span className="font-mono">{ev.ipAddress}</span>
            </span>
          )}
        </div>
      </div>
    </div>
  );
}

// ─── PermGroups — khối chọn quyền 3 nhóm, dùng chung cho Chi tiết & Tạo mới ──────
function PermGroups({ editable, granted, setGranted, scopes, setScopes }) {
  const [activeKey, setActiveKey] = React.useState(PERM_MODULES[0].key);
  const active = PERM_MODULES.find(m => m.key === activeKey) || PERM_MODULES[0];
  const toggle = (code) => {
    if (!editable) return;
    setGranted(prev => { const n = new Set(prev); n.has(code) ? n.delete(code) : n.add(code); return n; });
  };
  const setScope = (domain, v) => {
    if (!editable) return;
    const floor = BASELINE_OWN_DOMAINS.has(domain) ? 'own' : 'none';
    setScopes(prev => ({ ...prev, [domain]: SCOPE_RANK[v] < SCOPE_RANK[floor] ? floor : v }));
  };

  const screenState = (p) => {
    if (!editable) return 'readonly';
    if (isGuardrailed(p.code)) return 'guardrail';
    if (isBaseline(p.code)) return 'baseline';
    return granted.has(p.code) ? 'granted' : 'denied';
  };

  const permByCode = (code) => SCREEN_PERMS.find(p=>p.code===code) || ACTION_PERMS.find(p=>p.code===code) || { code, label: code };
  const totalGranted = PERM_MODULES.reduce((s,m) => s + moduleGrantedCount(m, granted, scopes).granted, 0);

  const SubHead = ({ icon, color, title }) => (
    <div className="mb-2 mt-1 flex items-center gap-2">
      <Icon name={icon} size={12} style={{ color }} />
      <span className="text-2xs font-bold uppercase tracking-[0.07em]" style={{ color }}>{title}</span>
    </div>
  );

  const renderPerm = (code) => {
    const p = permByCode(code);
    return <PermissionItem key={code} label={p.label} code={code}
      state={screenState(p)} granted={granted.has(code)} onToggle={()=>toggle(code)} />;
  };

  return (
    <div>
      <div className="mb-3 flex items-center justify-between gap-3">
        <div className="text-2xs leading-[1.5] text-muted-foreground">Quyền gom theo nhóm nghiệp vụ — chọn một nhóm bên trái để xem &amp; cấp quyền của nhóm đó.</div>
        <span className="shrink-0 rounded-full bg-primary-soft px-2.5 py-0.5 text-xs font-bold text-primary">Đã cấp: {totalGranted}</span>
      </div>

      <div className="grid grid-cols-[208px_1fr] gap-4">
        {/* Cột trái — danh sách nhóm (module) */}
        <div className="flex flex-col gap-1">
          {PERM_MODULES.map(m => {
            const c = moduleGrantedCount(m, granted, scopes);
            const on = m.key === active.key;
            return (
              <button key={m.key} type="button" onClick={()=>setActiveKey(m.key)}
                className={"flex items-center gap-2.5 rounded-md border px-2.5 py-2 text-left transition-colors "
                  + (on ? "border-primary bg-primary-soft" : "border-transparent hover:bg-muted")}>
                <div className={"grid size-7 shrink-0 place-items-center rounded-md " + (on ? "bg-primary" : "bg-muted")}>
                  <Icon name={m.icon} size={13} style={{ color: on ? '#fff' : 'var(--color-muted-foreground)' }} />
                </div>
                <div className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">{m.label}</div>
                {m.locked
                  ? <Icon name="lock" size={12} style={{ color:'var(--color-muted-foreground)' }} />
                  : <span className={"flex items-center gap-1 text-2xs font-semibold tabular-nums " + (c.granted>0 ? "text-primary" : "text-muted-foreground")}>
                      {c.granted>0 && <span className="size-1.5 rounded-full bg-primary" />}{c.granted}/{c.total}
                    </span>}
              </button>
            );
          })}
        </div>

        {/* Cột phải — quyền của nhóm đang chọn */}
        <div className="min-w-0 rounded-lg border border-border p-3.5">
          <div className="mb-3 flex items-center gap-2 border-b border-border pb-2.5">
            <div className="grid size-8 place-items-center rounded-md bg-muted">
              <Icon name={active.icon} size={15} style={{ color:'var(--color-foreground)' }} />
            </div>
            <div className="text-sm font-bold">{active.label}</div>
            {active.locked && (
              <span className="ml-auto inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-2xs font-semibold text-muted-foreground">
                <Icon name="lock" size={10} />Chỉ vai trò hệ thống
              </span>
            )}
          </div>

          {active.screens.length > 0 && (
            <div>
              <SubHead icon="layout-dashboard" color="var(--color-primary)" title="Màn hình" />
              <div className="grid gap-1">{active.screens.map(renderPerm)}</div>
            </div>
          )}

          {active.dataDomain && (() => {
            const domain = active.dataDomain;
            const baseFloor = BASELINE_OWN_DOMAINS.has(domain);
            const on = (scopes[domain]||'none')!=='none';
            return (
              <div className="mt-3">
                <SubHead icon="users" color="var(--color-info)" title="Phạm vi dữ liệu" />
                <div className={"flex items-center gap-[11px] rounded-md px-[11px] py-2 "
                  + (on ? "border border-border bg-muted" : "border border-transparent")}>
                  <div className="min-w-0 flex-1">
                    <div className="text-sm font-medium">Bản ghi {active.label.toLowerCase()}</div>
                    <div className="mt-px font-mono text-2xs text-muted-foreground">data:{domain}:&lt;scope&gt;</div>
                    {editable && baseFloor && (
                      <span className="mt-1.5 inline-flex items-center gap-1 rounded-full bg-success-soft px-[7px] py-0.5 text-2xs font-semibold text-success">
                        <Icon name="lock" size={9} />Nền tảng: tối thiểu Của mình
                      </span>
                    )}
                  </div>
                  <DataScopeControl value={scopes[domain] || 'none'} onChange={(v)=>setScope(domain, v)} readOnly={!editable} />
                </div>
              </div>
            );
          })()}

          {active.actions.length > 0 && (
            <div className="mt-3">
              <SubHead icon="check-circle" color="var(--color-success)" title="Hành động" />
              <div className="grid gap-1">{active.actions.map(renderPerm)}</div>
            </div>
          )}
        </div>
      </div>

      {/* Guardrail explainer (chỉ khi editable) */}
      {editable && (
        <div className="mt-4 flex gap-2.5 rounded-lg border border-border bg-muted px-3.5 py-[11px]">
          <Icon name="shield" size={16} className="mt-px shrink-0" style={{ color:'var(--color-muted-foreground)' }} />
          <div className="text-xs leading-[1.6] text-muted-foreground">
            <strong className="text-foreground">Giới hạn vai trò tùy chỉnh:</strong> bốn quyền quản trị
            <code className="mx-[3px] font-mono">*</code>,
            <code className="mx-[3px] font-mono">screen:roles</code>,
            <code className="mx-[3px] font-mono">screen:settings</code>,
            <code className="mx-[3px] font-mono">action:role:manage</code>
            (nhóm <strong className="text-foreground">Hệ thống</strong>) chỉ dành cho vai trò hệ thống nên bị vô hiệu hóa. Riêng <code className="font-mono">data:*:all</code> vẫn được phép cấp.
          </div>
        </div>
      )}
    </div>
  );
}

// ─── DeleteRoleDialog — hộp xác nhận XOÁ định nghĩa vai trò (gõ mã để xác nhận) ───
// Phản ánh ĐÚNG hành vi BE (DeleteRoleHandler): xoá là CASCADE, KHÔNG chặn khi còn user —
//   · role_assignments của vai trò bị gỡ (FK onDelete cascade);
//   · ai lấy làm vai trò chính bị đặt trống (users.primary_role_id → null, FK set null);
//   · cache quyền + org-scope của user bị ảnh hưởng bị vô hiệu NGAY → mất quyền tức thì (không chờ TTL 5');
//   · ghi audit ROLE_DELETED kèm ảnh chụp toàn bộ quyền lúc xoá (permissionsSnapshot).
// Vai trò hệ thống không xoá được nên dialog này chỉ dùng cho vai trò tùy chỉnh.
function DeleteRoleDialog({ role, value = '', onChange = () => {}, onClose = () => {} }) {
  const confirmed = value.trim() === role.code;
  const permText = role.full ? 'Toàn bộ quyền' : `${permCount(role)} quyền`;
  return (
    <div className="absolute inset-0 z-[60] grid place-items-center bg-black/50" onClick={onClose}>
      <div onClick={(e) => e.stopPropagation()}
        className="flex max-h-[90%] w-[500px] max-w-[92%] flex-col rounded-lg bg-popover shadow-2xl outline outline-4 outline-[oklch(0.92_0_0_/_0.6)]">
        {/* Header */}
        <div className="flex items-start justify-between border-b border-border px-[22px] pb-3.5 pt-[18px]">
          <div className="flex gap-[11px]">
            <div className="grid size-[34px] shrink-0 place-items-center rounded-md bg-destructive-soft">
              <Icon name="trash" size={17} className="text-destructive" />
            </div>
            <div>
              <div className="text-md font-bold">Xoá vai trò</div>
              <div className="mt-[3px] text-xs text-muted-foreground">
                Xoá vĩnh viễn vai trò <strong className="text-foreground">{role.displayName}</strong> (<span className="font-mono">{role.code}</span>) khỏi hệ thống
              </div>
            </div>
          </div>
          <Btn variant="ghost" size="sm" iconOnly icon="x" onClick={onClose} />
        </div>

        {/* Body */}
        <div className="flex-1 overflow-y-auto px-[22px] py-4">
          {/* Hệ quả — khớp cascade của BE */}
          <div className="mb-4 flex gap-2 rounded-md bg-destructive-soft px-3.5 py-3">
            <Icon name="alert-triangle" size={15} className="mt-px shrink-0 text-destructive" />
            <div className="text-xs leading-[1.55] text-destructive">
              <div className="mb-1 font-semibold">Hành động không thể hoàn tác. Khi xoá:</div>
              <ul className="list-disc space-y-1 pl-4">
                <li><strong>{role.users}</strong> người dùng bị gỡ vai trò này <strong>ngay lập tức</strong> — quyền mất hiệu lực tức thì (không chờ cache 5').</li>
                <li>Ai đang lấy đây làm <strong>vai trò chính</strong> sẽ bị <strong>đặt trống</strong> vai trò chính, cần gán lại.</li>
                <li><strong>{permText}</strong> của vai trò bị thu hồi.</li>
              </ul>
            </div>
          </div>

          {/* Ghi chú audit */}
          <div className="mb-4 flex items-start gap-1.5 text-2xs leading-[1.5] text-muted-foreground">
            <Icon name="info" size={11} className="mt-0.5 shrink-0" />
            <span>Ghi nhật ký <span className="font-semibold text-foreground">ROLE_DELETED</span> (người thực hiện · thời điểm · IP · ảnh chụp toàn bộ quyền lúc xoá), lưu 7 năm.</span>
          </div>

          {/* Gõ mã để xác nhận */}
          <label className="mb-1.5 block text-xs font-semibold text-foreground">
            Gõ mã vai trò <code className="rounded bg-muted px-1 py-0.5 font-mono text-destructive">{role.code}</code> để xác nhận
          </label>
          <input value={value} onChange={(e) => onChange(e.target.value)} placeholder={role.code}
            className="h-9 w-full rounded-md border border-input bg-transparent px-3 font-mono text-base text-foreground shadow-xs transition-colors placeholder:text-muted-foreground focus:border-destructive focus:outline-none focus:ring-[3px] focus:ring-[color-mix(in_oklab,var(--color-destructive)_35%,transparent)]" />
          {value && !confirmed && (
            <div className="mt-1.5 text-2xs text-destructive">Mã chưa khớp — gõ đúng <span className="font-mono">{role.code}</span>.</div>
          )}
        </div>

        {/* Footer */}
        <div className="flex items-center justify-end gap-2 border-t border-border px-[22px] py-3">
          <Btn variant="outline" size="sm" onClick={onClose}>Hủy</Btn>
          <Btn variant="destructive" size="sm" icon="trash" disabled={!confirmed} onClick={onClose}>Xoá vai trò</Btn>
        </div>
      </div>
    </div>
  );
}

// ─── RoleDetail — dùng chung cho system (đọc) & custom (sửa) ─────────────────────
function RoleDetail({ role }) {
  const editable = !role.isSystem;
  const [tab, setTab] = React.useState('perms');
  const [auditFilter, setAuditFilter] = React.useState('all');
  const [auditPage, setAuditPage] = React.useState(0);
  const [granted, setGranted] = React.useState(() => new Set(role.perms));
  const [scopes, setScopes] = React.useState(() => {
    const m = {}; DATA_DOMAINS.forEach(d => m[d.domain] = domainScope(role, d.domain)); return m;
  });
  // Xoá vai trò (chỉ custom) — mở hộp xác nhận gõ-mã.
  const [showDelete, setShowDelete] = React.useState(false);
  const [delConfirm, setDelConfirm] = React.useState('');

  // live summary từ scopes
  const liveSummary = (() => {
    if (role.full) return 'Toàn bộ dữ liệu';
    let best='none'; DATA_DOMAINS.forEach(d=>{ const s=scopes[d.domain]||'none'; if (SCOPE_RANK[s]>SCOPE_RANK[best]) best=s; });
    return best==='all'?'Toàn bộ dữ liệu':best==='dept'?'Theo phòng ban':best==='own'?'Chỉ dữ liệu bản thân':'Không có quyền dữ liệu';
  })();

  const USERS = [
    { name:'Trần Minh Tuấn', dept:'Kỹ thuật',   since:'15/03/2024' },
    { name:'Ngô Thị Hoa',    dept:'Marketing',  since:'02/06/2024' },
    { name:'Vũ Văn Thắng',   dept:'Kinh doanh', since:'10/09/2024' },
  ].slice(0, Math.min(role.users, 3));

  // Mock audit — mang ĐÚNG shape field BE (RoleAuditLogEntry + metadata) mà route
  // GET /roles/:id/audit-logs trả về; đủ đại diện cả 6 action (cấu hình + gán/thu hồi).
  const AUDIT = role.isSystem ? [
    { action:'ROLE_ASSIGNED', requestorName:'Nguyễn Quản Trị', targetUserName:'Phạm Thu Hà',
      justification:null, ipAddress:'10.0.0.12', createdAt:'12/06/2026 08:40' },
    { action:'ROLE_CREATED', requestorName:'Hệ thống',
      metadata:{ permissionsSnapshot: role.perms, roleName: role.code }, ipAddress:null, createdAt:'01/03/2024 10:00' },
  ] : [
    { action:'ROLE_UPDATED', requestorName:'Nguyễn Quản Trị',
      metadata:{ roleName: role.code, permissionsAdded:['data:recruitment:all'], permissionsRemoved:[] },
      ipAddress:'192.168.1.100', createdAt:'10/07/2026 09:30' },
    { action:'ROLE_UPDATED', requestorName:'Nguyễn Quản Trị',
      metadata:{ roleName: role.code, permissionsAdded:['action:recruitment:manage'], permissionsRemoved:['action:report:export'] },
      ipAddress:'192.168.1.100', createdAt:'09/07/2026 16:05' },
    { action:'ROLE_ASSIGNED', requestorName:'Nguyễn Quản Trị', targetUserName:'Trần Minh Tuấn',
      justification:'Bổ nhiệm phụ trách tuyển dụng Q3', ipAddress:'192.168.1.100', createdAt:'08/07/2026 14:22' },
    { action:'PRIMARY_ROLE_CHANGED', requestorName:'Nguyễn Quản Trị', targetUserName:'Vũ Văn Thắng',
      previousRoleName:'Nhân viên', newRoleName: role.displayName, ipAddress:'192.168.1.100', createdAt:'05/07/2026 11:10' },
    { action:'ROLE_REVOKED', requestorName:'Nguyễn Quản Trị', targetUserName:'Ngô Thị Hoa',
      justification:'Chuyển sang bộ phận khác', ipAddress:'192.168.1.100', createdAt:'03/07/2026 09:48' },
    { action:'ROLE_CREATED', requestorName:'Nguyễn Quản Trị',
      metadata:{ permissionsSnapshot: role.perms, roleName: role.code }, ipAddress:'192.168.1.100', createdAt:'02/05/2026 09:15' },
  ];

  return (
    <div className="relative size-full">
    <HRMShell active="rbac"
      title={role.displayName} crumbs={['Hệ thống','Phân quyền', role.displayName]}
      meta={<TypeBadge isSystem={role.isSystem} />}
      actions={editable
        ? <>
            <Btn variant="outline" size="sm" icon="trash"
              className="mr-1 border-[color-mix(in_oklab,var(--color-destructive)_40%,transparent)] text-destructive hover:bg-destructive-soft hover:text-destructive"
              onClick={()=>{ setDelConfirm(''); setShowDelete(true); }}>Xoá vai trò</Btn>
            <Btn variant="outline" size="sm">Hủy</Btn>
            <Btn variant="primary" size="sm" icon="check">Lưu cấu hình</Btn>
          </>
        : <Btn variant="outline" size="sm" icon="eye">Chế độ chỉ xem</Btn>}>

      <div className="grid grid-cols-[264px_1fr] gap-4">

        {/* ── Sidebar ── */}
        <div className="flex flex-col gap-3">
          <div className={CARD + " p-[18px]"}>
            <div className="mb-3.5 flex flex-col items-center border-b border-border pb-3.5 text-center">
              <div className="mb-2.5 grid size-[54px] place-items-center rounded-xl" style={{ background:role.bg }}>
                <Icon name={role.icon} size={23} style={{ color:role.color }} />
              </div>
              <div className="text-md font-bold">{role.displayName}</div>
              <div className="mt-[3px] font-mono text-2xs text-muted-foreground">{role.code}</div>
              <div className="mt-2.5"><TypeBadge isSystem={role.isSystem} /></div>
            </div>
            {[
              { label:'Cấp độ',          val: String(role.level) },
              { label:'Người dùng',      val:`${role.users} tài khoản` },
              { label:'Phạm vi dữ liệu', val: liveSummary },
              { label:'Số quyền',        val: role.full ? 'Toàn bộ' : `${permCount(role)} quyền` },
              { label:'Hiệu lực',        val:'≤ 5 phút sau khi lưu' },
            ].map((f,i,arr)=>(
              <div key={i} className={"flex justify-between gap-2.5 py-[7px] text-xs " + (i<arr.length-1?"border-b border-border":"")}>
                <span className="text-muted-foreground">{f.label}</span>
                <span className="text-right font-semibold">{f.val}</span>
              </div>
            ))}
          </div>

          {/* Card trạng thái theo loại vai trò */}
          {role.isSystem ? (
            <div className={CARD + " bg-muted p-[13px]"}>
              <div className="flex gap-2">
                <Icon name="lock" size={15} className="mt-px shrink-0" style={{ color:'var(--color-muted-foreground)' }} />
                <div className="text-xs leading-[1.6] text-muted-foreground">
                  <strong className="text-foreground">Vai trò hệ thống — chỉ xem.</strong> Không thể chỉnh sửa quyền. Để có cấu hình riêng, hãy tạo một vai trò tùy chỉnh.
                </div>
              </div>
            </div>
          ) : (
            <div className={CARD + " p-[13px]"} style={{ background:'var(--color-success-soft)', border:'1px solid color-mix(in oklab, var(--color-success) 22%, transparent)' }}>
              <div className="flex gap-2">
                <Icon name="lock" size={15} className="mt-px shrink-0" style={{ color:'var(--color-success)' }} />
                <div className="text-xs leading-[1.6]" style={{ color:'oklch(0.38 0.06 150)' }}>
                  <strong>Bộ quyền nền tảng (Nhân viên)</strong> đã được bao gồm sẵn và khóa cho mọi vai trò: bảng điều khiển, nghỉ phép, chấm công, bảng công và toàn bộ <code className="font-mono">data:*:own</code> của bản thân.
                </div>
              </div>
            </div>
          )}
        </div>

        {/* ── Panel phải ── */}
        <div className={CARD + " overflow-hidden"}>
          <div className="flex border-b border-border px-[18px]">
            {[
              { id:'perms', label:'Cấu hình quyền' },
              { id:'users', label:`Người dùng (${role.users})` },
              { id:'audit', label:'Lịch sử thay đổi' },
            ].map(t=>(
              <button key={t.id} onClick={()=>setTab(t.id)}
                className={"-mb-px cursor-pointer border-b-2 bg-transparent px-4 py-3 text-sm "
                  + (tab===t.id ? "border-primary font-semibold text-foreground" : "border-transparent font-medium text-muted-foreground")}>
                {t.label}
              </button>
            ))}
          </div>

          <div className="p-5">
            {tab==='perms' && (
              <div>
                <div className="mb-[18px] flex items-start justify-between gap-3">
                  <div className="max-w-[560px] text-xs leading-[1.6] text-muted-foreground">
                    {editable
                      ? 'Mỗi quyền có hai trạng thái: được cấp hoặc không cấp. Quyền nền tảng (Nhân viên) được khóa; bốn quyền quản trị bị giới hạn không khả dụng.'
                      : 'Vai trò hệ thống ở chế độ chỉ-đọc — hiển thị đúng tập quyền tường minh, không có nút lưu.'}
                  </div>
                  {editable && <Btn variant="outline" size="sm" icon="plus">Thêm quyền tùy chỉnh</Btn>}
                </div>
                <PermGroups editable={editable} granted={granted} setGranted={setGranted} scopes={scopes} setScopes={setScopes} />
              </div>
            )}

            {tab==='users' && (
              <div>
                <div className="mb-3.5 flex items-center justify-between">
                  <div className="text-sm font-semibold">{role.users} người dùng có vai trò này</div>
                  <Btn variant="soft" size="sm" icon="plus">Gán vai trò</Btn>
                </div>
                {USERS.map((u,i)=>(
                  <div key={i} className="flex items-center gap-3 border-b border-border py-2.5">
                    <Avatar name={u.name} />
                    <div className="flex-1">
                      <div className="text-sm font-semibold">{u.name}</div>
                      <div className="text-xs text-muted-foreground">Phòng {u.dept} · Từ {u.since}</div>
                    </div>
                    <Btn variant="ghost" size="sm" iconOnly icon="x" />
                  </div>
                ))}
                {role.users > USERS.length && (
                  <div className="mt-3 cursor-pointer text-center text-xs font-semibold text-primary">
                    Xem thêm {role.users-USERS.length} người dùng →
                  </div>
                )}
              </div>
            )}

            {tab==='audit' && (() => {
              const FILTERS = [
                { id:'all',    label:'Tất cả' },
                { id:'config', label:'Thay đổi quyền' },
                { id:'assign', label:'Gán / thu hồi' },
              ];
              const matchFilter = (e) =>
                auditFilter==='all' ? true
                : auditFilter==='config' ? AUDIT_CONFIG_ACTIONS.includes(e.action)
                : !AUDIT_CONFIG_ACTIONS.includes(e.action);
              const filtered = AUDIT.filter(matchFilter);
              const PAGE = 5;
              const pageCount = Math.max(1, Math.ceil(filtered.length / PAGE));
              const page = Math.min(auditPage, pageCount - 1);
              const start = page * PAGE;
              const items = filtered.slice(start, start + PAGE);
              return (
                <div>
                  <div className="mb-1 text-sm font-semibold">Lịch sử thay đổi vai trò</div>
                  <div className="mb-3.5 text-xs text-muted-foreground">Lưu giữ 7 năm · Không thể sửa đổi sau khi ghi</div>

                  {/* Chip lọc theo loại thao tác */}
                  <div className="mb-4 flex flex-wrap items-center gap-1.5">
                    {FILTERS.map(f => {
                      const on = auditFilter === f.id;
                      return (
                        <button key={f.id} type="button"
                          onClick={() => { setAuditFilter(f.id); setAuditPage(0); }}
                          className={"rounded-full px-3 py-1 text-xs font-semibold transition-colors "
                            + (on ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground")}>
                          {f.label}
                        </button>
                      );
                    })}
                  </div>

                  {/* Timeline thống nhất — mọi thao tác theo thời gian giảm dần */}
                  {items.length === 0
                    ? <div className="rounded-lg border border-dashed border-border py-8 text-center text-xs text-muted-foreground">Không có mục nào phù hợp bộ lọc.</div>
                    : <div className="flex flex-col">{items.map((ev,i) => <AuditRow key={start+i} ev={ev} last={i===items.length-1} />)}</div>}

                  {/* Phân trang (khớp limit/offset của BE) */}
                  <div className="mt-4 flex items-center justify-between border-t border-border pt-3">
                    <span className="text-xs tabular-nums text-muted-foreground">
                      {filtered.length === 0 ? '0 mục' : `${start+1}–${start+items.length} trong ${filtered.length} mục`}
                    </span>
                    <div className="flex items-center gap-1.5">
                      <Btn variant="outline" size="sm" icon="chevron-left" disabled={page===0} onClick={()=>setAuditPage(page-1)}>Trước</Btn>
                      <Btn variant="outline" size="sm" iconRight="chevron-right" disabled={page>=pageCount-1} onClick={()=>setAuditPage(page+1)}>Sau</Btn>
                    </div>
                  </div>
                </div>
              );
            })()}
          </div>
        </div>
      </div>
    </HRMShell>
      {editable && showDelete && (
        <DeleteRoleDialog role={role} value={delConfirm} onChange={setDelConfirm} onClose={()=>setShowDelete(false)} />
      )}
    </div>
  );
}

// ─── B. Tạo vai trò mới (/roles/new) ────────────────────────────────────────────
const RBACCreateScreen = () => {
  const [granted, setGranted] = React.useState(() => new Set(EMPLOYEE_BASELINE));
  const [scopes, setScopes] = React.useState(() => {
    const m = {}; DATA_DOMAINS.forEach(d => m[d.domain] = BASELINE_OWN_DOMAINS.has(d.domain) ? 'own' : 'none'); return m;
  });

  return (
    <HRMShell active="rbac"
      title="Tạo vai trò mới" crumbs={['Hệ thống','Phân quyền','Tạo vai trò mới']}
      meta={<TypeBadge isSystem={false} />}
      actions={<><Btn variant="outline" size="sm">Hủy</Btn><Btn variant="primary" size="sm" icon="check">Tạo vai trò</Btn></>}>

      <div className="grid grid-cols-[1fr_300px] items-start gap-4">

        {/* Form chính */}
        <div className="flex flex-col gap-4">
          {/* Thông tin */}
          <div className={CARD + " p-5"}>
            <div className="mb-4 text-sm font-bold">Thông tin vai trò</div>
            <div className="mb-3.5 grid grid-cols-2 gap-3.5">
              <div>
                <label className="mb-[5px] block text-xs font-semibold">Tên hiển thị *</label>
                <input className={INPUT} defaultValue="Chuyên viên Tuyển dụng" />
                <div className="mt-[5px] text-2xs text-muted-foreground">
                  Tên thân thiện hiển thị trong toàn hệ thống.
                </div>
              </div>
              <div>
                <label className="mb-[5px] block text-xs font-semibold">Mã vai trò *</label>
                <input className={INPUT + " font-mono"} defaultValue="RECRUITER" placeholder="VD: RECRUITER" />
                <div className="mt-[5px] text-2xs text-muted-foreground">Nhập tay dạng UPPER_SNAKE — duy nhất, không đổi sau khi tạo.</div>
              </div>
            </div>
            <div className="mb-3.5 grid grid-cols-[150px_1fr] gap-3.5">
              <div>
                <label className="mb-[5px] block text-xs font-semibold">Cấp độ *</label>
                <input className={INPUT + " tabular-nums"} type="number" min={1} max={99} defaultValue={50} />
                <div className="mt-[5px] text-2xs text-muted-foreground">Từ 1–99.</div>
              </div>
              <div className="flex items-start gap-2 self-end rounded-md bg-info-soft px-3 py-2 text-2xs leading-[1.5] text-muted-foreground" style={{ border:'1px solid color-mix(in oklab, var(--color-info) 20%, transparent)' }}>
                <Icon name="info" size={13} className="mt-px shrink-0" style={{ color:'var(--color-info)' }} />
                <span>Cấp bậc dùng để <strong className="text-foreground">giới hạn việc gán vai trò</strong>: người gán chỉ gán được vai trò cấp <strong className="text-foreground">thấp hơn</strong> mình. <strong className="text-foreground">Không</strong> ảnh hưởng quyền hạn.</span>
              </div>
            </div>
            <div>
              <label className="mb-[5px] block text-xs font-semibold">Mô tả</label>
              <textarea className={INPUT.replace('h-9','h-[62px]') + " resize-none pt-2"}
                defaultValue="Phụ trách tuyển dụng — quản lý tin tuyển dụng & ứng viên, xem hồ sơ nhân viên phòng ban." />
            </div>
          </div>

          {/* Khối quyền */}
          <div className={CARD + " p-5"}>
            <div className="mb-1.5 text-sm font-bold">Cấu hình quyền</div>
            <div className="mb-[18px] text-xs leading-[1.6] text-muted-foreground">
              Bộ quyền nền tảng (Nhân viên) đã chọn sẵn và khóa. Nhóm Hệ thống chỉ dành cho vai trò hệ thống.
            </div>
            <PermGroups editable={true} granted={granted} setGranted={setGranted} scopes={scopes} setScopes={setScopes} />
          </div>
        </div>

        {/* Sidebar phải */}
        <div className="sticky top-0 flex flex-col gap-3">
          <div className={CARD + " p-4"} style={{ background:'var(--color-success-soft)', border:'1px solid color-mix(in oklab, var(--color-success) 22%, transparent)' }}>
            <div className="mb-2 flex items-center gap-[7px]">
              <Icon name="lock" size={14} style={{ color:'var(--color-success)' }} />
              <span className="text-xs font-bold text-success">Bộ quyền nền tảng (Nhân viên)</span>
            </div>
            <div className="mb-2.5 text-xs leading-[1.6]" style={{ color:'oklch(0.38 0.06 150)' }}>
              Tự động thêm & khóa cho mọi vai trò — không thể bỏ chọn.
            </div>
            <div className="flex flex-wrap gap-1">
              {EMPLOYEE_BASELINE.map(c=>(
                <code key={c} className="rounded-sm bg-card px-1.5 py-0.5 font-mono text-2xs text-success" style={{ border:'1px solid color-mix(in oklab, var(--color-success) 20%, transparent)' }}>{c}</code>
              ))}
            </div>
          </div>

          <div className={CARD + " bg-muted p-4"}>
            <div className="mb-2 flex items-center gap-[7px]">
              <Icon name="shield" size={14} style={{ color:'var(--color-muted-foreground)' }} />
              <span className="text-xs font-bold">Không khả dụng (giới hạn)</span>
            </div>
            <div className="mb-2.5 text-xs leading-[1.6] text-muted-foreground">
              Chỉ dành cho vai trò hệ thống:
            </div>
            <div className="flex flex-wrap gap-1">
              {GUARDRAIL_CODES.map(c=>(
                <code key={c} className="rounded-sm border border-border bg-card px-1.5 py-0.5 font-mono text-2xs text-muted-foreground line-through">{c}</code>
              ))}
            </div>
            <div className="mt-2.5 text-2xs leading-[1.5] text-muted-foreground">
              Ghi chú: <code className="font-mono">data:*:all</code> vẫn được phép cấp.
            </div>
          </div>
        </div>
      </div>
    </HRMShell>
  );
};

// Wrappers cho canvas
const RBACDetailSystemScreen = () => <RoleDetail role={roleById('r3')} />;   // DEPT_MANAGER — chỉ xem
const RBACDetailCustomScreen = () => <RoleDetail role={roleById('r5')} />;   // RECRUITER — sửa được

// Artboard xem trước — hộp xác nhận Xoá mở sẵn trên nền màn Chi tiết (tùy chỉnh, RECRUITER).
const RBACDeleteRoleScreen = () => (
  <div className="relative size-full">
    <RoleDetail role={roleById('r5')} />
    <DeleteRoleDialog role={roleById('r5')} value="" onChange={()=>{}} onClose={()=>{}} />
  </div>
);

Object.assign(window, { PermGroups, RoleDetail, DeleteRoleDialog, RBACCreateScreen, RBACDetailSystemScreen, RBACDetailCustomScreen, RBACDeleteRoleScreen });
