<?php
/* ============================================================================
   WBMCZ ADMIN — STAFF ACCOUNTS
   ----------------------------------------------------------------------------
   Who may create whom
     Super Admin  →  Admin and Employee, with any access
     Admin        →  Employee only, and never more access than they hold
     Employee     →  nobody

   A staff member's access starts from their role, and can then be nudged for
   that one person: tick a box to give a little more, untick one to take a
   little back. Nothing above the giver's own access can be saved, and every
   change is written to the access history with a name, a time and an IP.

   The boxes on the create form are not fixed — a Super Admin designs them on
   Staff Form Fields, separately for Admin and for Employee.
   ============================================================================ */
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.view');

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

$MODULES  = acl_modules();
$GROUPS   = acl_groups();
$CEILING  = acl_ceiling();
$ALLKEYS  = acl_all_keys();
$MY_LEVEL = acl_level();
$IS_SUPER = ($MY_LEVEL === 'superadmin');
$LEVELS   = acl_creatable_levels();

$can_access = acl_can('staff.access');
$can_edit   = acl_can('staff.edit');
$can_del    = acl_can('staff.delete');
$can_pass   = acl_can('staff.password');
$can_block  = acl_can('staff.block');
$can_fields = acl_can('staff.fields');

$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']);

/* The permission set a role hands out. */
function sf_role_perms($db, $roleId) {
    if (!$roleId) return [];
    try { $r = $db->select("SELECT permissions, perms_json FROM roles WHERE id = ?", [(int)$roleId]); }
    catch (\Throwable $e) { return []; }
    if (empty($r)) return [];
    $p = json_decode((string)($r[0]['perms_json'] ?? ''), true);
    if (is_array($p) && !empty($p)) return in_array('*', $p, true) ? acl_all_keys() : $p;
    $old = json_decode((string)$r[0]['permissions'], true);
    $e = acl_expand_legacy(is_array($old) ? $old : []);
    return in_array('*', $e, true) ? acl_all_keys() : $e;
}

/* One staff row, or null. */
function sf_staff($db, $id) {
    $r = $db->select("SELECT * FROM users WHERE id = ? AND user_type = 'admin'", [(int)$id]);
    return !empty($r) ? $r[0] : null;
}

/* ============================================================================
   AJAX — one staff account, its effective access, and its history
   ============================================================================ */
if (isset($_GET['ajax'])) {
    header('Content-Type: application/json');
    $id = (int)($_GET['id'] ?? 0);
    $s  = $id ? sf_staff($db, $id) : null;
    if (!$s) { echo json_encode(['ok' => false, 'msg' => 'Staff account not found.']); exit; }

    $lvl   = acl_level($id);
    $base  = sf_role_perms($db, $s['role_id']);
    $eff   = acl_effective($id);
    if (in_array('*', $eff, true)) { $eff = acl_all_keys(); }

    $hist = [];
    try {
        $hist = $db->select("SELECT * FROM staff_access_log WHERE target_type = 'user' 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']));
            $g = json_decode((string)$h['granted'], true) ?: [];
            $v = json_decode((string)$h['revoked'], true) ?: [];
            $h['granted'] = $g; $h['revoked'] = $v;
            $h['granted_labels'] = array_map('acl_key_label', array_slice($g, 0, 40));
            $h['revoked_labels'] = array_map('acl_key_label', array_slice($v, 0, 40));
        }
        unset($h);
    } catch (\Throwable $e) {}

    echo json_encode([
        'ok'        => true,
        'staff'     => ['id' => $s['id'], 'name' => $s['name'], 'mobile' => $s['mobile'], 'email' => $s['email'],
                        'role_id' => $s['role_id'], 'status' => $s['status'], 'level' => $lvl],
        'base'      => array_values($base),
        'effective' => array_values($eff),
        'extra'     => json_decode((string)($s['perm_extra'] ?? ''), true) ?: [],
        'denied'    => json_decode((string)($s['perm_denied'] ?? ''), true) ?: [],
        'fields'    => acl_field_values($db, $id),
        'history'   => $hist,
        'can_manage'=> acl_can_manage_staff($id) && $can_access ? 1 : 0,
    ]);
    exit;
}

/* ============================================================================
   CREATE A STAFF ACCOUNT
   ============================================================================ */
