<?php
/* ============================================================================
   WBMCZ ADMIN — ROLE MANAGEMENT (detailed)
   ----------------------------------------------------------------------------
   A role is no longer one tick per module. Every module opens into two lists:

     ACTIONS   what may be done      view, create, edit, delete, export …
     COLUMNS   what may be seen      balance, KYC status, seller share …

   Whoever builds a role can only tick what they hold themselves. Anything
   above their own access is shown locked, and the server checks again before
   saving — so it cannot be got around by editing the page in a browser.
   ============================================================================ */
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../includes/Language.php';
require_once __DIR__ . '/../includes/rbac.php';
require_once __DIR__ . '/../includes/acl.php';
require_once __DIR__ . '/../includes/activity.php';

if (!isLoggedIn() || !isAdmin()) { redirect('login.php'); }
acl_ensure_schema($db);
acl_guard(['staff.role_view', 'staff.view']);

$lang         = new Language($db);
$current_lang = $lang->getCurrentLanguage();
$user_id      = (int)$_SESSION['user_id'];

$MODULES  = acl_modules();
$GROUPS   = acl_groups();
$CEILING  = acl_ceiling();
$MY_LEVEL = acl_level();
$IS_SUPER = ($MY_LEVEL === 'superadmin');
$LEVELS   = acl_creatable_levels();          // which role levels I may build for

$can_create = acl_can('staff.role_create');
$can_edit   = acl_can('staff.role_edit');
$can_delete = acl_can('staff.role_delete');

$user_data = $db->select("SELECT * FROM users WHERE id = ?", [$user_id]);
$user      = !empty($user_data) ? $user_data[0] : null;
if (!$user) { session_destroy(); redirect('login.php'); }

$company_name = getSetting('company_name', 'WBMCZ');
$profile_image_url = !empty($user['profile_pic']) ? '../uploads/profiles/' . $user['profile_pic'] : null;

$flash_ok  = $_SESSION['flash_success'] ?? ''; unset($_SESSION['flash_success']);
$flash_err = $_SESSION['flash_error']   ?? ''; unset($_SESSION['flash_error']);

/* A role I am allowed to touch: never the system role, and an admin may only
   work on employee-level roles. */
function rl_can_touch($role, $isSuper, $levels) {
    if ((int)$role['id'] === 1) return false;
    if ($isSuper) return true;
    $lvl = strtolower((string)($role['level'] ?? 'employee'));
    if ($lvl === 'superadmin' || $lvl === 'admin') return false;
    return array_key_exists($lvl, $levels);
}

/**
 * Insert a row and, when it will not go in, say exactly why.
 *
 * $db->insert() answers false for three quite different problems — a column that
 * is not there, a value MySQL refuses, and a numbered key that does not count up
 * — and the page used to show the same shrug for all three. This does the work
 * itself so the real reason can be put on the screen.
 *
 * @return array ['id' => int, 'error' => string]
 */
function rl_insert($conn, $sql, $types, $params) {
    $st = $conn->prepare($sql);
    if (!$st) {
        return ['id' => 0, 'error' => 'The roles table is missing a column this page needs — ' . $conn->error];
    }
    $st->bind_param($types, ...$params);
    if (!$st->execute()) {
        $err = $st->error; $st->close();
        return ['id' => 0, 'error' => $err];
    }
    $id  = (int)$st->insert_id;
    $aff = $st->affected_rows;
    $st->close();

    if ($id === 0 && $aff > 0) {
        return ['id' => 0, 'error' => 'The row was accepted but MySQL gave it no id number. '
            . 'The roles table was imported without its AUTO_INCREMENT — upload and open fixmigration.php once and this will be put right.'];
    }
    if ($id === 0) {
        return ['id' => 0, 'error' => 'Nothing was saved and MySQL gave no reason.'];
    }
    return ['id' => $id, 'error' => ''];
}

/* The detailed set a role currently holds. */
function rl_perms($role) {
    $p = json_decode((string)($role['perms_json'] ?? ''), true);
    if (is_array($p) && !empty($p)) return $p;
    $old = json_decode((string)$role['permissions'], true);
    return acl_expand_legacy(is_array($old) ? $old : []);
}

/* ============================================================================
   AJAX — one role's permission map, for the editor
   ============================================================================ */
if (isset($_GET['ajax'])) {
    header('Content-Type: application/json');
    $id = (int)($_GET['id'] ?? 0);
    $r  = $db->select("SELECT * FROM roles WHERE id = ?", [$id]);
    if (empty($r)) { echo json_encode(['ok' => false, 'msg' => 'Role not found.']); exit; }
    $role  = $r[0];
    $perms = rl_perms($role);

    $hist = [];
    try {
        $hist = $db->select("SELECT * FROM staff_access_log WHERE target_type = 'role' AND target_id = ? ORDER BY id DESC LIMIT 100", [$id]);
        foreach ($hist as &$h) {
            $h['when']    = date('d M Y, h:i A', strtotime($h['created_at']));
            $h['granted'] = json_decode((string)$h['granted'], true) ?: [];
            $h['revoked'] = json_decode((string)$h['revoked'], true) ?: [];
            $h['granted_labels'] = array_map('acl_key_label', array_slice($h['granted'], 0, 40));
            $h['revoked_labels'] = array_map('acl_key_label', array_slice($h['revoked'], 0, 40));
        }
        unset($h);
    } catch (\Throwable $e) {}

    echo json_encode([
        'ok'      => true,
        'role'    => $role,
        'perms'   => in_array('*', $perms, true) ? acl_all_keys() : array_values($perms),
        'is_all'  => in_array('*', $perms, true) ? 1 : 0,
        'history' => $hist,
        'can_edit'=> rl_can_touch($role, $IS_SUPER, $LEVELS) && $can_edit ? 1 : 0,
    ]);
    exit;
}

