<?php
declare(strict_types=1);
ini_set('display_errors', '0');

require_once __DIR__ . '/../includes/console_shell.php';
require_login();

$pageLink = 'settings/user-manager.php';
$acl = require_acl('can_view', $pageLink);
$errors = [];
$flash = $_SESSION['flash_user_manager'] ?? null;
unset($_SESSION['flash_user_manager']);

function um_stmt(mysqli $con, string $sql): mysqli_stmt
{
    $stmt = $con->prepare($sql);
    if (!$stmt) {
        throw new RuntimeException('Unable to prepare user manager query.');
    }
    return $stmt;
}

function um_required_access_columns(): array
{
    return [
        'payroll_access',
        'additional_payroll_access',
        'branch_access',
        'terminal_access',
        'subbranch_access',
        'department_access',
        'report_filter_access',
        'payscale_access',
        'attendance_editlog_user_access',
        'identified_img_status',
    ];
}

function um_missing_columns(mysqli $con, string $table, array $columns): array
{
    if (!$columns) {
        return [];
    }
    $placeholders = implode(',', array_fill(0, count($columns), '?'));
    $types = 's' . str_repeat('s', count($columns));
    $params = array_merge([$table], $columns);
    $stmt = um_stmt($con, 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND COLUMN_NAME IN (' . $placeholders . ')');
    $stmt->bind_param($types, ...$params);
    $stmt->execute();
    $result = $stmt->get_result();
    $found = [];
    while ($row = $result->fetch_assoc()) {
        $found[(string)$row['COLUMN_NAME']] = true;
    }
    $stmt->close();
    return array_values(array_filter($columns, static fn($column) => !isset($found[$column])));
}

function um_table_exists(mysqli $con, string $table): bool
{
    $stmt = um_stmt($con, 'SELECT COUNT(*) AS total FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=?');
    $stmt->bind_param('s', $table);
    $stmt->execute();
    $exists = (int)($stmt->get_result()->fetch_assoc()['total'] ?? 0) > 0;
    $stmt->close();
    return $exists;
}

function um_options(mysqli $con, string $sql): array
{
    $rows = [];
    $stmt = um_stmt($con, $sql);
    $stmt->execute();
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        $rows[] = $row;
    }
    $stmt->close();
    return $rows;
}

function um_user_group_options(mysqli $con): array
{
    if (um_table_exists($con, 'jos_usergroups')) {
        $legacy = um_options($con, "SELECT id,title AS name,1 AS status FROM jos_usergroups WHERE LOWER(title) NOT IN ('public','guest','registered','author','editor','publisher','manager','administrator','super users') ORDER BY id ASC");
        $roles = um_options($con, 'SELECT id,name,status FROM jos_admin_roles ORDER BY orderby ASC,id ASC');
        $seen = [];
        $maxOrder = 0;
        foreach ($roles as $row) {
            $seen[strtolower(trim((string)$row['name']))] = true;
            $maxOrder = max($maxOrder, (int)$row['id']);
        }
        foreach ($legacy as $row) {
            $name = trim((string)$row['name']);
            $key = strtolower($name);
            if ($name !== '' && !isset($seen[$key])) {
                ++$maxOrder;
                $status = 1;
                $stmt = um_stmt($con, 'INSERT INTO jos_admin_roles (name, status, orderby) VALUES (?, ?, ?)');
                $stmt->bind_param('sii', $name, $status, $maxOrder);
                $stmt->execute();
                $stmt->close();
                $seen[$key] = true;
            }
        }
    }
    return um_options($con, 'SELECT id,name,status FROM jos_admin_roles WHERE status=1 ORDER BY orderby ASC,id ASC');
}

function um_csv_ids($value): array
{
    if ($value === null || trim((string)$value) === '' || trim((string)$value) === '0') {
        return [];
    }
    $ids = array_map('intval', explode(',', (string)$value));
    return array_values(array_unique(array_filter($ids, static fn($id) => $id !== 0)));
}

function um_clean_ids(array $values, array $allowedIds): array
{
    $allowed = array_flip(array_map('intval', $allowedIds));
    $ids = [];
    foreach ($values as $value) {
        $id = (int)$value;
        if ($id !== 0 && isset($allowed[$id])) {
            $ids[] = $id;
        }
    }
    return array_values(array_unique($ids));
}

function um_access_value(string $mode, array $posted, array $allowedIds): string
{
    if ($mode === 'all') {
        return '0';
    }
    $ids = um_clean_ids($posted, $allowedIds);
    return $ids ? implode(',', $ids) : '';
}

function um_option_map(array $rows, string $labelKey): array
{
    $map = [];
    foreach ($rows as $row) {
        $map[(int)$row['id']] = (string)($row[$labelKey] ?? '');
    }
    return $map;
}

function um_names($csv, array $map, string $allLabel = 'All'): string
{
    $raw = trim((string)$csv);
    if ($raw === '0') {
        return $allLabel;
    }
    $names = [];
    foreach (um_csv_ids($csv) as $id) {
        $names[] = $map[$id] ?? ('#' . $id);
    }
    return $names ? implode(', ', $names) : '-';
}

function um_text(array $row, string $key, string $default = ''): string
{
    return array_key_exists($key, $row) && $row[$key] !== null ? (string)$row[$key] : $default;
}

function um_int(array $row, string $key, int $default = 0): int
{
    return array_key_exists($key, $row) && $row[$key] !== null ? (int)$row[$key] : $default;
}

function um_date(array $row, string $key): string
{
    $value = trim(um_text($row, $key));
    if ($value === '') {
        return '-';
    }
    $time = strtotime($value);
    return $time ? date('d-m-Y', $time) : $value;
}

function um_role_enum(string $roleName, int $roleId): string
{
    $name = strtolower(trim($roleName));
    if ($roleId === 1 || str_contains($name, 'super')) {
        return 'Super Admin';
    }
    if (str_contains($name, 'manager')) {
        return 'manager';
    }
    if (str_contains($name, 'viewer') || str_contains($name, 'view')) {
        return 'viewer';
    }
    return 'admin';
}

function um_user_exists(mysqli $con, int $id): bool
{
    if ($id <= 0) {
        return false;
    }
    $stmt = um_stmt($con, 'SELECT id FROM jos_admin_users WHERE id=? LIMIT 1');
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $exists = (bool)$stmt->get_result()->fetch_assoc();
    $stmt->close();
    return $exists;
}

function um_fetch_user(mysqli $con, int $id): ?array
{
    $stmt = um_stmt($con, 'SELECT * FROM jos_admin_users WHERE id=? LIMIT 1');
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc() ?: null;
    $stmt->close();
    return $row;
}