if (isset($_POST['add_staff'])) {
    $level = strtolower(trim((string)($_POST['staff_level'] ?? 'employee')));

    if (!acl_can_create_level($level)) {
        $_SESSION['flash_error'] = 'You are not allowed to create a ' . htmlspecialchars($level) . ' account.';
        redirect('staff.php');
    }

    /* The form sends only the chosen level's boxes (see the fieldset in the Add
       Staff modal). This stays as the check of last resort: if a browser ever
       sends a field twice, PHP keeps the last one, so an empty duplicate could
       wipe out what was typed. Reading with a fallback to the first non-empty
       value means a stray empty copy cannot blank a real answer. */
    $pick = function ($key) {
        $v = $_POST['sf_' . $key] ?? '';
        if (is_array($v)) {
            foreach ($v as $one) { if (trim((string)$one) !== '') { return trim((string)$one); } }
            return '';
        }
        return trim((string)$v);
    };

    $fields = acl_form_fields($db, $level);
    $vals   = [];
    $missing = [];
    foreach ($fields as $f) {
        $k = $f['field_key'];
        $v = $pick($k);
        if ((int)$f['is_required'] === 1 && $v === '') { $missing[] = $f['label']; }
        $vals[$k] = $v;
    }
    if (!empty($missing)) {
        $_SESSION['flash_error'] = 'Please fill in: ' . implode(', ', $missing) . '.';
        redirect('staff.php');
    }

    $name   = $vals['name']   ?? '';
    $mobile = $vals['mobile'] ?? '';
    $email  = $vals['email']  ?? '';
    $pass   = $vals['password'] ?? '';

    if ($name === '' || $mobile === '') {
        $_SESSION['flash_error'] = 'A name and a mobile number are needed.';
        redirect('staff.php');
    }
    if (strlen($pass) < 6) {
        $_SESSION['flash_error'] = 'The password needs at least 6 characters.';
        redirect('staff.php');
    }

    $dupe = $db->select("SELECT id FROM users WHERE mobile = ? OR (email <> '' AND email = ?)", [$mobile, $email]);
    if (!empty($dupe)) {
        $_SESSION['flash_error'] = 'Someone already uses that mobile number or email address.';
        redirect('staff.php');
    }

    /* the role must exist, sit at the level being created, and be one I could build */
    $roleId = (int)($_POST['role_id'] ?? 0);
    $rolePerms = [];
    if ($roleId > 0) {
        $rr = $db->select("SELECT * FROM roles WHERE id = ?", [$roleId]);
        if (empty($rr)) { $roleId = 0; }
        else {
            $rlvl = strtolower((string)($rr[0]['level'] ?? 'employee'));
            if (!$IS_SUPER && ($rlvl === 'admin' || $rlvl === 'superadmin' || (int)$rr[0]['id'] === 1)) {
                $_SESSION['flash_error'] = 'That role is above your own level.';
                redirect('staff.php');
            }
            $rolePerms = sf_role_perms($db, $roleId);
            /* an admin can never attach a role that holds more than they do */
            if (!$IS_SUPER) {
                $over = array_diff($rolePerms, $CEILING);
                if (!empty($over)) {
                    $_SESSION['flash_error'] = 'That role holds ' . count($over) . ' permission(s) you do not have yourself, so you cannot give it out.';
                    redirect('staff.php');
                }
            }
        }
    }

    /* the extra ticks made on the create form, kept inside my ceiling */
    $wanted = isset($_POST['perms']) && is_array($_POST['perms']) ? acl_filter_grant($_POST['perms']) : [];
    $extra  = array_values(array_diff($wanted, $rolePerms));
    $denied = array_values(array_intersect(array_diff($rolePerms, $wanted), $CEILING));

    $hash = password_hash($pass, PASSWORD_DEFAULT);
    try {
        $newId = $db->insert(
            "INSERT INTO users (name, mobile, email, password, user_type, role_id, staff_level,
                                perm_extra, perm_denied, status, created_by, created_by_name, created_via)
             VALUES (?,?,?,?,'admin',?,?,?,?,1,?,?,'staff_panel')",
            [$name, $mobile, $email, $hash, $roleId ?: null, $level,
             json_encode($extra), json_encode($denied), $user_id, $user['name']]
        );
    } catch (\Throwable $e) { $newId = 0; }

    if (!$newId) {
        /* older databases may not have created_via / created_by_name */
        try {
            $newId = $db->insert(
                "INSERT INTO users (name, mobile, email, password, user_type, role_id, staff_level, perm_extra, perm_denied, status)
                 VALUES (?,?,?,?,'admin',?,?,?,?,1)",
                [$name, $mobile, $email, $hash, $roleId ?: null, $level, json_encode($extra), json_encode($denied)]
            );
        } catch (\Throwable $e) { $newId = 0; }
    }

    if (!$newId) {
        $_SESSION['flash_error'] = 'The account could not be created.';
        redirect('staff.php');
    }

    /* the boxes that are not real user columns */
    foreach ($fields as $f) {
        $k = $f['field_key'];
        if (in_array($k, ['name', 'mobile', 'email', 'password'], true)) continue;
        $maps = trim((string)($f['maps_to'] ?? ''));
        if ($maps !== '' && $maps !== 'password') {
            try { $db->insert("UPDATE users SET `$maps` = ? WHERE id = ?", [$vals[$k], $newId]); }
            catch (\Throwable $e) { acl_save_field_value($db, $newId, $k, $vals[$k]); }
        } else {
            acl_save_field_value($db, $newId, $k, $vals[$k]);
        }
    }

    $granted = array_values(array_unique(array_merge($rolePerms, $extra)));
    $granted = array_values(array_diff($granted, $denied));
    acl_log($db, 'user', $newId, $name, 'create', $granted, [], 'New ' . $level . ' account');
    activity_log($db, 'create', 'User Management', "Created $level account: $name", 'user', $newId);

    $_SESSION['flash_success'] = ucfirst($level) . " account “$name” created with " . count($granted) . ' permission point(s).';
    redirect('staff.php');
}

/* ============================================================================
   CHANGE WHAT ONE PERSON MAY DO
   ----------------------------------------------------------------------------
   You tick what this person should end up with. Whatever sits above your own
   access is left exactly as it was — you can neither give it nor take it away.
   ============================================================================ */
if (isset($_POST['save_access'])) {
    $id = (int)($_POST['staff_id'] ?? 0);
    $s  = sf_staff($db, $id);
    if (!$s || !$can_access || !acl_can_manage_staff($id)) {
        $_SESSION['flash_error'] = 'That account is not yours to change.';
        redirect('staff.php');
    }

    $before = acl_effective($id);
    if (in_array('*', $before, true)) { $before = $ALLKEYS; }

    /* role may be changed at the same time */
    $roleId = isset($_POST['role_id']) ? (int)$_POST['role_id'] : (int)$s['role_id'];
    if ($roleId !== (int)$s['role_id'] && $roleId > 0) {
        $rr = $db->select("SELECT * FROM roles WHERE id = ?", [$roleId]);
        if (empty($rr)) { $roleId = (int)$s['role_id']; }
        elseif (!$IS_SUPER) {
            $rlvl = strtolower((string)($rr[0]['level'] ?? 'employee'));
            $over = array_diff(sf_role_perms($db, $roleId), $CEILING);
            if ($rlvl !== 'employee' || !empty($over)) {
                $_SESSION['flash_error'] = 'That role is above your own access, so you cannot hand it out.';
                redirect('staff.php');
            }
        }
    }

    $rolePerms = sf_role_perms($db, $roleId);

    /* what I may not touch stays exactly as it is */
    $untouchable = array_values(array_diff($before, $CEILING));

    $wantedIn = isset($_POST['perms']) && is_array($_POST['perms']) ? acl_filter_grant($_POST['perms']) : [];
    $final    = array_values(array_unique(array_merge($untouchable, $wantedIn)));

    $extra  = array_values(array_diff($final, $rolePerms));
    $denied = array_values(array_diff($rolePerms, $final));

    try {
        $db->insert("UPDATE users SET role_id = ?, perm_extra = ?, perm_denied = ? WHERE id = ?",
                    [$roleId ?: null, json_encode($extra), json_encode($denied), $id]);
    } catch (\Throwable $e) {
        $_SESSION['flash_error'] = 'The access could not be saved.';
        redirect('staff.php');
    }

    $added = array_values(array_diff($final, $before));
    $lost  = array_values(array_diff($before, $final));

    acl_log($db, 'user', $id, $s['name'], 'access', $added, $lost, trim((string)($_POST['reason'] ?? '')));
    activity_log($db, 'update', 'User Management',
        "Access changed for {$s['name']}: +" . count($added) . ' / −' . count($lost), 'user', $id);

    $_SESSION['flash_success'] = "{$s['name']} now holds " . count($final) . ' permission point(s)'
        . (count($added) ? ' — ' . count($added) . ' given' : '')
        . (count($lost)  ? ', ' . count($lost) . ' taken back' : '') . '.';
    redirect('staff.php');
}

/* ============================================================================
   EDIT THE DETAILS  ·  PASSWORD  ·  BLOCK  ·  DELETE
   ============================================================================ */