/* ============================================================================
   SAVE  —  create or update a role
   ============================================================================ */
if (isset($_POST['save_role'])) {
    $id    = (int)($_POST['role_id'] ?? 0);
    $name  = trim((string)($_POST['role_name'] ?? ''));
    $desc  = trim((string)($_POST['description'] ?? ''));
    $level = strtolower(trim((string)($_POST['level'] ?? 'employee')));
    $stat  = !empty($_POST['status']) ? 1 : 0;

    if ($name === '') { $_SESSION['flash_error'] = 'Give the role a name.'; redirect('roles.php'); }
    if (!array_key_exists($level, $LEVELS)) {
        $_SESSION['flash_error'] = 'You cannot build a role at that level.';
        redirect('roles.php');
    }

    /* Never trust the browser: keep only the keys this account actually holds. */
    $wanted  = isset($_POST['perms']) && is_array($_POST['perms']) ? $_POST['perms'] : [];
    $granted = acl_filter_grant($wanted);
    $dropped = count($wanted) - count($granted);

    /* keep the old-style list in step so pages written before this still work */
    $legacy = [];
    foreach ($MODULES as $mk => $m) {
        $l = $m['legacy'] ?? '';
        if ($l === '' || in_array($l, $legacy, true)) continue;
        if (in_array("$mk.view", $granted, true)) { $legacy[] = $l; }
    }

    if ($id > 0) {
        $cur = $db->select("SELECT * FROM roles WHERE id = ?", [$id]);
        if (empty($cur)) { $_SESSION['flash_error'] = 'That role no longer exists.'; redirect('roles.php'); }
        if (!rl_can_touch($cur[0], $IS_SUPER, $LEVELS) || !$can_edit) {
            $_SESSION['flash_error'] = 'This role is above your own access — you cannot change it.';
            redirect('roles.php');
        }

        $was   = rl_perms($cur[0]);
        $added = array_values(array_diff($granted, $was));
        $lost  = array_values(array_diff($was, $granted));

        try {
            $db->insert(
                "UPDATE roles SET name = ?, description = ?, level = ?, status = ?, permissions = ?, perms_json = ?, updated_at = NOW() WHERE id = ?",
                [$name, $desc, $level, $stat, json_encode($legacy), json_encode($granted), $id]
            );
        } catch (\Throwable $e) {
            $_SESSION['flash_error'] = 'The role could not be saved.';
            redirect('roles.php');
        }

        acl_log($db, 'role', $id, $name, 'update', $added, $lost,
                trim((string)($_POST['reason'] ?? '')));
        activity_log($db, 'update', 'User Management',
            "Role $name updated — " . count($granted) . ' permission(s)', 'role', $id);
        $_SESSION['flash_success'] = "Role “$name” saved with " . count($granted) . ' permission point(s).'
            . ($dropped > 0 ? " $dropped tick(s) were above your own access and were left out." : '');
    } else {
        if (!$can_create) { $_SESSION['flash_error'] = 'You cannot create roles.'; redirect('roles.php'); }
        $res = rl_insert(
            $db->getConnection(),
            "INSERT INTO roles (name, description, level, status, permissions, perms_json, created_by, created_by_name)
             VALUES (?,?,?,?,?,?,?,?)",
            'sssisssi',
            [$name, $desc, $level, $stat, json_encode($legacy), json_encode($granted),
             $user_id, $user['name']]
        );
        $id = $res['id'];

        if ($id) {
            acl_log($db, 'role', $id, $name, 'create', $granted, [], trim((string)($_POST['reason'] ?? '')));
            activity_log($db, 'create', 'User Management', "Role $name created", 'role', $id);
            $_SESSION['flash_success'] = "Role “$name” created with " . count($granted) . ' permission point(s).'
                . ($dropped > 0 ? " $dropped tick(s) were above your own access and were left out." : '');
        } else {
            $_SESSION['flash_error'] = 'The role could not be created. ' . $res['error'];
        }
    }
    redirect('roles.php');
}

/* ============================================================================
   DUPLICATE
   ============================================================================ */
if (isset($_POST['clone_role'])) {
    $id = (int)($_POST['role_id'] ?? 0);
    $r  = $db->select("SELECT * FROM roles WHERE id = ?", [$id]);
    if (!empty($r) && $can_create) {
        $src   = $r[0];
        $perms = acl_filter_grant(rl_perms($src));         // never above my own ceiling
        $lvl   = strtolower((string)($src['level'] ?? 'employee'));
        if (!array_key_exists($lvl, $LEVELS)) { $lvl = array_key_first($LEVELS) ?: 'employee'; }
        $name  = substr($src['name'] . ' (copy)', 0, 100);
        try {
            $new = $db->insert(
                "INSERT INTO roles (name, description, level, status, permissions, perms_json, created_by, created_by_name)
                 VALUES (?,?,?,1,?,?,?,?)",
                [$name, $src['description'], $lvl, $src['permissions'], json_encode($perms), $user_id, $user['name']]
            );
            if ($new) {
                acl_log($db, 'role', $new, $name, 'create', $perms, [], 'Copied from ' . $src['name']);
                $_SESSION['flash_success'] = "“$name” created — edit it and save.";
            }
        } catch (\Throwable $e) { $_SESSION['flash_error'] = 'The copy could not be made.'; }
    }
    redirect('roles.php');
}