function um_username_exists(mysqli $con, string $username, int $excludeId = 0): bool
{
    if ($excludeId > 0) {
        $stmt = um_stmt($con, 'SELECT id FROM jos_admin_users WHERE username=? AND id<>? LIMIT 1');
        $stmt->bind_param('si', $username, $excludeId);
    } else {
        $stmt = um_stmt($con, 'SELECT id FROM jos_admin_users WHERE username=? LIMIT 1');
        $stmt->bind_param('s', $username);
    }
    $stmt->execute();
    $exists = (bool)$stmt->get_result()->fetch_assoc();
    $stmt->close();
    return $exists;
}

function um_active_super_admin_count(mysqli $con): int
{
    $stmt = um_stmt($con, 'SELECT COUNT(*) AS total FROM jos_admin_users WHERE role_id=1 AND status=1');
    $stmt->execute();
    $count = (int)($stmt->get_result()->fetch_assoc()['total'] ?? 0);
    $stmt->close();
    return $count;
}

function um_save_user(mysqli $con, int $id, array $data, ?string $passwordHash): int
{
    if ($id > 0) {
        if ($passwordHash !== null) {
            $stmt = um_stmt($con, 'UPDATE jos_admin_users SET name=?, username=?, email=?, mobile_no=?, gid=?, role=?, role_id=?, status=?, password_hash=?, payroll_access=?, additional_payroll_access=?, branch_access=?, terminal_access=?, subbranch_access=?, department_access=?, report_filter_access=?, payscale_access=?, attendance_editlog_user_access=?, identified_img_status=?, updated_at=NOW() WHERE id=?');
            $stmt->bind_param('ssssisiissssssssssii', $data['name'], $data['username'], $data['email'], $data['mobile_no'], $data['role_id'], $data['role'], $data['role_id'], $data['status'], $passwordHash, $data['payroll_access'], $data['additional_payroll_access'], $data['branch_access'], $data['terminal_access'], $data['subbranch_access'], $data['department_access'], $data['report_filter_access'], $data['payscale_access'], $data['attendance_editlog_user_access'], $data['identified_img_status'], $id);
        } else {
            $stmt = um_stmt($con, 'UPDATE jos_admin_users SET name=?, username=?, email=?, mobile_no=?, gid=?, role=?, role_id=?, status=?, payroll_access=?, additional_payroll_access=?, branch_access=?, terminal_access=?, subbranch_access=?, department_access=?, report_filter_access=?, payscale_access=?, attendance_editlog_user_access=?, identified_img_status=?, updated_at=NOW() WHERE id=?');
            $stmt->bind_param('ssssisiisssssssssii', $data['name'], $data['username'], $data['email'], $data['mobile_no'], $data['role_id'], $data['role'], $data['role_id'], $data['status'], $data['payroll_access'], $data['additional_payroll_access'], $data['branch_access'], $data['terminal_access'], $data['subbranch_access'], $data['department_access'], $data['report_filter_access'], $data['payscale_access'], $data['attendance_editlog_user_access'], $data['identified_img_status'], $id);
        }
        if (!$stmt->execute()) {
            throw new RuntimeException('Unable to update user.');
        }
        $stmt->close();
        return $id;
    }

    $stmt = um_stmt($con, 'INSERT INTO jos_admin_users (name, username, email, mobile_no, gid, role, role_id, status, password_hash, payroll_access, additional_payroll_access, branch_access, terminal_access, subbranch_access, department_access, report_filter_access, payscale_access, attendance_editlog_user_access, identified_img_status, force_password_change) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0)');
    $stmt->bind_param('ssssisiissssssssssi', $data['name'], $data['username'], $data['email'], $data['mobile_no'], $data['role_id'], $data['role'], $data['role_id'], $data['status'], $passwordHash, $data['payroll_access'], $data['additional_payroll_access'], $data['branch_access'], $data['terminal_access'], $data['subbranch_access'], $data['department_access'], $data['report_filter_access'], $data['payscale_access'], $data['attendance_editlog_user_access'], $data['identified_img_status']);
    if (!$stmt->execute()) {
        throw new RuntimeException('Unable to add user.');
    }
    $savedId = (int)$con->insert_id;
    $stmt->close();
    return $savedId;
}

function um_update_status(mysqli $con, int $id, int $status): void
{
    $stmt = um_stmt($con, 'UPDATE jos_admin_users SET status=?, updated_at=NOW() WHERE id=?');
    $stmt->bind_param('ii', $status, $id);
    if (!$stmt->execute()) {
        throw new RuntimeException('Unable to update user status.');
    }
    $stmt->close();
}

function um_fetch_admin_rows(mysqli $con, string $filterQ, int $filterRole, int $filterStatus): array
{
    $where = ['1=1'];
    $types = '';
    $params = [];
    if ($filterQ !== '') {
        $where[] = '(u.name LIKE ? OR u.username LIKE ? OR u.email LIKE ?)';
        $types .= 'sss';
        $like = '%' . $filterQ . '%';
        $params[] = $like;
        $params[] = $like;
        $params[] = $like;
    }
    if ($filterRole > 0) {
        $where[] = 'u.role_id=?';
        $types .= 'i';
        $params[] = $filterRole;
    }
    if ($filterStatus === 0 || $filterStatus === 1) {
        $where[] = 'u.status=?';
        $types .= 'i';
        $params[] = $filterStatus;
    }
    $stmt = um_stmt($con, 'SELECT u.*,r.name AS role_name,0 AS is_legacy FROM jos_admin_users u LEFT JOIN jos_admin_roles r ON r.id=u.role_id WHERE ' . implode(' AND ', $where));
    if ($types !== '') {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $rows = [];
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        $row['sort_date'] = um_text($row, 'created_at');
        $rows[] = $row;
    }
    $stmt->close();
    return $rows;
}

function um_fetch_legacy_rows(mysqli $con, string $filterQ, int $filterRole, int $filterStatus, array $roleMap): array
{
    if (!um_table_exists($con, 'jos_users') || !um_table_exists($con, 'jos_user_usergroup_map') || !um_table_exists($con, 'jos_usergroups')) {
        return [];
    }
    $where = ["NOT EXISTS (SELECT 1 FROM jos_admin_users au WHERE au.username=u.username)"];
    $types = '';
    $params = [];
    if ($filterQ !== '') {
        $where[] = '(u.name LIKE ? OR u.username LIKE ? OR u.email LIKE ?)';
        $types .= 'sss';
        $like = '%' . $filterQ . '%';
        $params[] = $like;
        $params[] = $like;
        $params[] = $like;
    }
    if ($filterRole > 0) {
        $roleName = trim($roleMap[$filterRole] ?? '');
        if ($roleName === '') {
            return [];
        }
        $where[] = 'g.title=?';
        $types .= 's';
        $params[] = $roleName;
    }
    if ($filterStatus === 0 || $filterStatus === 1) {
        $where[] = 'IF(COALESCE(u.block,0)=0,1,0)=?';
        $types .= 'i';
        $params[] = $filterStatus;
    }
    $sql = "SELECT u.id,u.name,u.username,u.email,u.registerDate AS created_at,COALESCE(NULLIF(GROUP_CONCAT(DISTINCT g.title ORDER BY g.id SEPARATOR ', '),''),'-') AS role_name,IF(COALESCE(u.block,0)=0,1,0) AS status,1 AS is_legacy,'' AS payroll_access,'' AS additional_payroll_access,'' AS branch_access,'' AS terminal_access,'' AS subbranch_access,'' AS department_access,'' AS report_filter_access,'' AS payscale_access,'' AS attendance_editlog_user_access,0 AS identified_img_status FROM jos_users u LEFT JOIN jos_user_usergroup_map ug ON ug.user_id=u.id LEFT JOIN jos_usergroups g ON g.id=ug.group_id WHERE " . implode(' AND ', $where) . ' GROUP BY u.id,u.name,u.username,u.email,u.registerDate,u.block';
    $stmt = um_stmt($con, $sql);
    if ($types !== '') {
        $stmt->bind_param($types, ...$params);
    }
    $stmt->execute();
    $rows = [];
    $result = $stmt->get_result();
    while ($row = $result->fetch_assoc()) {
        $row['sort_date'] = um_text($row, 'created_at');
        $rows[] = $row;
    }
    $stmt->close();
    return $rows;
}