if (isset($_POST['edit_staff'])) {
    $id = (int)($_POST['staff_id'] ?? 0);
    $s  = sf_staff($db, $id);
    if (!$s || !$can_edit || !acl_can_manage_staff($id)) {
        $_SESSION['flash_error'] = 'That account is not yours to edit.';
        redirect('staff.php');
    }
    $level  = acl_level($id);
    $fields = acl_form_fields($db, $level);
    $name   = trim((string)($_POST['sf_name']   ?? $s['name']));
    $mobile = trim((string)($_POST['sf_mobile'] ?? $s['mobile']));
    $email  = trim((string)($_POST['sf_email']  ?? $s['email']));

    $dupe = $db->select("SELECT id FROM users WHERE (mobile = ? OR (email <> '' AND email = ?)) AND id <> ?", [$mobile, $email, $id]);
    if (!empty($dupe)) {
        $_SESSION['flash_error'] = 'Another account already uses that mobile number or email.';
        redirect('staff.php');
    }

    try { $db->insert("UPDATE users SET name = ?, mobile = ?, email = ? WHERE id = ?", [$name, $mobile, $email, $id]); }
    catch (\Throwable $e) {}

    foreach ($fields as $f) {
        $k = $f['field_key'];
        if (in_array($k, ['name', 'mobile', 'email', 'password'], true)) continue;
        if (!isset($_POST['sf_' . $k])) continue;
        $v    = trim((string)$_POST['sf_' . $k]);
        $maps = trim((string)($f['maps_to'] ?? ''));
        if ($maps !== '' && $maps !== 'password') {
            try { $db->insert("UPDATE users SET `$maps` = ? WHERE id = ?", [$v, $id]); }
            catch (\Throwable $e) { acl_save_field_value($db, $id, $k, $v); }
        } else {
            acl_save_field_value($db, $id, $k, $v);
        }
    }

    acl_log($db, 'user', $id, $name, 'update', [], [], 'Details updated');
    activity_log($db, 'update', 'User Management', "Staff details updated: $name", 'user', $id);
    $_SESSION['flash_success'] = "“$name” updated.";
    redirect('staff.php');
}

if (isset($_POST['reset_password'])) {
    $id = (int)($_POST['staff_id'] ?? 0);
    $s  = sf_staff($db, $id);
    $np = (string)($_POST['new_password'] ?? '');
    if (!$s || !$can_pass || !acl_can_manage_staff($id)) {
        $_SESSION['flash_error'] = 'That account is not yours to change.';
    } elseif (strlen($np) < 6) {
        $_SESSION['flash_error'] = 'The password needs at least 6 characters.';
    } else {
        try { $db->insert("UPDATE users SET password = ? WHERE id = ?", [password_hash($np, PASSWORD_DEFAULT), $id]); }
        catch (\Throwable $e) {}
        acl_log($db, 'user', $id, $s['name'], 'password', [], [], 'Password reset');
        activity_log($db, 'reset', 'User Management', "Password reset for {$s['name']}", 'user', $id);
        $_SESSION['flash_success'] = "New password set for {$s['name']}.";
    }
    redirect('staff.php');
}

if (isset($_POST['toggle_staff'])) {
    $id = (int)($_POST['staff_id'] ?? 0);
    $s  = sf_staff($db, $id);
    if ($s && $can_block && acl_can_manage_staff($id) && $id !== $user_id) {
        $new = (int)($s['status'] ?? 1) === 1 ? 0 : 1;
        try { $db->insert("UPDATE users SET status = ? WHERE id = ?", [$new, $id]); } catch (\Throwable $e) {}
        acl_log($db, 'user', $id, $s['name'], 'update', [], [], $new ? 'Account unblocked' : 'Account blocked');
        activity_log($db, $new ? 'unblock' : 'block', 'User Management', ($new ? 'Unblocked' : 'Blocked') . " staff {$s['name']}", 'user', $id);
        $_SESSION['flash_success'] = "{$s['name']} is now " . ($new ? 'active.' : 'blocked — they cannot sign in.');
    } else {
        $_SESSION['flash_error'] = 'That account cannot be blocked from here.';
    }
    redirect('staff.php');
}

if (isset($_POST['delete_staff'])) {
    $id = (int)($_POST['staff_id'] ?? 0);
    $s  = sf_staff($db, $id);
    if (!$s || !$can_del || !acl_can_manage_staff($id)) {
        $_SESSION['flash_error'] = 'That account is not yours to remove.';
    } elseif ($id === $user_id) {
        $_SESSION['flash_error'] = 'You cannot remove your own account.';
    } elseif (acl_level($id) === 'superadmin') {
        $_SESSION['flash_error'] = 'A Super Admin account cannot be removed from here.';
    } else {
        /* ------------------------------------------------------------------
           Removing a staff account used to run DELETE FROM users, so the row
           was gone — which is why nothing ever turned up under Deleted Users,
           and why there was no way back from a mis-click.

           It is a soft delete now, exactly like removing a member: the account
           can no longer sign in and is hidden everywhere, but the row is intact
           and Deleted Users can restore it. Their answers on the staff form are
           kept too, so a restore brings back the whole account rather than a
           blank one. To erase it for good, use "Delete for ever" on the Deleted
           Users page — two deliberate steps, not one.
           ------------------------------------------------------------------ */
        try {
            $db->insert("UPDATE users SET deleted_at = NOW(), deleted_by = ?, delete_reason = ?, status = 0
                          WHERE id = ? AND user_type = 'admin'",
                [$user_id, 'Removed from Staff Accounts', $id]);
        } catch (\Throwable $e) {}
        try {
            $db->insert("INSERT INTO user_update_history (user_id, field_label, old_value, new_value, updated_by, updated_by_name)
                         VALUES (?, 'Staff account removed', 'Active', 'Deleted', ?, ?)",
                [$id, $user_id, (string)($user['name'] ?? 'Admin')]);
        } catch (\Throwable $e) {}
        acl_log($db, 'user', $id, $s['name'], 'delete', [], [], 'Staff account removed');
        activity_log($db, 'delete', 'User Management', "Removed staff {$s['name']}", 'user', $id);
        $_SESSION['flash_success'] = "“{$s['name']}” removed.";
    }
    redirect('staff.php');
}

/* ============================================================================
   DATA
   ============================================================================ */
$f_q     = trim((string)($_GET['q'] ?? ''));
$f_level = trim((string)($_GET['lvl'] ?? ''));

$where = ["u.user_type = 'admin'"]; $params = [];
if ($f_q !== '') {
    $where[] = "(u.name LIKE ? OR u.mobile LIKE ? OR u.email LIKE ?)";
    $like = "%$f_q%"; array_push($params, $like, $like, $like);
}
if (in_array($f_level, ['superadmin', 'admin', 'employee'], true)) {
    $where[] = "COALESCE(NULLIF(u.staff_level,''), 'employee') = ?"; $params[] = $f_level;
}
$where_sql = implode(' AND ', $where);