/* ============================================================================
   DELETE
   ============================================================================ */
if (isset($_POST['delete_role'])) {
    $id = (int)($_POST['role_id'] ?? 0);
    $r  = $db->select("SELECT * FROM roles WHERE id = ?", [$id]);
    if (empty($r)) { redirect('roles.php'); }
    if (!$can_delete || !rl_can_touch($r[0], $IS_SUPER, $LEVELS)) {
        $_SESSION['flash_error'] = 'You cannot delete this role.';
        redirect('roles.php');
    }
    $inUse = 0;
    try { $inUse = (int)($db->select("SELECT COUNT(*) c FROM users WHERE role_id = ?", [$id])[0]['c'] ?? 0); }
    catch (\Throwable $e) {}

    if ($inUse > 0) {
        $_SESSION['flash_error'] = "$inUse staff account(s) are on “{$r[0]['name']}”. Move them to another role first, or switch this one off instead.";
    } else {
        try {
            $db->insert("DELETE FROM roles WHERE id = ?", [$id]);
            acl_log($db, 'role', $id, $r[0]['name'], 'delete', [], rl_perms($r[0]), 'Role deleted');
            activity_log($db, 'delete', 'User Management', "Role {$r[0]['name']} deleted", 'role', $id);
            $_SESSION['flash_success'] = "Role “{$r[0]['name']}” deleted.";
        } catch (\Throwable $e) { $_SESSION['flash_error'] = 'The role could not be deleted.'; }
    }
    redirect('roles.php');
}

/* ============================================================================
   TURN A ROLE ON / OFF
   ============================================================================ */
if (isset($_POST['toggle_role'])) {
    $id = (int)($_POST['role_id'] ?? 0);
    $r  = $db->select("SELECT * FROM roles WHERE id = ?", [$id]);
    if (!empty($r) && $can_edit && rl_can_touch($r[0], $IS_SUPER, $LEVELS)) {
        $new = (int)($r[0]['status'] ?? 1) === 1 ? 0 : 1;
        try { $db->insert("UPDATE roles SET status = ?, updated_at = NOW() WHERE id = ?", [$new, $id]); } catch (\Throwable $e) {}
        acl_log($db, 'role', $id, $r[0]['name'], 'update', [], [], $new ? 'Role switched on' : 'Role switched off');
        $_SESSION['flash_success'] = "“{$r[0]['name']}” is now " . ($new ? 'active.' : 'switched off — everyone on it loses access until it is switched back on.');
    }
    redirect('roles.php');
}

/* ============================================================================
   DATA
   ============================================================================ */