function um_fetch_legacy_user(mysqli $con, int $id): ?array
{
    if ($id <= 0 || !um_table_exists($con, 'jos_users') || !um_table_exists($con, 'jos_user_usergroup_map') || !um_table_exists($con, 'jos_usergroups')) {
        return null;
    }
    $stmt = um_stmt($con, "SELECT u.id,u.name,u.username,u.email,u.registerDate AS created_at,IF(COALESCE(u.block,0)=0,1,0) AS status,GROUP_CONCAT(DISTINCT g.title ORDER BY g.id SEPARATOR ', ') AS role_name FROM jos_users u LEFT JOIN jos_user_usergroup_map ug ON ug.user_id=u.id LEFT JOIN jos_usergroups g ON g.id=ug.group_id WHERE u.id=? GROUP BY u.id,u.name,u.username,u.email,u.registerDate,u.block LIMIT 1");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc() ?: null;
    $stmt->close();
    return $row;
}

function um_role_id_from_legacy_groups(string $groups, array $roleMap): int
{
    $lookup = [];
    foreach ($roleMap as $id => $name) {
        $lookup[strtolower(trim((string)$name))] = (int)$id;
    }
    foreach (array_map('trim', explode(',', $groups)) as $group) {
        $key = strtolower($group);
        if ($key !== '' && isset($lookup[$key])) {
            return $lookup[$key];
        }
    }
    return 0;
}

function um_update_legacy_status(mysqli $con, int $id, int $status): void
{
    $block = $status === 1 ? 0 : 1;
    $stmt = um_stmt($con, 'UPDATE jos_users SET block=? WHERE id=?');
    $stmt->bind_param('ii', $block, $id);
    if (!$stmt->execute()) {
        throw new RuntimeException('Unable to update old user status.');
    }
    $stmt->close();
}

function um_delete_legacy_user(mysqli $con, int $id): void
{
    $con->begin_transaction();
    try {
        if (um_table_exists($con, 'jos_user_usergroup_map')) {
            $stmt = um_stmt($con, 'DELETE FROM jos_user_usergroup_map WHERE user_id=?');
            $stmt->bind_param('i', $id);
            $stmt->execute();
            $stmt->close();
        }
        $stmt = um_stmt($con, 'DELETE FROM jos_users WHERE id=?');
        $stmt->bind_param('i', $id);
        if (!$stmt->execute()) {
            throw new RuntimeException('Unable to delete old user.');
        }
        $stmt->close();
        $con->commit();
    } catch (Throwable $e) {
        $con->rollback();
        throw $e;
    }
}

function um_picker_options(array $rows, string $labelKey): array
{
    $options = [];
    foreach ($rows as $row) {
        $options[] = ['id' => (int)$row['id'], 'name' => (string)$row[$labelKey]];
    }
    return $options;
}

function um_picker(string $label, string $modeName, string $fieldName, array $options, $storedValue, string $placeholder, bool $allowAll = true): void
{
    $stored = trim((string)$storedValue);
    $mode = $stored === '0' ? 'all' : 'select';
    $selected = um_csv_ids($stored);
    ?>
    <div class="space-y-2">
      <div class="flex flex-wrap items-center justify-between gap-2">
        <label class="text-sm font-semibold text-slate-700"><?= h($label) ?></label>
        <?php if ($allowAll): ?>
          <select name="<?= h($modeName) ?>" class="rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-xs font-bold text-slate-600">
            <option value="all" <?= $mode === 'all' ? 'selected' : '' ?>>All</option>
            <option value="select" <?= $mode === 'select' ? 'selected' : '' ?>>Select</option>
          </select>
        <?php endif; ?>
      </div>
      <div class="relative js-user-picker" data-name="<?= h($fieldName) ?>[]" data-placeholder="<?= h($placeholder) ?>" data-heading="-Select Option-" data-options='<?= h(json_encode($options, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) ?>' data-selected='<?= h(json_encode($selected)) ?>'>
        <div class="js-picker-control min-h-[46px] w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-800 outline-none focus-within:border-brand-500 focus-within:ring-2 focus-within:ring-brand-100">
          <div class="js-picker-tags mb-1 flex flex-wrap gap-1.5"></div>
          <input type="text" class="js-picker-search w-full border-0 bg-transparent p-0 text-sm font-medium text-slate-800 outline-none placeholder:text-slate-400" placeholder="<?= h($placeholder) ?>" autocomplete="off">
        </div>
        <div class="js-picker-dropdown hidden absolute left-0 right-0 top-full z-40 max-h-72 overflow-y-auto rounded-b-xl border border-slate-200 bg-white shadow-xl"></div>
        <div class="js-picker-inputs"></div>
      </div>
    </div>
    <?php
}

$currentUser = current_user() ?: [];
$currentUserId = (int)($currentUser['id'] ?? 0);
$isSuperAdmin = (int)($currentUser['role_id'] ?? 0) === 1;
$missingAccessColumns = um_missing_columns($con, 'jos_admin_users', um_required_access_columns());
if ($missingAccessColumns) {
    $errors[] = 'User Manager setup is incomplete. Run settings/user-manager-setup.php once as Super Admin.';
}