$staffs = [];
try {
    $staffs = $db->select(
        "SELECT u.*, r.name AS role_name, r.level AS role_level
         FROM users u LEFT JOIN roles r ON r.id = u.role_id
         WHERE $where_sql
         ORDER BY FIELD(COALESCE(NULLIF(u.staff_level,''),'employee'),'superadmin','admin','employee'), u.name ASC",
        $params);
} catch (\Throwable $e) {
    $staffs = $db->select("SELECT u.*, r.name AS role_name FROM users u LEFT JOIN roles r ON r.id = u.role_id WHERE u.user_type='admin' ORDER BY u.id ASC");
}

/* An admin only sees the employees plus themselves. */
if (!$IS_SUPER) {
    $staffs = array_values(array_filter($staffs, function ($s) use ($user_id) {
        return (int)$s['id'] === $user_id || acl_level((int)$s['id']) === 'employee';
    }));
}

/* Roles I may hand out, grouped by the level they belong to. */
$roleOptions = [];
try {
    foreach ($db->select("SELECT * FROM roles WHERE (status IS NULL OR status = 1) ORDER BY name ASC") as $r) {
        $rl = strtolower((string)($r['level'] ?? 'employee'));
        if ((int)$r['id'] === 1) { $rl = 'superadmin'; }
        if (!$IS_SUPER) {
            if ($rl !== 'employee') continue;
            if (!empty(array_diff(sf_role_perms($db, $r['id']), $CEILING))) continue;   // holds more than I do
        }
        if ($rl === 'superadmin') continue;      // never handed out from this screen
        $roleOptions[$rl][] = ['id' => (int)$r['id'], 'name' => $r['name'],
                               'count' => count(sf_role_perms($db, $r['id']))];
    }
} catch (\Throwable $e) {}

$FORM_FIELDS = [];
foreach (array_keys($LEVELS) as $lk) { $FORM_FIELDS[$lk] = acl_form_fields($db, $lk); }

$counts = ['superadmin' => 0, 'admin' => 0, 'employee' => 0];
foreach ($staffs as $s) {
    $l = acl_level((int)$s['id']);
    if (isset($counts[$l])) $counts[$l]++;
}