$roles = [];
try {
    $roles = $db->select(
        "SELECT r.*, (SELECT COUNT(*) FROM users u WHERE u.role_id = r.id) AS staff_count
         FROM roles r ORDER BY FIELD(r.level,'superadmin','admin','employee'), r.id ASC");
} catch (\Throwable $e) {
    $roles = $db->select("SELECT * FROM roles ORDER BY id ASC");
}

$LEVEL_META = [
    'superadmin' => ['Super Admin', 'bg-violet-50 text-violet-700 ring-violet-200', 'fa-crown'],
    'admin'      => ['Admin',       'bg-rose-50 text-rose-700 ring-rose-200',       'fa-shield-halved'],
    'employee'   => ['Employee',    'bg-teal-50 text-teal-700 ring-teal-200',       'fa-user-tie'],
];
?>
<!DOCTYPE html>
<html lang="<?php echo $current_lang; ?>">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Role Management - <?php echo htmlspecialchars($company_name); ?> Admin</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
    <style>
        body { font-family: 'Inter', sans-serif; }
        [x-cloak] { display: none !important; }
        .lbl { display:block; font-size:11px; font-weight:700; color:#475569; margin-bottom:4px; }
        .fld { width:100%; border:1px solid #cbd5e1; border-radius:10px; padding:8px 11px; font-size:13px; background:#fff; }
        .fld:focus { outline:none; border-color:#6366f1; box-shadow:0 0 0 3px rgba(99,102,241,.15); }
        .pbox { display:flex; align-items:flex-start; gap:8px; padding:7px 9px; border:1px solid #e2e8f0; border-radius:9px; background:#fff; cursor:pointer; font-size:11.5px; line-height:1.35; }
        .pbox:hover { border-color:#a5b4fc; }
        .pbox.on { border-color:#6366f1; background:#eef2ff; }
        .pbox.locked { opacity:.45; cursor:not-allowed; background:#f8fafc; }
    </style>
</head>
<body class="bg-gray-50" x-data="roleBoard()" x-cloak>

<div class="flex h-screen overflow-hidden">

    <?php include __DIR__ . '/includes/sidebar.php'; ?>

    <div class="flex-1 flex flex-col min-w-0 bg-gray-100 overflow-hidden">

        <header class="h-20 bg-white flex items-center justify-between px-4 lg:px-8 shadow-sm border-b border-gray-200 z-40 relative flex-shrink-0">
            <div class="flex items-center min-w-0">
                <button @click="sidebarOpen = !sidebarOpen" class="p-2 mr-3 text-slate-500 hover:text-indigo-600 rounded-lg hover:bg-gray-100"><i class="fas fa-bars text-xl"></i></button>
                <div class="min-w-0">
                    <h2 class="text-xl font-bold truncate text-slate-800">Role Management</h2>
                    <p class="text-[11px] text-slate-400 hidden sm:block">
                        <?php echo count(acl_all_keys()); ?> permission points across <?php echo count($MODULES); ?> modules
                    </p>
                </div>
            </div>
            <div class="flex items-center gap-2">
                <a href="staff.php" class="hidden sm:inline-flex items-center gap-2 px-4 py-2 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600 hover:bg-slate-50"><i class="fas fa-users-gear"></i> Staff Accounts</a>
                <?php if ($can_create && !empty($LEVELS)): ?>
                <button @click="openRole(null)" class="inline-flex items-center gap-2 px-4 py-2.5 rounded-xl bg-gradient-to-r from-indigo-600 to-violet-600 text-white text-xs font-bold shadow hover:shadow-lg"><i class="fas fa-plus"></i> Create Role</button>
                <?php endif; ?>
            </div>
        </header>

        <main class="flex-1 overflow-y-auto p-4 md:p-6 lg:p-8">

            <?php if ($flash_ok): ?>
            <div class="mb-5 bg-emerald-50 border border-emerald-200 text-emerald-700 px-4 py-3 rounded-xl text-sm"><i class="fas fa-check-circle mr-2"></i><?php echo htmlspecialchars($flash_ok); ?></div>
            <?php endif; ?>
            <?php if ($flash_err): ?>
            <div class="mb-5 bg-rose-50 border border-rose-200 text-rose-700 px-4 py-3 rounded-xl text-sm"><i class="fas fa-circle-exclamation mr-2"></i><?php echo htmlspecialchars($flash_err); ?></div>
            <?php endif; ?>

            <div class="mb-5 rounded-2xl border border-indigo-200 bg-indigo-50/60 px-5 py-4 text-xs text-indigo-900 leading-relaxed">
                <p class="font-bold mb-1"><i class="fas fa-circle-info mr-1"></i>How access works here</p>
                <p>
                    A role opens into <b>modules</b>. Inside each module you tick the <b>actions</b> a person may take and the
                    <b>columns</b> they may see — separately. You are
                    <?php if ($IS_SUPER): ?>
                        a <b>Super Admin</b>, so everything is open to you: you can build Admin and Employee roles.
                    <?php else: ?>
                        an <b>Admin</b>, so you can only tick what you hold yourself and only build Employee roles.
                        Anything above your own access is shown locked.
                    <?php endif; ?>
                </p>
            </div>

            <div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
                <div class="p-5 md:p-6 border-b border-slate-100">
                    <h3 class="text-lg font-extrabold text-slate-800">Custom Roles</h3>
                    <p class="text-xs text-slate-400 mt-0.5">A role is the starting point. On the Staff screen you can give one person a little more or a little less.</p>
                </div>

                <div class="overflow-x-auto">
                    <table class="w-full text-left border-collapse text-xs">
                        <thead>
                            <tr class="bg-slate-50 text-[10px] uppercase text-slate-500 tracking-wider border-b border-slate-200">
                                <th class="p-4 font-semibold">Role</th>
                                <th class="p-4 font-semibold">Level</th>
                                <th class="p-4 font-semibold">Access granted</th>
                                <th class="p-4 font-semibold">Staff on it</th>
                                <th class="p-4 font-semibold">Status</th>
                                <th class="p-4 font-semibold text-center">Action</th>
                            </tr>
                        </thead>
                        <tbody class="divide-y divide-slate-100">
                        <?php foreach ($roles as $r):
                            $perms = rl_perms($r);
                            $isAll = in_array('*', $perms, true) || (int)$r['id'] === 1;
                            $lvl   = $isAll ? 'superadmin' : strtolower((string)($r['level'] ?? 'employee'));
                            $lm    = $LEVEL_META[$lvl] ?? $LEVEL_META['employee'];
                            $touch = rl_can_touch($r, $IS_SUPER, $LEVELS);
                            $active = (int)($r['status'] ?? 1) === 1;

                            /* which modules this role reaches, and how deep */
                            $chips = [];
                            foreach ($MODULES as $mk => $m) {
                                $all = acl_module_keys($mk);
                                $have = $isAll ? count($all) : count(array_intersect($all, $perms));
                                if ($have > 0) { $chips[] = [$m['label'], $have, count($all)]; }
                            }
                        ?>
                            <tr class="hover:bg-slate-50/70 align-top">
                                <td class="p-4">
                                    <p class="font-bold text-slate-800 text-sm"><i class="fas fa-shield-halved text-indigo-400 mr-1.5"></i><?php echo htmlspecialchars($r['name']); ?></p>
                                    <?php if (!empty($r['description'])): ?>
                                    <p class="text-slate-400 mt-0.5 max-w-[220px]"><?php echo htmlspecialchars($r['description']); ?></p>
                                    <?php endif; ?>
                                    <?php if (!empty($r['created_by_name'])): ?>
                                    <p class="text-[10px] text-slate-300 mt-1">by <?php echo htmlspecialchars($r['created_by_name']); ?></p>
                                    <?php endif; ?>
                                </td>

                                <td class="p-4 whitespace-nowrap">
                                    <span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-[10px] font-bold ring-1 <?php echo $lm[1]; ?>">
                                        <i class="fas <?php echo $lm[2]; ?>"></i><?php echo $lm[0]; ?>
                                    </span>
                                </td>

                                <td class="p-4">
                                    <?php if ($isAll): ?>
                                        <span class="inline-block bg-violet-100 text-violet-700 text-[10px] font-black px-2.5 py-1 rounded-lg">FULL SYSTEM ACCESS</span>
                                    <?php elseif (empty($chips)): ?>
                                        <span class="text-slate-300">No access yet</span>
                                    <?php else: ?>
                                        <p class="text-[10px] font-bold text-slate-500 mb-1.5"><?php echo count($perms); ?> permission point(s) across <?php echo count($chips); ?> module(s)</p>
                                        <div class="flex flex-wrap gap-1 max-w-[420px]">
                                            <?php foreach (array_slice($chips, 0, 8) as $c): ?>
                                            <span class="bg-slate-100 text-slate-600 text-[10px] font-bold px-2 py-0.5 rounded-md border border-slate-200">
                                                <?php echo htmlspecialchars($c[0]); ?> <span class="text-slate-400"><?php echo $c[1]; ?>/<?php echo $c[2]; ?></span>
                                            </span>
                                            <?php endforeach; ?>
                                            <?php if (count($chips) > 8): ?>
                                            <span class="text-[10px] font-bold text-indigo-500 px-1 py-0.5">+<?php echo count($chips) - 8; ?> more</span>
                                            <?php endif; ?>
                                        </div>
                                    <?php endif; ?>
                                </td>

                                <td class="p-4 whitespace-nowrap">
                                    <span class="font-bold text-slate-700"><?php echo (int)($r['staff_count'] ?? 0); ?></span>
                                    <span class="text-slate-400">staff</span>
                                </td>

                                <td class="p-4 whitespace-nowrap">
                                    <span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-[10px] font-bold ring-1 <?php echo $active ? 'bg-emerald-50 text-emerald-600 ring-emerald-200' : 'bg-slate-100 text-slate-500 ring-slate-200'; ?>">
                                        <i class="fas <?php echo $active ? 'fa-circle-check' : 'fa-circle-pause'; ?>"></i><?php echo $active ? 'Active' : 'Off'; ?>
                                    </span>
                                </td>

                                <td class="p-4">
                                    <div class="flex items-center justify-center gap-1.5">
                                        <button @click="openRole(<?php echo (int)$r['id']; ?>)" title="Open"
                                                class="w-8 h-8 rounded-lg bg-slate-100 text-slate-500 hover:bg-indigo-100 hover:text-indigo-600"><i class="fas fa-eye text-xs"></i></button>
                                        <?php if ($touch && $can_create): ?>
                                        <form method="POST" class="inline"><input type="hidden" name="clone_role" value="1"><input type="hidden" name="role_id" value="<?php echo (int)$r['id']; ?>">
                                            <button type="submit" title="Make a copy" class="w-8 h-8 rounded-lg bg-sky-50 text-sky-600 hover:bg-sky-100"><i class="fas fa-copy text-xs"></i></button>
                                        </form>
                                        <?php endif; ?>
                                        <?php if ($touch && $can_edit): ?>
                                        <form method="POST" class="inline"><input type="hidden" name="toggle_role" value="1"><input type="hidden" name="role_id" value="<?php echo (int)$r['id']; ?>">
                                            <button type="submit" title="<?php echo $active ? 'Switch off' : 'Switch on'; ?>" class="w-8 h-8 rounded-lg <?php echo $active ? 'bg-amber-50 text-amber-600 hover:bg-amber-100' : 'bg-emerald-50 text-emerald-600 hover:bg-emerald-100'; ?>"><i class="fas <?php echo $active ? 'fa-pause' : 'fa-play'; ?> text-xs"></i></button>
                                        </form>
                                        <?php endif; ?>
                                        <?php if ($touch && $can_delete): ?>
                                        <button @click="askDelete(<?php echo (int)$r['id']; ?>, '<?php echo htmlspecialchars(addslashes($r['name']), ENT_QUOTES); ?>')" title="Delete"
                                                class="w-8 h-8 rounded-lg bg-rose-50 text-rose-600 hover:bg-rose-100"><i class="fas fa-trash text-xs"></i></button>
                                        <?php endif; ?>
                                        <?php if (!$touch): ?>
                                        <span class="text-[10px] text-slate-400 font-bold bg-slate-100 px-2 py-1 rounded" title="<?php echo (int)$r['id'] === 1 ? 'The system role can never be changed' : 'This role is at or above your own level'; ?>"><i class="fas fa-lock mr-1"></i>Locked</span>
                                        <?php endif; ?>
                                    </div>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </main>
    </div>
</div>

<!-- ================= ROLE BUILDER ================= -->
<div x-show="box" x-cloak class="fixed inset-0 z-[70] flex items-center justify-center p-3 sm:p-4 bg-slate-900/50 backdrop-blur-sm" @click.self="box = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-6xl max-h-[94vh] flex flex-col overflow-hidden">
        <form method="POST" class="flex flex-col min-h-0 flex-1">
            <input type="hidden" name="save_role" value="1">
            <input type="hidden" name="role_id" :value="f.id">

            <!-- header -->
            <div class="px-6 py-4 border-b border-slate-100 flex items-center justify-between gap-3 flex-shrink-0">
                <div class="min-w-0">
                    <h3 class="text-lg font-extrabold text-slate-800" x-text="f.id ? 'Edit role' : 'Create a role'"></h3>
                    <p class="text-xs text-slate-400">
                        <span x-text="picked.length"></span> of <?php echo count($CEILING); ?> permission point(s) you can give
                        <span x-show="!readonly" class="text-indigo-500 font-semibold"> · tick what this role may do and see</span>
                        <span x-show="readonly" class="text-amber-600 font-semibold"> · read only — this role is at or above your own level</span>
                    </p>
                </div>
                <button type="button" @click="box = false" class="w-9 h-9 rounded-xl bg-slate-100 text-slate-500 hover:bg-slate-200 flex-shrink-0"><i class="fas fa-xmark"></i></button>
            </div>

            <!-- meta -->
            <div class="px-6 py-4 border-b border-slate-100 grid grid-cols-1 sm:grid-cols-4 gap-3 bg-slate-50/60 flex-shrink-0">
                <div class="sm:col-span-2">
                    <label class="lbl">Role name <span class="text-rose-500">*</span></label>
                    <input type="text" name="role_name" x-model="f.name" class="fld" required :disabled="readonly" placeholder="Sales Manager">
                </div>
                <div>
                    <label class="lbl">This role is for</label>
                    <select name="level" x-model="f.level" class="fld" :disabled="readonly">
                        <?php foreach ($LEVELS as $lk => $ll): ?>
                        <option value="<?php echo $lk; ?>"><?php echo $ll; ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div>
                    <label class="lbl">Description</label>
                    <input type="text" name="description" x-model="f.description" class="fld" :disabled="readonly" placeholder="What this role is for">
                </div>
                <div class="sm:col-span-4 flex flex-wrap items-center gap-4">
                    <label class="flex items-center gap-2 text-xs font-bold text-slate-600">
                        <input type="checkbox" name="status" x-model="f.status" class="w-4 h-4 rounded accent-emerald-600" :disabled="readonly"> Role is active
                    </label>
                    <div class="flex-1 min-w-[200px]">
                        <input type="text" name="reason" class="fld !py-1.5 !text-xs" :disabled="readonly" placeholder="Why is this changing? (kept in the access history)">
                    </div>
                    <div class="flex gap-2" x-show="!readonly">
                        <button type="button" @click="setAll(true)"  class="px-3 py-1.5 rounded-lg bg-indigo-50 text-indigo-600 ring-1 ring-indigo-200 text-[11px] font-bold hover:bg-indigo-100"><i class="fas fa-check-double mr-1"></i>Tick everything I can give</button>
                        <button type="button" @click="setAll(false)" class="px-3 py-1.5 rounded-lg bg-white ring-1 ring-slate-200 text-[11px] font-bold text-slate-500 hover:bg-slate-50"><i class="fas fa-eraser mr-1"></i>Clear all</button>
                    </div>
                </div>
            </div>

            <!-- search -->
            <div class="px-6 py-3 border-b border-slate-100 flex-shrink-0">
                <div class="relative">
                    <input type="text" x-model="q" class="fld pl-9" placeholder="Search a module, an action or a column…">
                    <i class="fas fa-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-300 text-xs"></i>
                </div>
            </div>

            <!-- the modules -->
            <div class="flex-1 overflow-y-auto px-6 py-5 space-y-5 min-h-0">
                <?php foreach ($GROUPS as $gname => $gicon):
                    $inGroup = array_filter($MODULES, function ($m) use ($gname) { return ($m['group'] ?? '') === $gname; });
                    if (empty($inGroup)) continue; ?>

                <div x-show="groupVisible('<?php echo $gname; ?>')">
                    <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-2.5">
                        <i class="fas <?php echo $gicon; ?> mr-1"></i><?php echo $gname; ?>
                    </p>

                    <div class="space-y-3">
                    <?php foreach ($inGroup as $mk => $m):
                        $mKeys   = acl_module_keys($mk);
                        $mAllow  = array_values(array_intersect($mKeys, $CEILING));
                        $blocked = count($mKeys) - count($mAllow);
                    ?>
                        <div class="rounded-xl border border-slate-200 overflow-hidden" x-show="modVisible('<?php echo $mk; ?>')">
                            <div class="flex items-center justify-between gap-3 px-4 py-2.5 bg-slate-50 border-b border-slate-200 cursor-pointer" @click="toggleOpen('<?php echo $mk; ?>')">
                                <div class="flex items-center gap-2.5 min-w-0">
                                    <i class="fas <?php echo $m['icon']; ?> text-indigo-500 text-sm"></i>
                                    <span class="font-bold text-slate-700 text-sm truncate"><?php echo htmlspecialchars($m['label']); ?></span>
                                    <span class="text-[10px] font-bold px-2 py-0.5 rounded-md"
                                          :class="modCount('<?php echo $mk; ?>') > 0 ? 'bg-indigo-100 text-indigo-600' : 'bg-slate-200 text-slate-400'">
                                        <span x-text="modCount('<?php echo $mk; ?>')"></span>/<?php echo count($mAllow); ?>
                                    </span>
                                    <?php if ($blocked > 0): ?>
                                    <span class="text-[10px] font-bold text-slate-400"><i class="fas fa-lock"></i> <?php echo $blocked; ?> above you</span>
                                    <?php endif; ?>
                                </div>
                                <div class="flex items-center gap-2 flex-shrink-0">
                                    <button type="button" x-show="!readonly" @click.stop="modAll('<?php echo $mk; ?>', true)"  class="text-[10px] font-bold text-indigo-600 hover:underline">All</button>
                                    <button type="button" x-show="!readonly" @click.stop="modAll('<?php echo $mk; ?>', false)" class="text-[10px] font-bold text-slate-400 hover:underline">None</button>
                                    <i class="fas text-slate-400 text-xs" :class="isOpen('<?php echo $mk; ?>') ? 'fa-chevron-up' : 'fa-chevron-down'"></i>
                                </div>
                            </div>

                            <div x-show="isOpen('<?php echo $mk; ?>')" class="p-4 space-y-4">
                                <div>
                                    <p class="text-[10px] font-black text-slate-400 uppercase tracking-wider mb-2">What they may do</p>
                                    <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
                                    <?php foreach ($m['actions'] as $ak => $al):
                                        $key    = "$mk.$ak";
                                        $locked = !in_array($key, $CEILING, true); ?>
                                        <label class="pbox <?php echo $locked ? 'locked' : ''; ?>" :class="!<?php echo $locked ? 'true' : 'false'; ?> && sel['<?php echo $key; ?>'] ? 'on' : ''">
                                            <input type="checkbox" name="perms[]" value="<?php echo $key; ?>"
                                                   x-model="sel['<?php echo $key; ?>']"
                                                   <?php echo $locked ? 'disabled' : ''; ?> :disabled="readonly || <?php echo $locked ? 'true' : 'false'; ?>"
                                                   class="w-3.5 h-3.5 mt-0.5 rounded accent-indigo-600 flex-shrink-0">
                                            <span class="text-slate-700"><?php echo htmlspecialchars($al); ?>
                                                <?php if ($locked): ?><i class="fas fa-lock text-[9px] text-slate-400 ml-1"></i><?php endif; ?>
                                            </span>
                                        </label>
                                    <?php endforeach; ?>
                                    </div>
                                </div>

                                <div>
                                    <p class="text-[10px] font-black text-slate-400 uppercase tracking-wider mb-2">Which columns they may see</p>
                                    <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
                                    <?php foreach ($m['columns'] as $ck => $cl):
                                        $key    = "$mk.col.$ck";
                                        $locked = !in_array($key, $CEILING, true); ?>
                                        <label class="pbox <?php echo $locked ? 'locked' : ''; ?>" :class="!<?php echo $locked ? 'true' : 'false'; ?> && sel['<?php echo $key; ?>'] ? 'on' : ''">
                                            <input type="checkbox" name="perms[]" value="<?php echo $key; ?>"
                                                   x-model="sel['<?php echo $key; ?>']"
                                                   <?php echo $locked ? 'disabled' : ''; ?> :disabled="readonly || <?php echo $locked ? 'true' : 'false'; ?>"
                                                   class="w-3.5 h-3.5 mt-0.5 rounded accent-emerald-600 flex-shrink-0">
                                            <span class="text-slate-600"><?php echo htmlspecialchars($cl); ?>
                                                <?php if ($locked): ?><i class="fas fa-lock text-[9px] text-slate-400 ml-1"></i><?php endif; ?>
                                            </span>
                                        </label>
                                    <?php endforeach; ?>
                                    </div>
                                </div>
                            </div>
                        </div>
                    <?php endforeach; ?>
                    </div>
                </div>
                <?php endforeach; ?>

                <!-- history -->
                <div x-show="f.id && history.length" class="pt-2">
                    <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-2"><i class="fas fa-clock-rotate-left mr-1"></i>Access history</p>
                    <div class="space-y-2">
                        <template x-for="h in history" :key="h.id">
                            <div class="rounded-xl border border-slate-200 px-4 py-2.5 text-[11px]">
                                <div class="flex justify-between gap-3 flex-wrap">
                                    <span class="font-bold text-slate-700" x-text="h.action === 'create' ? 'Role created' : (h.action === 'delete' ? 'Role deleted' : 'Access changed')"></span>
                                    <span class="text-slate-400" x-text="h.when"></span>
                                </div>
                                <p class="text-emerald-600 mt-1" x-show="h.granted.length">+ <span x-text="h.granted.length"></span> given: <span class="text-slate-500" x-text="h.granted_labels.slice(0,6).join(' · ')"></span></p>
                                <p class="text-rose-600 mt-0.5" x-show="h.revoked.length">− <span x-text="h.revoked.length"></span> taken back: <span class="text-slate-500" x-text="h.revoked_labels.slice(0,6).join(' · ')"></span></p>
                                <p class="text-slate-500 mt-1" x-show="h.remark" x-text="h.remark"></p>
                                <p class="text-[10px] text-slate-400 mt-1"><i class="fas fa-user mr-1"></i><span x-text="h.done_by_name"></span> · <span x-text="h.ip_address"></span></p>
                            </div>
                        </template>
                    </div>
                </div>
            </div>

            <div class="px-6 py-4 border-t border-slate-100 flex items-center justify-between gap-3 flex-shrink-0 bg-white">
                <p class="text-[11px] text-slate-400"><i class="fas fa-shield-halved mr-1"></i>Whatever you tick is checked again on the server — nothing above your own access can be saved.</p>
                <div class="flex gap-2">
                    <button type="button" @click="box = false" class="px-5 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600">Close</button>
                    <button type="submit" x-show="!readonly" class="px-6 py-2.5 rounded-xl bg-gradient-to-r from-indigo-600 to-violet-600 text-white text-xs font-bold shadow"><i class="fas fa-check mr-1"></i> Save role</button>
                </div>
            </div>
        </form>
    </div>
</div>

<!-- ================= DELETE ================= -->
<div x-show="del" x-cloak class="fixed inset-0 z-[80] flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm" @click.self="del = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-sm p-6 text-center">
        <div class="w-14 h-14 rounded-2xl bg-rose-50 text-rose-500 flex items-center justify-center text-xl mx-auto mb-4"><i class="fas fa-trash"></i></div>
        <h3 class="text-base font-extrabold text-slate-800 mb-1">Delete this role?</h3>
        <p class="text-xs text-slate-500 mb-5">“<b x-text="delName"></b>” will be removed. If anyone is on it, move them first.</p>
        <form method="POST" class="flex gap-2">
            <input type="hidden" name="delete_role" value="1">
            <input type="hidden" name="role_id" :value="delId">
            <button type="button" @click="del = false" class="flex-1 px-4 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600">Keep it</button>
            <button type="submit" class="flex-1 px-4 py-2.5 rounded-xl bg-rose-600 text-white text-xs font-bold">Delete</button>
        </form>
    </div>
</div>

<script>
function roleBoard() {
    return {
        sidebarOpen: window.innerWidth >= 768,
        box: false, del: false, readonly: false,
        q: '', open: {}, history: [],
        delId: 0, delName: '',
        sel: {},

        CEILING:  <?php echo json_encode(array_values($CEILING)); ?>,
        MODKEYS:  <?php
            $mk = [];
            foreach ($MODULES as $k => $m) { $mk[$k] = array_values(array_intersect(acl_module_keys($k), $CEILING)); }
            echo json_encode($mk); ?>,
        MODTEXT:  <?php
            $mt = [];
            foreach ($MODULES as $k => $m) {
                $mt[$k] = strtolower($m['label'] . ' ' . implode(' ', $m['actions']) . ' ' . implode(' ', $m['columns']));
            }
            echo json_encode($mt); ?>,
        MODGROUP: <?php
            $mg = [];
            foreach ($MODULES as $k => $m) { $mg[$k] = $m['group'] ?? ''; }
            echo json_encode($mg); ?>,

        f: { id: 0, name: '', level: '<?php echo array_key_first($LEVELS) ?: 'employee'; ?>', description: '', status: true },

        get picked() { return Object.keys(this.sel).filter(k => this.sel[k]); },

        isOpen(m)     { return !!this.open[m] || this.q.trim() !== ''; },
        toggleOpen(m) { this.open[m] = !this.open[m]; },

        modCount(m) { return (this.MODKEYS[m] || []).filter(k => this.sel[k]).length; },
        modAll(m, on) {
            if (this.readonly) return;
            (this.MODKEYS[m] || []).forEach(k => { this.sel[k] = on; });
        },
        setAll(on) {
            if (this.readonly) return;
            this.CEILING.forEach(k => { this.sel[k] = on; });
        },

        modVisible(m) {
            const q = this.q.trim().toLowerCase();
            if (q === '') return true;
            return (this.MODTEXT[m] || '').indexOf(q) !== -1;
        },
        groupVisible(g) {
            const q = this.q.trim().toLowerCase();
            if (q === '') return true;
            return Object.keys(this.MODGROUP).some(m => this.MODGROUP[m] === g && this.modVisible(m));
        },

        blank() {
            const s = {};
            this.CEILING.forEach(k => { s[k] = false; });
            return s;
        },

        openRole(id) {
            this.q = ''; this.open = {}; this.history = [];
            if (!id) {
                this.readonly = false;
                this.sel = this.blank();
                this.f = { id: 0, name: '', level: '<?php echo array_key_first($LEVELS) ?: 'employee'; ?>', description: '', status: true };
                this.box = true;
                return;
            }
            this.box = true;
            fetch('roles.php?ajax=1&id=' + id, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
                .then(r => r.json())
                .then(j => {
                    if (!j.ok) { alert(j.msg || 'Role not found.'); this.box = false; return; }
                    const s = this.blank();
                    (j.perms || []).forEach(k => { if (k in s) s[k] = true; });
                    this.sel = s;
                    this.readonly = (j.can_edit != 1);
                    this.history = j.history || [];
                    this.f = {
                        id: j.role.id,
                        name: j.role.name || '',
                        level: (j.role.level || 'employee'),
                        description: j.role.description || '',
                        status: String(j.role.status === null ? 1 : j.role.status) === '1'
                    };
                })
                .catch(() => { alert('Could not load the role.'); this.box = false; });
        },

        askDelete(id, name) { this.delId = id; this.delName = name; this.del = true; }
    };
}
</script>

</body>
</html>