$roles = um_user_group_options($con);
$roleMap = um_option_map($roles, 'name');
$roleIds = array_map(static fn($row) => (int)$row['id'], $roles);
$payrollLocations = um_options($con, 'SELECT id,name FROM jos_app_payrolllocation WHERE status=1 ORDER BY name ASC,id ASC');
$additionalPayrollLocations = um_options($con, 'SELECT id,name FROM jos_app_payrolllocation WHERE status=2 ORDER BY name ASC,id ASC');
$branchLocations = um_options($con, 'SELECT id,name FROM jos_app_orglocation ORDER BY name ASC,id ASC');
$subBranches = um_options($con, 'SELECT id,subbranch FROM jos_app_subbranch ORDER BY subbranch ASC,id ASC');
$departments = um_options($con, 'SELECT id,department FROM jos_app_department ORDER BY department ASC,id ASC');
$reportFilters = um_options($con, 'SELECT id,name FROM jos_app_report_filters WHERE status=1 ORDER BY orderby ASC,id ASC');
$attendanceUsers = um_options($con, 'SELECT id,name,username FROM jos_admin_users WHERE status=1 ORDER BY name ASC,id ASC');

$payrollMap = um_option_map($payrollLocations, 'name');
$additionalPayrollMap = um_option_map($additionalPayrollLocations, 'name');
$branchMap = um_option_map($branchLocations, 'name');
$subBranchMap = um_option_map($subBranches, 'subbranch');
$departmentMap = um_option_map($departments, 'department');
$reportFilterMap = um_option_map($reportFilters, 'name');
$attendanceUserMap = [];
foreach ($attendanceUsers as $row) {
    $attendanceUserMap[(int)$row['id']] = trim((string)$row['name']) . ' (' . trim((string)$row['username']) . ')';
}
$scaleRows = [
    ['id' => 1, 'name' => 'Verify'],
    ['id' => 2, 'name' => 'Approve'],
    ['id' => -1, 'name' => 'Unlock'],
];
$scaleMap = [1 => 'Verify', 2 => 'Approve', -1 => 'Unlock'];

$mode = (string)($_GET['mode'] ?? '');
$isForm = $mode === 'add';
$editId = isset($_GET['edit']) ? max(0, (int)$_GET['edit']) : 0;
$legacyId = isset($_GET['legacy_id']) ? max(0, (int)$_GET['legacy_id']) : 0;
$editRow = [
    'id' => 0,
    'name' => '',
    'username' => '',
    'email' => '',
    'mobile_no' => '',
    'role_id' => 0,
    'status' => 1,
    'payroll_access' => '0',
    'additional_payroll_access' => '',
    'branch_access' => '0',
    'terminal_access' => '0',
    'subbranch_access' => '',
    'department_access' => '0',
    'report_filter_access' => '',
    'payscale_access' => '',
    'attendance_editlog_user_access' => '',
    'identified_img_status' => 0,
];

if ($isForm && empty($acl['can_add'])) {
    http_response_code(403);
    exit('Access denied.');
}

if ($isForm && $legacyId > 0) {
    $legacyRow = um_fetch_legacy_user($con, $legacyId);
    if ($legacyRow) {
        $editRow['name'] = um_text($legacyRow, 'name');
        $editRow['username'] = um_text($legacyRow, 'username');
        $editRow['email'] = um_text($legacyRow, 'email');
        $editRow['role_id'] = um_role_id_from_legacy_groups(um_text($legacyRow, 'role_name'), $roleMap);
        $editRow['status'] = um_int($legacyRow, 'status', 1);
    } else {
        $_SESSION['flash_user_manager'] = 'User was not found.';
        redirect('/settings/user-manager.php');
    }
}