$LEVEL_META = [
    'superadmin' => ['Super Admin', 'bg-violet-50 text-violet-700 ring-violet-200', 'fa-crown',          'from-violet-500 to-purple-600'],
    'admin'      => ['Admin',       'bg-rose-50 text-rose-700 ring-rose-200',       'fa-shield-halved',  'from-rose-500 to-pink-600'],
    'employee'   => ['Employee',    'bg-teal-50 text-teal-700 ring-teal-200',       'fa-user-tie',       'from-teal-500 to-cyan-600'],
];
?>
<!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>Staff Accounts - <?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="staffBoard()" 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">Staff Accounts</h2>
                    <p class="text-[11px] text-slate-400 hidden sm:block">
                        You are a <b><?php echo $LEVEL_META[$MY_LEVEL][0] ?? ucfirst($MY_LEVEL); ?></b> ·
                        <?php echo $IS_SUPER ? 'you can create Admins and Employees' : 'you can create Employees, with at most your own access'; ?>
                    </p>
                </div>
            </div>
            <div class="flex items-center gap-2">
                <a href="roles.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-shield-halved"></i> Roles</a>
                <?php if ($can_fields): ?>
                <a href="staff_fields.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-list-check"></i> Form Fields</a>
                <?php endif; ?>
                <?php if (!empty($LEVELS)): ?>
                <button @click="openCreate()" 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-user-plus"></i> Add Staff</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="grid grid-cols-3 gap-4 mb-6">
                <?php foreach ($LEVEL_META as $lk => $lm): ?>
                <a href="?lvl=<?php echo $f_level === $lk ? '' : $lk; ?>"
                   class="bg-white rounded-2xl border p-5 transition hover:shadow-md <?php echo $f_level === $lk ? 'border-indigo-300 ring-2 ring-indigo-100' : 'border-slate-200'; ?>">
                    <div class="w-10 h-10 rounded-xl bg-gradient-to-br <?php echo $lm[3]; ?> text-white flex items-center justify-center mb-3"><i class="fas <?php echo $lm[2]; ?>"></i></div>
                    <p class="text-2xl font-black text-slate-800"><?php echo $counts[$lk]; ?></p>
                    <p class="text-[11px] font-bold text-slate-400 uppercase tracking-wide"><?php echo $lm[0]; ?></p>
                </a>
                <?php endforeach; ?>
            </div>

            <div class="bg-white rounded-2xl shadow-sm border border-slate-200 overflow-hidden">
                <form method="GET" class="p-4 md:p-5 border-b border-slate-100 flex flex-wrap gap-3 items-end bg-slate-50/60">
                    <input type="hidden" name="lvl" value="<?php echo htmlspecialchars($f_level); ?>">
                    <div class="flex-1 min-w-[220px]">
                        <label class="lbl">Search</label>
                        <div class="relative">
                            <input type="text" name="q" value="<?php echo htmlspecialchars($f_q); ?>" class="fld pl-9" placeholder="Name, mobile or email…">
                            <i class="fas fa-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-300 text-xs"></i>
                        </div>
                    </div>
                    <button type="submit" class="px-5 py-2.5 rounded-xl bg-indigo-600 text-white text-xs font-bold"><i class="fas fa-filter mr-1"></i>Filter</button>
                    <a href="staff.php" class="px-5 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600"><i class="fas fa-rotate mr-1"></i>Reset</a>
                </form>

                <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">Staff</th>
                                <th class="p-4 font-semibold">Contact</th>
                                <th class="p-4 font-semibold">Level</th>
                                <th class="p-4 font-semibold">Role</th>
                                <th class="p-4 font-semibold">Access</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 if (!empty($staffs)): foreach ($staffs as $s):
                            $sid   = (int)$s['id'];
                            $lvl   = acl_level($sid);
                            $lm    = $LEVEL_META[$lvl] ?? $LEVEL_META['employee'];
                            $eff   = acl_effective($sid);
                            $nkeys = in_array('*', $eff, true) ? count($ALLKEYS) : count($eff);
                            $mine  = ($sid === $user_id);
                            $manage= acl_can_manage_staff($sid);
                            $extra = json_decode((string)($s['perm_extra'] ?? ''), true) ?: [];
                            $deny  = json_decode((string)($s['perm_denied'] ?? ''), true) ?: [];
                            $active= (int)($s['status'] ?? 1) === 1;

                            $chips = [];
                            foreach ($MODULES as $mk => $m) {
                                list($have, $tot) = acl_module_count($mk, $sid);
                                if ($have > 0) { $chips[] = [$m['label'], $have, $tot]; }
                            }
                        ?>
                            <tr class="hover:bg-slate-50/70 align-top <?php echo $mine ? 'bg-indigo-50/30' : ''; ?>">
                                <td class="p-4">
                                    <div class="flex items-start gap-2.5">
                                        <div class="w-9 h-9 rounded-full bg-gradient-to-br <?php echo $lm[3]; ?> text-white flex items-center justify-center text-xs font-black flex-shrink-0">
                                            <?php echo strtoupper(substr($s['name'], 0, 1)); ?>
                                        </div>
                                        <div class="min-w-0">
                                            <p class="font-bold text-slate-800 text-sm truncate max-w-[160px]"><?php echo htmlspecialchars($s['name']); ?><?php if ($mine): ?> <span class="text-[9px] font-black text-indigo-500">(you)</span><?php endif; ?></p>
                                            <p class="text-[10px] text-slate-400 font-mono">ID #<?php echo str_pad($sid, 4, '0', STR_PAD_LEFT); ?></p>
                                            <?php if (!empty($s['created_by_name'])): ?>
                                            <p class="text-[10px] text-slate-300">added by <?php echo htmlspecialchars($s['created_by_name']); ?></p>
                                            <?php endif; ?>
                                        </div>
                                    </div>
                                </td>

                                <td class="p-4">
                                    <p class="text-slate-600"><i class="fas fa-phone text-slate-300 mr-1"></i><?php echo htmlspecialchars($s['mobile']); ?></p>
                                    <p class="text-slate-400 mt-0.5 truncate max-w-[170px]"><i class="fas fa-envelope text-slate-300 mr-1"></i><?php echo htmlspecialchars($s['email'] ?: '—'); ?></p>
                                </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">
                                    <p class="font-semibold text-slate-700"><?php echo htmlspecialchars($s['role_name'] ?: '—'); ?></p>
                                    <?php if (!empty($extra) || !empty($deny)): ?>
                                    <p class="text-[10px] mt-1">
                                        <?php if (!empty($extra)): ?><span class="text-emerald-600 font-bold">+<?php echo count($extra); ?> extra</span><?php endif; ?>
                                        <?php if (!empty($deny)): ?><span class="text-rose-600 font-bold ml-1">−<?php echo count($deny); ?> removed</span><?php endif; ?>
                                    </p>
                                    <?php endif; ?>
                                </td>

                                <td class="p-4">
                                    <?php if ($lvl === 'superadmin'): ?>
                                        <span class="inline-block bg-violet-100 text-violet-700 text-[10px] font-black px-2.5 py-1 rounded-lg">EVERYTHING</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"><?php echo $nkeys; ?> point(s) · <?php echo count($chips); ?> module(s)</p>
                                        <div class="flex flex-wrap gap-1 max-w-[300px]">
                                            <?php foreach (array_slice($chips, 0, 5) 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) > 5): ?><span class="text-[10px] font-bold text-indigo-500">+<?php echo count($chips) - 5; ?></span><?php endif; ?>
                                        </div>
                                    <?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 $active ? 'bg-emerald-50 text-emerald-600 ring-emerald-200' : 'bg-rose-50 text-rose-600 ring-rose-200'; ?>">
                                        <i class="fas <?php echo $active ? 'fa-circle-check' : 'fa-ban'; ?>"></i><?php echo $active ? 'Active' : 'Blocked'; ?>
                                    </span>
                                </td>

                                <td class="p-4">
                                    <div class="flex items-center justify-center gap-1.5 flex-wrap">
                                        <?php if ($manage && $can_access): ?>
                                        <button @click="openAccess(<?php echo $sid; ?>)" title="Give or take back access"
                                                class="w-8 h-8 rounded-lg bg-indigo-50 text-indigo-600 hover:bg-indigo-100"><i class="fas fa-key text-xs"></i></button>
                                        <?php endif; ?>
                                        <?php if ($manage && $can_edit): ?>
                                        <button @click="openEdit(<?php echo $sid; ?>)" title="Edit details"
                                                class="w-8 h-8 rounded-lg bg-sky-50 text-sky-600 hover:bg-sky-100"><i class="fas fa-pen text-xs"></i></button>
                                        <?php endif; ?>
                                        <?php if ($manage && $can_pass): ?>
                                        <button @click="openPass(<?php echo $sid; ?>, '<?php echo htmlspecialchars(addslashes($s['name']), ENT_QUOTES); ?>')" title="Reset password"
                                                class="w-8 h-8 rounded-lg bg-amber-50 text-amber-600 hover:bg-amber-100"><i class="fas fa-key text-xs"></i></button>
                                        <?php endif; ?>
                                        <?php if ($manage && $can_block && !$mine): ?>
                                        <form method="POST" class="inline"><input type="hidden" name="toggle_staff" value="1"><input type="hidden" name="staff_id" value="<?php echo $sid; ?>">
                                            <button type="submit" title="<?php echo $active ? 'Block' : 'Unblock'; ?>" class="w-8 h-8 rounded-lg <?php echo $active ? 'bg-slate-100 text-slate-500 hover:bg-slate-200' : 'bg-emerald-50 text-emerald-600 hover:bg-emerald-100'; ?>"><i class="fas <?php echo $active ? 'fa-ban' : 'fa-circle-check'; ?> text-xs"></i></button>
                                        </form>
                                        <?php endif; ?>
                                        <?php if ($manage && $can_del && !$mine && $lvl !== 'superadmin'): ?>
                                        <button @click="askDelete(<?php echo $sid; ?>, '<?php echo htmlspecialchars(addslashes($s['name']), ENT_QUOTES); ?>')" title="Remove"
                                                class="w-8 h-8 rounded-lg bg-rose-50 text-rose-600 hover:bg-rose-100"><i class="fas fa-user-minus text-xs"></i></button>
                                        <?php endif; ?>
                                        <?php if (!$manage): ?>
                                        <span class="text-[10px] text-slate-400 font-bold bg-slate-100 px-2 py-1 rounded"><i class="fas fa-lock mr-1"></i>Protected</span>
                                        <?php endif; ?>
                                    </div>
                                </td>
                            </tr>
                        <?php endforeach; else: ?>
                            <tr><td colspan="7" class="p-16 text-center">
                                <div class="w-16 h-16 rounded-2xl bg-slate-100 text-slate-300 flex items-center justify-center text-2xl mx-auto mb-4"><i class="fas fa-users-gear"></i></div>
                                <p class="font-bold text-slate-600 text-sm">No staff account here yet</p>
                                <p class="text-slate-400 text-xs mt-1">Use <b>Add Staff</b> to create the first one.</p>
                            </td></tr>
                        <?php endif; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </main>
    </div>
</div>

<?php
/* The permission grid is used twice — once when creating a staff account and
   once when changing what one person may do — so it is written out here. */
function sf_perm_grid($MODULES, $GROUPS, $CEILING) { ?>
    <div class="px-1">
        <div class="relative mb-3">
            <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>
        <?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; ?>')" class="mb-4">
            <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-2"><i class="fas <?php echo $gicon; ?> mr-1"></i><?php echo $gname; ?></p>
            <div class="space-y-2.5">
            <?php foreach ($inGroup as $mk => $m):
                $mKeys  = acl_module_keys($mk);
                $mAllow = array_values(array_intersect($mKeys, $CEILING));
                if (empty($mAllow)) continue;   /* nothing here I could hand out */
            ?>
                <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>
                        </div>
                        <div class="flex items-center gap-2 flex-shrink-0">
                            <button type="button" @click.stop="modAll('<?php echo $mk; ?>', true)"  class="text-[10px] font-bold text-indigo-600 hover:underline">All</button>
                            <button type="button" @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"; if (!in_array($key, $CEILING, true)) continue; ?>
                                <label class="pbox" :class="sel['<?php echo $key; ?>'] ? 'on' : ''">
                                    <input type="checkbox" name="perms[]" value="<?php echo $key; ?>" x-model="sel['<?php echo $key; ?>']" 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); ?></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"; if (!in_array($key, $CEILING, true)) continue; ?>
                                <label class="pbox" :class="sel['<?php echo $key; ?>'] ? 'on' : ''">
                                    <input type="checkbox" name="perms[]" value="<?php echo $key; ?>" x-model="sel['<?php echo $key; ?>']" 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); ?></span>
                                </label>
                            <?php endforeach; ?>
                            </div>
                        </div>
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
        </div>
        <?php endforeach; ?>
    </div>
<?php } ?>

<?php if (!empty($LEVELS)): ?>
<!-- ================= ADD STAFF ================= -->
<div x-show="create" 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="create = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-5xl max-h-[94vh] flex flex-col overflow-hidden">
        <form method="POST" class="flex flex-col min-h-0 flex-1">
            <input type="hidden" name="add_staff" value="1">

            <div class="px-6 py-4 border-b border-slate-100 flex items-center justify-between flex-shrink-0">
                <div>
                    <h3 class="text-lg font-extrabold text-slate-800">Add a staff account</h3>
                    <p class="text-xs text-slate-400">Fill in the details, pick a role, then fine-tune what they may do</p>
                </div>
                <button type="button" @click="create = false" class="w-9 h-9 rounded-xl bg-slate-100 text-slate-500 hover:bg-slate-200"><i class="fas fa-xmark"></i></button>
            </div>

            <div class="flex-1 overflow-y-auto min-h-0">
                <div class="px-6 py-4 bg-slate-50/60 border-b border-slate-100">
                    <label class="lbl">What kind of account?</label>
                    <div class="flex flex-wrap gap-2">
                        <?php foreach ($LEVELS as $lk => $ll): ?>
                        <label class="flex items-center gap-2 px-4 py-2.5 rounded-xl border cursor-pointer text-xs font-bold"
                               :class="c.level === '<?php echo $lk; ?>' ? 'border-indigo-400 bg-indigo-50 text-indigo-700 ring-2 ring-indigo-100' : 'border-slate-200 bg-white text-slate-500'">
                            <input type="radio" name="staff_level" value="<?php echo $lk; ?>" x-model="c.level" class="accent-indigo-600">
                            <i class="fas <?php echo $lk === 'admin' ? 'fa-shield-halved' : 'fa-user-tie'; ?>"></i> <?php echo $ll; ?>
                        </label>
                        <?php endforeach; ?>
                    </div>
                    <p class="text-[11px] text-slate-400 mt-2">
                        <?php echo $IS_SUPER
                            ? 'An Admin can create Employees of their own, but never more access than you give them here.'
                            : 'You can create Employees. They can never be given more than you hold yourself.'; ?>
                    </p>
                </div>

                <div class="px-6 py-5 space-y-4 border-b border-slate-100">
                    <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest">Their details</p>
                    <?php /* ------------------------------------------------------------------
                       ONE BLOCK PER LEVEL, BUT ONLY ONE OF THEM IS REAL

                       A super admin gets an Employee block and an Admin block, and
                       both are in the page at once with the SAME input names —
                       sf_name, sf_mobile, sf_email, sf_password.

                       x-show only sets display:none. A hidden input is still sent,
                       so the browser posted every name twice and PHP kept the LAST
                       one, which came from the block you were not filling in. That
                       is why creating an admin answered "Please fill in: Full Name,
                       Mobile Number, Email Address, Login Password" with all four
                       boxes visibly full.

                       A <fieldset disabled> is not just hidden: its controls are
                       left out of the submission altogether, and out of the
                       browser's own required-field check. So only the level you
                       picked is ever sent.
                       ------------------------------------------------------------------ */ ?>
                    <?php foreach ($FORM_FIELDS as $lk => $flds): ?>
                    <fieldset x-show="c.level === '<?php echo $lk; ?>'"
                              x-bind:disabled="c.level !== '<?php echo $lk; ?>'"
                              class="grid grid-cols-1 sm:grid-cols-2 gap-4 border-0 p-0 m-0 min-w-0">
                        <?php foreach ($flds as $f):
                            $req  = (int)$f['is_required'] === 1;
                            $wide = in_array($f['field_type'], ['textarea'], true); ?>
                        <div class="<?php echo $wide ? 'sm:col-span-2' : ''; ?>">
                            <label class="lbl"><?php echo htmlspecialchars($f['label']); ?><?php if ($req): ?> <span class="text-rose-500">*</span><?php endif; ?></label>
                            <?php if ($f['field_type'] === 'textarea'): ?>
                                <textarea name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" rows="2" class="fld" placeholder="<?php echo htmlspecialchars($f['placeholder']); ?>" <?php echo $req ? 'x-bind:required="c.level === \'' . $lk . '\'"' : ''; ?>></textarea>
                            <?php elseif ($f['field_type'] === 'select'): ?>
                                <select name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" class="fld">
                                    <option value="">— choose —</option>
                                    <?php foreach (preg_split('/\r\n|\r|\n/', (string)$f['options']) as $o): if (trim($o) === '') continue; ?>
                                    <option value="<?php echo htmlspecialchars(trim($o)); ?>"><?php echo htmlspecialchars(trim($o)); ?></option>
                                    <?php endforeach; ?>
                                </select>
                            <?php else: ?>
                                <input type="<?php echo htmlspecialchars($f['field_type']); ?>" name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" class="fld" placeholder="<?php echo htmlspecialchars($f['placeholder']); ?>" <?php echo $req ? 'x-bind:required="c.level === \'' . $lk . '\'"' : ''; ?>>
                            <?php endif; ?>
                            <?php if (!empty($f['help_text'])): ?><p class="text-[10px] text-slate-400 mt-1"><?php echo htmlspecialchars($f['help_text']); ?></p><?php endif; ?>
                        </div>
                        <?php endforeach; ?>
                    </fieldset>
                    <?php endforeach; ?>
                    <?php if ($can_fields): ?>
                    <p class="text-[11px] text-slate-400"><i class="fas fa-circle-info mr-1"></i>Want different boxes here? <a href="staff_fields.php" class="text-indigo-600 font-bold hover:underline">Design this form</a>.</p>
                    <?php endif; ?>
                </div>

                <div class="px-6 py-5 border-b border-slate-100">
                    <label class="lbl">Start from a role</label>
                    <select name="role_id" x-model="c.role_id" @change="applyRole()" class="fld max-w-md">
                        <option value="0">No role — I will tick everything myself</option>
                        <?php foreach ($roleOptions as $rl => $list): ?>
                        <optgroup label="<?php echo ucfirst($rl); ?> roles">
                            <?php foreach ($list as $r): ?>
                            <option value="<?php echo $r['id']; ?>"><?php echo htmlspecialchars($r['name']); ?> — <?php echo $r['count']; ?> permission(s)</option>
                            <?php endforeach; ?>
                        </optgroup>
                        <?php endforeach; ?>
                    </select>
                    <p class="text-[11px] text-slate-400 mt-2">Picking a role ticks its boxes below. Change any of them for this one person.</p>
                </div>

                <div class="px-6 py-5">
                    <div class="flex items-center justify-between mb-3 flex-wrap gap-2">
                        <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest">What this person may do and see — <span x-text="picked.length"></span> of <?php echo count($CEILING); ?></p>
                        <div class="flex gap-2">
                            <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">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">Clear all</button>
                        </div>
                    </div>
                    <?php sf_perm_grid($MODULES, $GROUPS, $CEILING); ?>
                </div>
            </div>

            <div class="px-6 py-4 border-t border-slate-100 flex justify-end gap-2 flex-shrink-0 bg-white">
                <button type="button" @click="create = false" class="px-5 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600">Cancel</button>
                <button type="submit" 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-user-plus mr-1"></i> Create account</button>
            </div>
        </form>
    </div>