if ($editId > 0) {
    if (empty($acl['can_edit'])) {
        http_response_code(403);
        exit('Access denied.');
    }
    $isForm = true;
    $editRow = um_fetch_user($con, $editId) ?: [];
    if (!$editRow) {
        $_SESSION['flash_user_manager'] = 'User was not found.';
        redirect('/settings/user-manager.php');
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = (string)($_POST['action'] ?? '');
    if (!verify_csrf($_POST['_csrf'] ?? null)) {
        $errors[] = 'Security token expired. Please refresh and try again.';
    } elseif ($action === 'save') {
        if ($missingAccessColumns) {
            $errors[] = 'User Manager setup must be completed before saving users.';
        }
        $id = max(0, (int)($_POST['id'] ?? 0));
        if ($id > 0 && empty($acl['can_edit'])) {
            $errors[] = 'You do not have permission to edit users.';
        }
        if ($id === 0 && empty($acl['can_add'])) {
            $errors[] = 'You do not have permission to add users.';
        }
        if ($id > 0 && !um_user_exists($con, $id)) {
            $errors[] = 'User was not found.';
        }

        $existing = $id > 0 ? um_fetch_user($con, $id) : null;
        $name = trim((string)($_POST['name'] ?? ''));
        $username = trim((string)($_POST['username'] ?? ''));
        $email = $existing ? um_text($existing, 'email') : '';
        $mobile = $existing ? um_text($existing, 'mobile_no') : '';
        $roleId = (int)($_POST['role_id'] ?? 0);
        $status = (int)($_POST['status'] ?? 1) === 1 ? 1 : 0;
        $password = (string)($_POST['password'] ?? '');
        $password2 = (string)($_POST['password2'] ?? '');

        if ($name === '') {
            $errors[] = 'Name is required.';
        } elseif (strlen($name) > 120) {
            $errors[] = 'Name must be 120 characters or fewer.';
        }
        if ($username === '') {
            $errors[] = 'Username is required.';
        } elseif (!preg_match('/^[A-Za-z0-9._@-]{3,120}$/', $username)) {
            $errors[] = 'Username must be 3-120 characters and use only letters, numbers, dot, underscore, hyphen, or @.';
        } elseif (um_username_exists($con, $username, $id)) {
            $errors[] = 'Username already exists.';
        }
        if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $errors[] = 'Enter a valid email address.';
        }
        if ($mobile !== '' && !preg_match('/^[0-9+\-\s]{6,20}$/', $mobile)) {
            $errors[] = 'Enter a valid mobile number.';
        }
        if (!in_array($roleId, $roleIds, true)) {
            $errors[] = 'Select a valid user group.';
        }
        if (!$isSuperAdmin && ($roleId === 1 || ($existing && (int)$existing['role_id'] === 1))) {
            $errors[] = 'Only Super Admin can manage Super Admin users.';
        }
        if ($id === 0 && $password === '') {
            $errors[] = 'Password is required for new users.';
        }
        if ($password !== '' || $password2 !== '') {
            if (strlen($password) < 8) {
                $errors[] = 'Password must be at least 8 characters.';
            }
            if ($password !== $password2) {
                $errors[] = 'Password and confirm password must match.';
            }
        }
        if ($id > 0 && $id === $currentUserId && $status === 0) {
            $errors[] = 'You cannot deactivate your own account.';
        }
        if ($id > 0 && $status === 0 && $existing && (int)$existing['role_id'] === 1 && um_active_super_admin_count($con) <= 1) {
            $errors[] = 'At least one active Super Admin must remain.';
        }

        $data = [
            'name' => $name,
            'username' => $username,
            'email' => $email,
            'mobile_no' => $mobile,
            'role_id' => $roleId,
            'role' => um_role_enum($roleMap[$roleId] ?? '', $roleId),
            'status' => $status,
            'payroll_access' => um_access_value((string)($_POST['payroll_mode'] ?? 'all'), (array)($_POST['payroll_access'] ?? []), array_keys($payrollMap)),
            'additional_payroll_access' => um_access_value((string)($_POST['additional_payroll_mode'] ?? 'select'), (array)($_POST['additional_payroll_access'] ?? []), array_keys($additionalPayrollMap)),
            'branch_access' => um_access_value((string)($_POST['branch_mode'] ?? 'all'), (array)($_POST['branch_access'] ?? []), array_keys($branchMap)),
            'terminal_access' => um_access_value((string)($_POST['terminal_mode'] ?? 'all'), (array)($_POST['terminal_access'] ?? []), array_keys($branchMap)),
            'subbranch_access' => um_access_value((string)($_POST['subbranch_mode'] ?? 'select'), (array)($_POST['subbranch_access'] ?? []), array_keys($subBranchMap)),
            'department_access' => um_access_value((string)($_POST['department_mode'] ?? 'all'), (array)($_POST['department_access'] ?? []), array_keys($departmentMap)),
            'report_filter_access' => um_access_value((string)($_POST['report_filter_mode'] ?? 'select'), (array)($_POST['report_filter_access'] ?? []), array_keys($reportFilterMap)),
            'payscale_access' => implode(',', um_clean_ids((array)($_POST['payscale_access'] ?? []), array_keys($scaleMap))),
            'attendance_editlog_user_access' => um_access_value((string)($_POST['attendance_editlog_mode'] ?? 'select'), (array)($_POST['attendance_editlog_user_access'] ?? []), array_keys($attendanceUserMap)),
            'identified_img_status' => (int)($_POST['identified_img_status'] ?? 0) === 1 ? 1 : 0,
        ];

        $passwordHash = $password !== '' ? password_hash($password, PASSWORD_DEFAULT) : null;

        if (!$errors) {
            try {
                $savedId = um_save_user($con, $id, $data, $passwordHash);
                audit_log($id > 0 ? 'admin_user.update' : 'admin_user.create', 'jos_admin_users', (string)$savedId, $username);
                $_SESSION['flash_user_manager'] = $id > 0 ? 'User updated successfully.' : 'User added successfully.';
                redirect('/settings/user-manager.php');
            } catch (Throwable $e) {
                $errors[] = 'Unable to save the user. No changes were committed.';
            }
        }
        $isForm = true;
        $editRow = $data + ['id' => $id];
    } elseif ($action === 'status') {
        $id = max(0, (int)($_POST['id'] ?? 0));
        $targetStatus = (int)($_POST['status'] ?? 0) === 1 ? 1 : 0;
        $target = $id > 0 ? um_fetch_user($con, $id) : null;
        if (empty($acl['can_delete'])) {
            $errors[] = 'You do not have permission to activate or deactivate users.';
        } elseif (!$target) {
            $errors[] = 'User was not found.';
        } elseif ($id === $currentUserId && $targetStatus === 0) {
            $errors[] = 'You cannot deactivate your own account.';
        } elseif (!$isSuperAdmin && (int)$target['role_id'] === 1) {
            $errors[] = 'Only Super Admin can manage Super Admin users.';
        } elseif ($targetStatus === 0 && (int)$target['role_id'] === 1 && um_active_super_admin_count($con) <= 1) {
            $errors[] = 'At least one active Super Admin must remain.';
        } else {
            try {
                um_update_status($con, $id, $targetStatus);
                audit_log($targetStatus === 1 ? 'admin_user.activate' : 'admin_user.deactivate', 'jos_admin_users', (string)$id, (string)$target['username']);
                $_SESSION['flash_user_manager'] = $targetStatus === 1 ? 'User activated successfully.' : 'User deactivated successfully.';
                redirect('/settings/user-manager.php');
            } catch (Throwable $e) {
                $errors[] = 'Unable to update the user status.';
            }
        }
    } elseif ($action === 'legacy_status') {
        $id = max(0, (int)($_POST['id'] ?? 0));
        $targetStatus = (int)($_POST['status'] ?? 0) === 1 ? 1 : 0;
        $target = um_fetch_legacy_user($con, $id);
        if (empty($acl['can_delete'])) {
            $errors[] = 'You do not have permission to activate or deactivate users.';
        } elseif (!$target) {
            $errors[] = 'User was not found.';
        } else {
            try {
                um_update_legacy_status($con, $id, $targetStatus);
                audit_log($targetStatus === 1 ? 'legacy_user.activate' : 'legacy_user.deactivate', 'jos_users', (string)$id, (string)$target['username']);
                $_SESSION['flash_user_manager'] = $targetStatus === 1 ? 'User activated successfully.' : 'User deactivated successfully.';
                redirect('/settings/user-manager.php');
            } catch (Throwable $e) {
                $errors[] = 'Unable to update the user status.';
            }
        }
    } elseif ($action === 'legacy_delete') {
        $id = max(0, (int)($_POST['id'] ?? 0));
        $target = um_fetch_legacy_user($con, $id);
        if (empty($acl['can_delete'])) {
            $errors[] = 'You do not have permission to delete users.';
        } elseif (!$target) {
            $errors[] = 'User was not found.';
        } else {
            try {
                um_delete_legacy_user($con, $id);
                audit_log('legacy_user.delete', 'jos_users', (string)$id, (string)$target['username']);
                $_SESSION['flash_user_manager'] = 'User deleted successfully.';
                redirect('/settings/user-manager.php');
            } catch (Throwable $e) {
                $errors[] = 'Unable to delete the user.';
            }
        }
    }
}

$filterQ = trim((string)($_GET['q'] ?? ''));
$filterRole = isset($_GET['role_id']) && $_GET['role_id'] !== '' ? (int)$_GET['role_id'] : 0;
$filterStatus = isset($_GET['status']) && $_GET['status'] !== '' ? (int)$_GET['status'] : -1;
$page = max(1, (int)($_GET['page'] ?? 1));
$perPage = 20;
$rows = [];
$totalRows = 0;
$pages = 1;

if (!$isForm) {
    $allRows = array_merge(
        um_fetch_admin_rows($con, $filterQ, $filterRole, $filterStatus),
        um_fetch_legacy_rows($con, $filterQ, $filterRole, $filterStatus, $roleMap)
    );
    usort($allRows, static function (array $a, array $b): int {
        $ad = strtotime((string)($a['sort_date'] ?? '')) ?: 0;
        $bd = strtotime((string)($b['sort_date'] ?? '')) ?: 0;
        if ($bd === $ad) {
            return (int)($b['id'] ?? 0) <=> (int)($a['id'] ?? 0);
        }
        return $bd <=> $ad;
    });
    $totalRows = count($allRows);
    $pages = max(1, (int)ceil($totalRows / $perPage));
    $page = min($page, $pages);
    $offset = ($page - 1) * $perPage;
    $rows = array_slice($allRows, $offset, $perPage);
}