</div>
<?php endif; ?>

<!-- ================= CHANGE ACCESS ================= -->
<div x-show="access" 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="access = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-5xl 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_access" value="1">
            <input type="hidden" name="staff_id" :value="s.id">

            <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">Access for <span x-text="s.name"></span></h3>
                    <p class="text-xs text-slate-400">
                        <span x-text="picked.length"></span> ticked ·
                        <span class="text-emerald-600 font-bold">+<span x-text="addedCount"></span> more than the role</span> ·
                        <span class="text-rose-600 font-bold">−<span x-text="removedCount"></span> taken back</span>
                        <span x-show="untouchable.length" class="text-slate-400"> · <span x-text="untouchable.length"></span> point(s) above your own access are left untouched</span>
                    </p>
                </div>
                <button type="button" @click="access = 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>

            <div class="flex-1 overflow-y-auto min-h-0">
                <div class="px-6 py-4 bg-slate-50/60 border-b border-slate-100 grid grid-cols-1 sm:grid-cols-3 gap-3 items-end">
                    <div>
                        <label class="lbl">Role</label>
                        <select name="role_id" x-model="s.role_id" @change="applyRoleTo(s.role_id)" class="fld">
                            <option value="0">No role — only what is ticked below</option>
                            <?php foreach ($roleOptions as $rl => $list): ?>
                            <optgroup label="<?php echo ucfirst($rl); ?> roles">
                                <?php foreach ($list as $r): ?>
                                <option value="<?php echo $r['id']; ?>"><?php echo htmlspecialchars($r['name']); ?> — <?php echo $r['count']; ?> permission(s)</option>
                                <?php endforeach; ?>
                            </optgroup>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="sm:col-span-2">
                        <label class="lbl">Why is this changing? <span class="text-slate-400 font-normal">(kept in the access history)</span></label>
                        <input type="text" name="reason" class="fld" placeholder="e.g. taking over KYC while Puja is away">
                    </div>
                </div>

                <div class="px-6 py-4 flex flex-wrap gap-2 border-b border-slate-100">
                    <button type="button" @click="resetToRole()" class="px-3 py-1.5 rounded-lg bg-white ring-1 ring-slate-200 text-[11px] font-bold text-slate-600"><i class="fas fa-rotate-left mr-1"></i>Back to exactly what the role gives</button>
                    <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">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">Clear all</button>
                </div>

                <div class="px-6 py-5">
                    <?php sf_perm_grid($MODULES, $GROUPS, $CEILING); ?>
                </div>

                <div class="px-6 pb-6" x-show="history.length">
                    <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' ? 'Account created' : (h.action === 'password' ? 'Password reset' : (h.action === 'access' ? 'Access changed' : 'Updated'))"></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>Only what you hold yourself can be given or taken back here.</p>
                <div class="flex gap-2">
                    <button type="button" @click="access = false" class="px-5 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600">Cancel</button>
                    <button type="submit" 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 access</button>
                </div>
            </div>
        </form>
    </div>
</div>

<!-- ================= EDIT DETAILS ================= -->
<div x-show="edit" x-cloak class="fixed inset-0 z-[70] flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm" @click.self="edit = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-2xl max-h-[92vh] overflow-y-auto">
        <form method="POST">
            <input type="hidden" name="edit_staff" value="1">
            <input type="hidden" name="staff_id" :value="s.id">
            <div class="px-6 py-5 border-b border-slate-100">
                <h3 class="text-lg font-extrabold text-slate-800">Edit staff details</h3>
                <p class="text-xs text-slate-400" x-text="s.name"></p>
            </div>
            <div class="p-6 grid grid-cols-1 sm:grid-cols-2 gap-4">
                <?php
                $editFields = acl_form_fields($db, 'employee');
                $seen = [];
                foreach ($FORM_FIELDS as $flds) { foreach ($flds as $f) { $seen[$f['field_key']] = $f; } }
                foreach ($seen as $f):
                    if ($f['field_key'] === 'password') continue;
                    $wide = $f['field_type'] === 'textarea'; ?>
                <div class="<?php echo $wide ? 'sm:col-span-2' : ''; ?>">
                    <label class="lbl"><?php echo htmlspecialchars($f['label']); ?></label>
                    <?php if ($f['field_type'] === 'textarea'): ?>
                        <textarea name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" rows="2" class="fld" x-model="ef['<?php echo htmlspecialchars($f['field_key']); ?>']"></textarea>
                    <?php elseif ($f['field_type'] === 'select'): ?>
                        <select name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" class="fld" x-model="ef['<?php echo htmlspecialchars($f['field_key']); ?>']">
                            <option value="">— choose —</option>
                            <?php foreach (preg_split('/\r\n|\r|\n/', (string)$f['options']) as $o): if (trim($o) === '') continue; ?>
                            <option value="<?php echo htmlspecialchars(trim($o)); ?>"><?php echo htmlspecialchars(trim($o)); ?></option>
                            <?php endforeach; ?>
                        </select>
                    <?php else: ?>
                        <input type="<?php echo htmlspecialchars($f['field_type']); ?>" name="sf_<?php echo htmlspecialchars($f['field_key']); ?>" class="fld" x-model="ef['<?php echo htmlspecialchars($f['field_key']); ?>']">
                    <?php endif; ?>
                </div>
                <?php endforeach; ?>
            </div>
            <div class="px-6 py-4 border-t border-slate-100 flex justify-end gap-2">
                <button type="button" @click="edit = false" class="px-5 py-2.5 rounded-xl bg-white ring-1 ring-slate-200 text-xs font-bold text-slate-600">Cancel</button>
                <button type="submit" class="px-6 py-2.5 rounded-xl bg-sky-600 text-white text-xs font-bold"><i class="fas fa-check mr-1"></i> Save</button>
            </div>
        </form>
    </div>
</div>

<!-- ================= PASSWORD ================= -->
<div x-show="pass" x-cloak class="fixed inset-0 z-[75] flex items-center justify-center p-4 bg-slate-900/50 backdrop-blur-sm" @click.self="pass = false">
    <div class="bg-white rounded-2xl shadow-2xl w-full max-w-sm">
        <form method="POST" class="p-6">
            <input type="hidden" name="reset_password" value="1">
            <input type="hidden" name="staff_id" :value="passId">
            <h3 class="text-base font-extrabold text-slate-800 mb-1">Set a new password</h3>
            <p class="text-xs text-slate-400 mb-4">for <b x-text="passName"></b></p>
            <input type="text" name="new_password" class="fld mb-4" required minlength="6" placeholder="At least 6 characters" autocomplete="off">
            <div class="flex gap-2">
                <button type="button" @click="pass = 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">Cancel</button>
                <button type="submit" class="flex-1 px-4 py-2.5 rounded-xl bg-amber-500 text-white text-xs font-bold">Set password</button>
            </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-user-minus"></i></div>
        <h3 class="text-base font-extrabold text-slate-800 mb-1">Remove this staff account?</h3>
        <p class="text-xs text-slate-500 mb-5">“<b x-text="delName"></b>” will lose access straight away. Their activity history stays.</p>
        <form method="POST" class="flex gap-2">
            <input type="hidden" name="delete_staff" value="1">
            <input type="hidden" name="staff_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">Remove</button>
        </form>
    </div>
</div>

<script>
function staffBoard() {
    return {
        sidebarOpen: window.innerWidth >= 768,
        create: false, access: false, edit: false, pass: false, del: false,
        q: '', open: {}, sel: {},
        s: { id: 0, name: '', role_id: 0 },
        ef: {}, base: [], untouchable: [], history: [],
        passId: 0, passName: '', delId: 0, delName: '',
        c: { level: '<?php echo array_key_first($LEVELS) ?: 'employee'; ?>', role_id: '0' },

        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); ?>,
        ROLEPERMS: <?php
            $rp = ['0' => []];
            foreach ($roleOptions as $list) {
                foreach ($list as $r) { $rp[(string)$r['id']] = array_values(array_intersect(sf_role_perms($db, $r['id']), $CEILING)); }
            }
            echo json_encode($rp); ?>,

        get picked() { return Object.keys(this.sel).filter(k => this.sel[k]); },
        get addedCount()   { return this.picked.filter(k => this.base.indexOf(k) === -1).length; },
        get removedCount() { return this.base.filter(k => !this.sel[k] && this.CEILING.indexOf(k) !== -1).length; },

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

        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) { (this.MODKEYS[m] || []).forEach(k => { this.sel[k] = on; }); },
        setAll(on)    { this.CEILING.forEach(k => { this.sel[k] = on; }); },

        modVisible(m) {
            const q = this.q.trim().toLowerCase();
            return q === '' ? true : (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));
        },

        openCreate() {
            this.q = ''; this.open = {}; this.sel = this.blank(); this.base = []; this.untouchable = [];
            this.c = { level: '<?php echo array_key_first($LEVELS) ?: 'employee'; ?>', role_id: '0' };
            this.create = true;
        },

        applyRole() {
            const p = this.ROLEPERMS[String(this.c.role_id)] || [];
            this.sel = this.blank();
            p.forEach(k => { if (k in this.sel) this.sel[k] = true; });
            this.base = p.slice();
        },

        applyRoleTo(rid) {
            const p = this.ROLEPERMS[String(rid)] || [];
            this.sel = this.blank();
            p.forEach(k => { if (k in this.sel) this.sel[k] = true; });
            this.base = p.slice();
        },

        resetToRole() { this.applyRoleTo(this.s.role_id); },

        load(id) {
            return fetch('staff.php?ajax=1&id=' + id, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
                .then(r => r.json())
                .then(j => {
                    if (!j.ok) { alert(j.msg || 'Not found.'); return null; }
                    return j;
                })
                .catch(() => { alert('Could not load that account.'); return null; });
        },

        async openAccess(id) {
            this.q = ''; this.open = {}; this.history = [];
            const j = await this.load(id);
            if (!j) return;
            const s = this.blank();
            (j.effective || []).forEach(k => { if (k in s) s[k] = true; });
            this.sel = s;
            this.base = (j.base || []).filter(k => this.CEILING.indexOf(k) !== -1);
            this.untouchable = (j.effective || []).filter(k => this.CEILING.indexOf(k) === -1);
            this.history = j.history || [];
            this.s = { id: j.staff.id, name: j.staff.name, role_id: j.staff.role_id || 0 };
            this.access = true;
        },

        async openEdit(id) {
            const j = await this.load(id);
            if (!j) return;
            this.s = { id: j.staff.id, name: j.staff.name, role_id: j.staff.role_id || 0 };
            this.ef = Object.assign({}, j.fields || {}, {
                name: j.staff.name || '', mobile: j.staff.mobile || '', email: j.staff.email || ''
            });
            this.edit = true;
        },

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

</body>
</html>