$value = static function (string $key, $default = '') use (&$editRow) {
    return $editRow[$key] ?? $default;
};
$input = 'mt-1 w-full rounded-lg border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-800 outline-none focus:border-brand-500 focus:ring-2 focus:ring-brand-100';
$filterInput = 'rounded-xl border border-slate-200 px-3 py-2.5 text-sm';

console_header('User Manager', $pageLink);
?>
<div class="mb-4 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
  <div>
    <div class="mb-2 flex items-center gap-2 text-xs font-semibold text-slate-500"><a href="/dashboard.php">Dashboard</a><i class="fa-solid fa-chevron-right text-[9px]"></i><span>D. Masters</span><i class="fa-solid fa-chevron-right text-[9px]"></i><span class="text-brand-600">User Manager</span></div>
    <h1 class="text-2xl font-bold text-slate-900">User Manager</h1>
    <p class="mt-1 text-sm text-slate-500">Manage user registration, group access, payroll locations, branch access, and report permissions.</p>
  </div>
</div>
<?php if ($flash): ?><div class="mb-5 rounded-xl border border-emerald-100 bg-emerald-50 px-5 py-4 text-sm font-semibold text-emerald-700"><i class="fa-solid fa-circle-check mr-2"></i><?= h($flash) ?></div><?php endif; ?>
<?php if ($errors): ?><div class="mb-5 rounded-xl border border-red-100 bg-red-50 px-5 py-4 text-sm font-semibold text-red-700"><div class="font-bold">Please fix the following</div><ul class="mt-2 list-inside list-disc"><?php foreach ($errors as $error): ?><li><?= h($error) ?></li><?php endforeach; ?></ul></div><?php endif; ?>

<?php if ($isForm): ?>
<form method="post" class="space-y-4">
  <input type="hidden" name="_csrf" value="<?= h(csrf_token()) ?>"><input type="hidden" name="action" value="save"><input type="hidden" name="id" value="<?= (int)$value('id', 0) ?>">
  <section class="rounded-2xl border border-slate-100 bg-white p-4 shadow-sm">
    <div class="mb-4 flex flex-wrap items-center justify-between gap-3"><div class="flex items-center gap-3"><span class="flex h-9 w-9 items-center justify-center rounded-lg bg-brand-50 text-brand-600"><i class="fa-solid fa-user-shield"></i></span><div><h2 class="font-bold text-slate-800"><?= (int)$value('id', 0) > 0 ? 'Edit User Registration' : 'User Registration' ?></h2><p class="text-xs text-slate-400">Fields marked with * are required.</p></div></div><a href="/settings/user-manager.php" class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-bold text-slate-600 hover:bg-slate-50"><i class="fa-solid fa-arrow-left mr-2"></i>Back to List</a></div>
    <div class="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
      <label class="text-sm font-semibold text-slate-700">User Group: *<select name="role_id" required class="<?= $input ?>"><option value="">Select</option><?php foreach ($roles as $role): ?><option value="<?= (int)$role['id'] ?>" <?= (int)$value('role_id') === (int)$role['id'] ? 'selected' : '' ?>><?= h((string)$role['name']) ?></option><?php endforeach; ?></select></label>
      <label class="text-sm font-semibold text-slate-700">Name *<input name="name" maxlength="120" required value="<?= h((string)$value('name')) ?>" class="<?= $input ?>" placeholder="User full name"></label>
      <label class="text-sm font-semibold text-slate-700">User Name *<input name="username" maxlength="120" required value="<?= h((string)$value('username')) ?>" class="<?= $input ?>" placeholder="Username"></label>
      <label class="text-sm font-semibold text-slate-700">Activate Status<select name="status" class="<?= $input ?>"><option value="1" <?= (int)$value('status', 1) === 1 ? 'selected' : '' ?>>Active</option><option value="0" <?= (int)$value('status', 1) === 0 ? 'selected' : '' ?>>Inactive</option></select></label>
      <label class="text-sm font-semibold text-slate-700">Password <?= (int)$value('id', 0) > 0 ? '' : '*' ?><input type="password" name="password" <?= (int)$value('id', 0) > 0 ? '' : 'required' ?> minlength="8" class="<?= $input ?>" placeholder="<?= (int)$value('id', 0) > 0 ? 'Leave blank to keep current' : 'Minimum 8 characters' ?>"></label>
      <label class="text-sm font-semibold text-slate-700">Confirm Password <?= (int)$value('id', 0) > 0 ? '' : '*' ?><input type="password" name="password2" <?= (int)$value('id', 0) > 0 ? '' : 'required' ?> minlength="8" class="<?= $input ?>" placeholder="Re-enter password"></label>
    </div>
  </section>

  <section class="rounded-2xl border border-slate-100 bg-white p-4 shadow-sm">
    <div class="mb-4"><h2 class="font-bold text-emerald-700">Define User Access</h2><p class="mt-1 text-xs font-medium text-slate-400">Select specific values, or keep All where access should not be restricted.</p></div>
    <div class="grid gap-4 lg:grid-cols-2">
      <?php um_picker('Payroll Location :', 'payroll_mode', 'payroll_access', um_picker_options($payrollLocations, 'name'), $value('payroll_access', '0'), 'Type or select payroll location'); ?>
      <?php um_picker('Branch Location:', 'branch_mode', 'branch_access', um_picker_options($branchLocations, 'name'), $value('branch_access', '0'), 'Type or select branch'); ?>
      <?php um_picker('Terminal Location:', 'terminal_mode', 'terminal_access', um_picker_options($branchLocations, 'name'), $value('terminal_access', '0'), 'Type or select terminal'); ?>
      <?php um_picker('Department :', 'department_mode', 'department_access', um_picker_options($departments, 'department'), $value('department_access', '0'), 'Type or select department'); ?>
      <?php um_picker('Sub Branch Location :', 'subbranch_mode', 'subbranch_access', um_picker_options($subBranches, 'subbranch'), $value('subbranch_access'), 'Type or select sub branch'); ?>
      <?php um_picker('Additional Payroll Location :', 'additional_payroll_mode', 'additional_payroll_access', um_picker_options($additionalPayrollLocations, 'name'), $value('additional_payroll_access'), 'Type or select additional payroll'); ?>
      <?php um_picker('App Report Filter Type :', 'report_filter_mode', 'report_filter_access', um_picker_options($reportFilters, 'name'), $value('report_filter_access'), 'Type or select report filter'); ?>
      <?php um_picker('User Pay Scale Access :', 'payscale_mode', 'payscale_access', $scaleRows, $value('payscale_access'), 'Type or select pay scale access', false); ?>
      <?php um_picker('Attendance Edit log report show users:', 'attendance_editlog_mode', 'attendance_editlog_user_access', array_map(static fn($id, $name) => ['id' => $id, 'name' => $name], array_keys($attendanceUserMap), array_values($attendanceUserMap)), $value('attendance_editlog_user_access'), 'Type or select user'); ?>
      <div class="flex items-center gap-3 text-sm font-semibold text-slate-700">
        <span>Show Identified Images :</span>
        <label class="inline-flex items-center gap-1 font-medium"><input type="radio" name="identified_img_status" value="1" <?= (int)$value('identified_img_status') === 1 ? 'checked' : '' ?>>Yes</label>
        <label class="inline-flex items-center gap-1 font-medium"><input type="radio" name="identified_img_status" value="0" <?= (int)$value('identified_img_status') !== 1 ? 'checked' : '' ?>>No</label>
      </div>
    </div>
  </section>
  <div class="flex flex-wrap justify-end gap-2"><a href="/settings/user-manager.php" class="rounded-lg border border-slate-200 bg-white px-5 py-2.5 text-sm font-bold text-slate-600">Cancel</a><button class="rounded-lg bg-brand-600 px-5 py-2.5 text-sm font-bold text-white hover:bg-brand-700"><i class="fa-solid fa-floppy-disk mr-2"></i>Save User</button></div>
</form>
<?php else: ?>
<section class="overflow-hidden rounded-2xl border border-slate-100 bg-white shadow-sm">
  <div class="flex flex-col gap-3 border-b border-slate-100 px-5 py-4 sm:flex-row sm:items-center sm:justify-between"><div><h2 class="font-bold text-slate-800">User List</h2><p class="mt-1 text-xs font-medium text-slate-400">Users are ordered by latest registration date.</p></div><?php if (!empty($acl['can_add'])): ?><a href="?mode=add" class="inline-flex items-center justify-center gap-2 rounded-lg bg-brand-600 px-4 py-2.5 text-sm font-bold text-white shadow-sm hover:bg-brand-700"><i class="fa-solid fa-plus"></i>+ Add</a><?php endif; ?></div>
  <form method="get" class="flex flex-wrap items-end gap-3 border-b border-slate-100 p-5">
    <label class="min-w-[240px] text-sm font-semibold text-slate-700">Group<select name="role_id" class="mt-1 w-full <?= $filterInput ?>"><option value="">Select</option><?php foreach ($roles as $role): ?><option value="<?= (int)$role['id'] ?>" <?= $filterRole === (int)$role['id'] ? 'selected' : '' ?>><?= h((string)$role['name']) ?></option><?php endforeach; ?></select></label>
    <button class="rounded-xl bg-red-500 px-5 py-2.5 text-sm font-bold text-white hover:bg-red-600">GO</button>
    <a href="/settings/user-manager.php" class="rounded-xl border border-slate-200 px-5 py-2.5 text-center text-sm font-bold text-slate-600 hover:bg-slate-50">Clear</a>
  </form>
  <div class="overflow-x-auto"><table class="w-full min-w-[1900px] text-left text-sm"><thead class="bg-slate-50 text-[10px] font-extrabold uppercase tracking-wider text-slate-700"><tr><th class="px-5 py-4 w-20">Sr No</th><th class="px-5 py-4">Date</th><th class="px-5 py-4">Name</th><th class="px-5 py-4">Username</th><th class="px-5 py-4">Group</th><th class="px-5 py-4">Payroll Location</th><th class="px-5 py-4">Branch Location</th><th class="px-5 py-4">Terminal Location</th><th class="px-5 py-4">Sub Branch Location</th><th class="px-5 py-4">Department</th><th class="px-5 py-4">Additional Payroll Location</th><th class="px-5 py-4">App Report Filter Type</th><th class="px-5 py-4">Show Identified Images On Report</th><th class="px-5 py-4">Pay Scale Access</th><th class="px-5 py-4">Attendance Edit log report show users</th><th class="px-5 py-4 text-right">Actions</th></tr></thead><tbody class="divide-y divide-slate-100">
    <?php if (!$rows): ?><tr><td colspan="16" class="px-6 py-14 text-center font-semibold text-slate-400">No users found.</td></tr><?php endif; ?>
    <?php foreach ($rows as $index => $row): ?>
      <tr class="align-top hover:bg-slate-50/70">
        <td class="px-5 py-4 font-semibold text-slate-500"><?= (($page - 1) * $perPage) + $index + 1 ?></td>
        <td class="px-5 py-4 font-semibold text-slate-600"><?= h(um_date($row, 'created_at')) ?></td>
        <td class="px-5 py-4 font-bold text-slate-800"><?= h(um_text($row, 'name')) ?></td>
        <td class="px-5 py-4 font-semibold text-slate-700"><?= h(um_text($row, 'username')) ?></td>
        <td class="px-5 py-4 font-semibold text-slate-700"><?= h(um_text($row, 'role_name', um_text($row, 'role'))) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'payroll_access'), $payrollMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'branch_access'), $branchMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'terminal_access'), $branchMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'subbranch_access'), $subBranchMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'department_access'), $departmentMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'additional_payroll_access'), $additionalPayrollMap)) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'report_filter_access'), $reportFilterMap)) ?></td>
        <td class="px-5 py-4"><?= um_int($row, 'identified_img_status') === 1 ? 'Yes' : 'No' ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'payscale_access'), $scaleMap, '-')) ?></td>
        <td class="px-5 py-4"><?= h(um_names(um_text($row, 'attendance_editlog_user_access'), $attendanceUserMap)) ?></td>
        <td class="px-5 py-4">
          <div class="flex justify-end gap-2">
            <?php if (um_int($row, 'is_legacy') === 1): ?>
              <?php if (!empty($acl['can_edit'])): ?>
                <a href="?mode=add&legacy_id=<?= um_int($row, 'id') ?>" class="rounded-lg border border-slate-200 px-3 py-2 text-slate-600 hover:bg-brand-50 hover:text-brand-600" title="Edit"><i class="fa-solid fa-pen"></i></a>
              <?php endif; ?>
              <?php if (!empty($acl['can_delete'])): ?>
                <form method="post" onsubmit="return confirm('Delete this user?');">
                  <input type="hidden" name="_csrf" value="<?= h(csrf_token()) ?>">
                  <input type="hidden" name="action" value="legacy_delete">
                  <input type="hidden" name="id" value="<?= um_int($row, 'id') ?>">
                  <button class="rounded-lg border border-slate-200 px-3 py-2 text-slate-600 hover:bg-red-50 hover:text-red-600" title="Delete"><i class="fa-solid fa-trash-can"></i></button>
                </form>
                <form method="post" onsubmit="return confirm('<?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?> this user?');">
                  <input type="hidden" name="_csrf" value="<?= h(csrf_token()) ?>">
                  <input type="hidden" name="action" value="legacy_status">
                  <input type="hidden" name="id" value="<?= um_int($row, 'id') ?>">
                  <input type="hidden" name="status" value="<?= um_int($row, 'status', 1) === 1 ? 0 : 1 ?>">
                  <button class="rounded-lg px-3 py-2 text-xs font-bold text-white <?= um_int($row, 'status', 1) === 1 ? 'bg-emerald-600 hover:bg-emerald-700' : 'bg-amber-500 hover:bg-amber-600' ?>" title="<?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?>"><?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?></button>
                </form>
              <?php endif; ?>
            <?php else: ?>
              <?php if (!empty($acl['can_edit'])): ?>
                <a href="?edit=<?= um_int($row, 'id') ?>" class="rounded-lg border border-slate-200 px-3 py-2 text-slate-600 hover:bg-brand-50 hover:text-brand-600" title="Edit"><i class="fa-solid fa-pen"></i></a>
              <?php endif; ?>
              <?php if (!empty($acl['can_delete'])): ?>
                <form method="post" onsubmit="return confirm('<?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?> this user?');">
                  <input type="hidden" name="_csrf" value="<?= h(csrf_token()) ?>">
                  <input type="hidden" name="action" value="status">
                  <input type="hidden" name="id" value="<?= um_int($row, 'id') ?>">
                  <input type="hidden" name="status" value="<?= um_int($row, 'status', 1) === 1 ? 0 : 1 ?>">
                  <button class="rounded-lg px-3 py-2 text-xs font-bold text-white <?= um_int($row, 'status', 1) === 1 ? 'bg-emerald-600 hover:bg-emerald-700' : 'bg-amber-500 hover:bg-amber-600' ?>" title="<?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?>"><?= um_int($row, 'status', 1) === 1 ? 'Deactivate' : 'Activate' ?></button>
                </form>
              <?php endif; ?>
            <?php endif; ?>
          </div>
        </td>
      </tr>
    <?php endforeach; ?>
  </tbody></table></div>
  <?php if ($totalRows > $perPage): ?><div class="flex items-center justify-between border-t border-slate-100 px-5 py-4 text-sm"><span class="font-medium text-slate-500"><?= $totalRows ?> users</span><div class="flex gap-2"><?php $base = ['q' => $filterQ, 'role_id' => $filterRole ?: '', 'status' => $filterStatus >= 0 ? $filterStatus : '']; if ($page > 1): ?><a class="rounded-lg border border-slate-200 px-4 py-2 font-semibold" href="?<?= h(http_build_query($base + ['page' => $page - 1])) ?>">Previous</a><?php endif; ?><?php if ($page < $pages): ?><a class="rounded-lg border border-slate-200 px-4 py-2 font-semibold" href="?<?= h(http_build_query($base + ['page' => $page + 1])) ?>">Next</a><?php endif; ?></div></div><?php endif; ?>
</section>
<?php endif; ?>
<?php if ($isForm): ?>
<script>
document.querySelectorAll('.js-user-picker').forEach(function (picker) {
  const options = JSON.parse(picker.dataset.options || '[]');
  const fieldName = picker.dataset.name || 'items[]';
  const placeholderText = picker.dataset.placeholder || 'Type or select some options';
  const headingText = picker.dataset.heading || '-Select Option-';
  let selected = JSON.parse(picker.dataset.selected || '[]').map(Number);
  const control = picker.querySelector('.js-picker-control');
  const search = picker.querySelector('.js-picker-search');
  const tags = picker.querySelector('.js-picker-tags');
  const dropdown = picker.querySelector('.js-picker-dropdown');
  const inputs = picker.querySelector('.js-picker-inputs');
  function labelFor(id) {
    const option = options.find(function (item) { return Number(item.id) === Number(id); });
    return option ? option.name : '#' + id;
  }
  function syncInputs() {
    inputs.innerHTML = '';
    selected.forEach(function (id) {
      const input = document.createElement('input');
      input.type = 'hidden';
      input.name = fieldName;
      input.value = String(id);
      inputs.appendChild(input);
    });
  }
  function drawTags() {
    tags.innerHTML = '';
    if (!selected.length) {
      tags.classList.add('hidden');
      search.placeholder = placeholderText;
    } else {
      tags.classList.remove('hidden');
      search.placeholder = '';
    }
    selected.forEach(function (id) {
      const tag = document.createElement('span');
      tag.className = 'inline-flex items-center gap-1 rounded-md bg-brand-50 px-2 py-1 text-xs font-bold text-brand-700';
      tag.textContent = labelFor(id);
      const remove = document.createElement('button');
      remove.type = 'button';
      remove.className = 'ml-1 text-brand-500 hover:text-red-600';
      remove.innerHTML = '&times;';
      remove.addEventListener('click', function () {
        selected = selected.filter(function (value) { return Number(value) !== Number(id); });
        render();
        openDropdown();
        search.focus();
      });
      tag.appendChild(remove);
      tags.appendChild(tag);
    });
  }
  function drawOptions() {
    const term = search.value.trim().toLowerCase();
    dropdown.innerHTML = '';
    const placeholder = document.createElement('button');
    placeholder.type = 'button';
    placeholder.className = 'block w-full bg-brand-600 px-3 py-2 text-left text-sm font-semibold text-white';
    placeholder.textContent = headingText;
    placeholder.addEventListener('click', function () { search.value = ''; drawOptions(); search.focus(); });
    dropdown.appendChild(placeholder);
    const available = options.filter(function (option) {
      return !selected.includes(Number(option.id)) && (!term || option.name.toLowerCase().includes(term));
    });
    if (!available.length) {
      const empty = document.createElement('div');
      empty.className = 'px-3 py-3 text-sm font-medium text-slate-400';
      empty.textContent = 'No options found';
      dropdown.appendChild(empty);
      return;
    }
    available.forEach(function (option) {
      const item = document.createElement('button');
      item.type = 'button';
      item.className = 'block w-full px-3 py-2 text-left text-sm font-medium text-slate-700 hover:bg-brand-50 hover:text-brand-700';
      item.textContent = option.name;
      item.addEventListener('click', function () {
        selected.push(Number(option.id));
        search.value = '';
        render();
        openDropdown();
        search.focus();
      });
      dropdown.appendChild(item);
    });
  }
  function openDropdown() { drawOptions(); dropdown.classList.remove('hidden'); }
  function render() { drawTags(); syncInputs(); drawOptions(); }
  control.addEventListener('click', function () { search.focus(); openDropdown(); });
  search.addEventListener('focus', openDropdown);
  search.addEventListener('input', openDropdown);
  search.addEventListener('keydown', function (event) { if (event.key === 'Escape') dropdown.classList.add('hidden'); });
  document.addEventListener('click', function (event) { if (!picker.contains(event.target)) dropdown.classList.add('hidden'); });
  render();
});
</script>
<?php endif; ?>
<?php console_footer(); ?>
