<?php
/**
 * Report Access Control Center — modern, attractive, informative.
 *
 *   - Per-report user × action override matrix
 *   - Avatars, role pills, last-login, has-override highlighting
 *   - Live filters: search, user type, override status
 *   - Bulk actions: column-toggle, per-row Grant-all / Revoke-all
 *   - Live "X changes pending" counter on the Save button
 *   - Modern toggle switches instead of plain checkboxes
 *
 *   Resolution order remains: SysAdmin > per-report row > role default > deny
 */
require_once __DIR__ . '/../includes/config.php';
$me = require_login('internal');

$pdo = db();
$reportId = (int) ($_GET['report_id'] ?? $_POST['report_id'] ?? 0);
$action   = (string) ($_POST['action'] ?? '');

/* Helper: clean int[] from $_POST['name'] (handles array OR scalar OR missing). */
$cleanIntArr = function ($raw): array {
    if ($raw === null) return [];
    $arr = is_array($raw) ? $raw : [$raw];
    $arr = array_map('intval', $arr);
    $arr = array_filter($arr, fn($n) => $n > 0);
    return array_values(array_unique($arr));
};

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'bulk_grant') {
    csrf_check_or_die();

    $userId      = (int) ($_POST['user_id'] ?? 0);
    $clientIds   = $cleanIntArr($_POST['client_ids']  ?? []);
    $processIds  = $cleanIntArr($_POST['process_ids'] ?? []);
    $reportIds   = $cleanIntArr($_POST['report_ids']  ?? []);
    $replaceMode = !empty($_POST['replace_mode']);

    $flags = [
        'can_view'     => !empty($_POST['can_view'])     ? 1 : 0,
        'can_upload'   => !empty($_POST['can_upload'])   ? 1 : 0,
        'can_download' => !empty($_POST['can_download']) ? 1 : 0,
        'can_delete'   => !empty($_POST['can_delete'])   ? 1 : 0,
        'can_replace'  => !empty($_POST['can_replace'])  ? 1 : 0,
    ];

    $errors = [];
    if ($userId <= 0)                       $errors[] = 'Bulk grant: pick a user.';
    if (!$clientIds && !$processIds && !$reportIds) $errors[] = 'Bulk grant: pick at least one client, process, or report.';
    if (array_sum($flags) === 0 && !$replaceMode)   $errors[] = 'Bulk grant: pick at least one permission (or check "Replace existing" to clear).';

    // Resolve the union of report ids covered by any of the three pickers.
    $targetIds = [];
    if (!$errors) {
        $allReports = $pdo->query("SELECT r.id, p.client_id, r.process_id
                                    FROM reports r JOIN processes p ON p.id = r.process_id
                                    WHERE r.deleted_at IS NULL")->fetchAll();
        foreach ($allReports as $r) {
            if (in_array((int)$r['client_id'],  $clientIds,  true)) $targetIds[(int)$r['id']] = true;
            if (in_array((int)$r['process_id'], $processIds, true)) $targetIds[(int)$r['id']] = true;
            if (in_array((int)$r['id'],         $reportIds,  true)) $targetIds[(int)$r['id']] = true;
        }
        $targetIds = array_keys($targetIds);
        if (!$targetIds) $errors[] = 'Bulk grant: your selection resolved to zero reports.';
    }

    if ($errors) {
        foreach ($errors as $e) flash('error', $e);
        $_SESSION['_bulk_grant_state'] = [
            'user_id' => $userId, 'client_ids' => $clientIds, 'process_ids' => $processIds,
            'report_ids' => $reportIds, 'flags' => $flags, 'replace_mode' => $replaceMode,
        ];
        redirect('/admin/access.php?bulk=1' . ($reportId ? '&report_id=' . $reportId : ''));
    }

    $applied = 0; $wiped = 0;
    if ($replaceMode) {
        $ph = implode(',', array_fill(0, count($targetIds), '?'));
        $st = $pdo->prepare("DELETE FROM report_access WHERE user_id=? AND report_id IN ($ph)");
        $st->execute(array_merge([$userId], $targetIds));
        $wiped = $st->rowCount();
    }
    if (array_sum($flags) > 0) {
        $ins = $pdo->prepare(
            'INSERT INTO report_access
                 (report_id, user_id, can_view, can_upload, can_download, can_delete, can_replace,
                  granted_by, granted_at, created_at, updated_at)
             VALUES (?,?,?,?,?,?,?,?,NOW(),NOW(),NOW())
             ON DUPLICATE KEY UPDATE
                  can_view     = GREATEST(can_view,     VALUES(can_view)),
                  can_upload   = GREATEST(can_upload,   VALUES(can_upload)),
                  can_download = GREATEST(can_download, VALUES(can_download)),
                  can_delete   = GREATEST(can_delete,   VALUES(can_delete)),
                  can_replace  = GREATEST(can_replace,  VALUES(can_replace)),
                  granted_by   = VALUES(granted_by), updated_at = NOW()'
        );
        foreach ($targetIds as $rid) {
            $ins->execute([
                $rid, $userId,
                $flags['can_view'], $flags['can_upload'], $flags['can_download'],
                $flags['can_delete'], $flags['can_replace'], (int) $me['id'],
            ]);
            $applied++;
        }
    }

    audit_log('report.access.bulk_grant', 'user', $userId, null, [
        'reports' => count($targetIds), 'flags' => $flags, 'replace' => $replaceMode,
        'clients' => $clientIds, 'processes' => $processIds,
    ]);

    $msg = $applied
        ? "Bulk grant applied to $applied report" . ($applied===1?'':'s')
        : "Replace-only run: $wiped existing override" . ($wiped===1?'':'s') . " removed";
    if ($replaceMode && $applied) $msg .= " (existing wiped first)";
    flash('success', $msg . '.');
    unset($_SESSION['_bulk_grant_state']);
    redirect('/admin/access.php' . ($reportId ? '?report_id=' . $reportId : ''));
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    csrf_check_or_die();
    if (!$reportId) { flash('error','Pick a report first.'); redirect('/admin/access.php'); }
    $rows = (array) ($_POST['access'] ?? []);
    $changed = 0;
    foreach ($rows as $userId => $perms) {
        $userId = (int) $userId;
        $flags = [
            'can_view'     => !empty($perms['view'])     ? 1 : 0,
            'can_upload'   => !empty($perms['upload'])   ? 1 : 0,
            'can_download' => !empty($perms['download']) ? 1 : 0,
            'can_delete'   => !empty($perms['delete'])   ? 1 : 0,
            'can_replace'  => !empty($perms['replace'])  ? 1 : 0,
        ];
        $any = array_sum($flags) > 0;
        if (!$any) {
            $st = $pdo->prepare('DELETE FROM report_access WHERE report_id=? AND user_id=?');
            $st->execute([$reportId, $userId]);
            $changed += $st->rowCount();
        } else {
            $pdo->prepare(
                'INSERT INTO report_access
                 (report_id, user_id, can_view, can_upload, can_download, can_delete, can_replace,
                  granted_by, granted_at, created_at, updated_at)
                 VALUES (?,?,?,?,?,?,?,?,NOW(),NOW(),NOW())
                 ON DUPLICATE KEY UPDATE
                    can_view=VALUES(can_view), can_upload=VALUES(can_upload),
                    can_download=VALUES(can_download), can_delete=VALUES(can_delete),
                    can_replace=VALUES(can_replace),
                    granted_by=VALUES(granted_by), updated_at=NOW()'
            )->execute([
                $reportId, $userId,
                $flags['can_view'], $flags['can_upload'], $flags['can_download'],
                $flags['can_delete'], $flags['can_replace'], $me['id']
            ]);
            $changed++;
        }
    }
    audit_log('report.access.set', 'report', $reportId, null, ['count' => count($rows)]);
    flash('success', "Access updated · $changed user override" . ($changed===1?'':'s') . " applied.");
    redirect('/admin/access.php?report_id=' . $reportId);
}

$reports = $pdo->query("
    SELECT r.id, r.name, r.code, c.name AS client_name, v.name AS vertical_name, v.id AS vertical_id
    FROM reports r
    JOIN processes p ON p.id = r.process_id
    JOIN clients c ON c.id = p.client_id
    JOIN verticals v ON v.id = c.vertical_id
    WHERE r.deleted_at IS NULL
    ORDER BY v.name, c.name, r.name")->fetchAll();

// Verticals for the dependent-dropdown filter (pick a vertical → its clients/processes/reports only).
$verticals = $pdo->query("SELECT id, name FROM verticals ORDER BY name")->fetchAll();

// Current report context (only if a report is picked)
$currentReport = null;
if ($reportId) {
    foreach ($reports as $r) if ((int)$r['id'] === $reportId) { $currentReport = $r; break; }
}

$pageTitle = 'Report Access Control';
require __DIR__ . '/../includes/header.php';
?>
<style>
.rv-title-bar { padding:14px 0 10px; border-bottom: 1px solid var(--m-border); margin-bottom:14px; }

/* KPI tiles */
.ac-kpi { background: var(--m-surface); border: 1px solid var(--m-border); border-radius: 10px; padding: 12px 14px; transition: all .12s; height: 100%; }
.ac-kpi:hover { border-color: var(--m-border-strong); }
.ac-kpi .lbl { font-size:.65rem; text-transform: uppercase; letter-spacing: .05em; color: var(--m-text-soft); }
.ac-kpi .val { font-size: 1.55rem; font-weight: 700; line-height: 1.1; color: var(--m-text); margin-top: 2px; font-variant-numeric: tabular-nums; }
.ac-kpi .ico { width: 30px; height: 30px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; font-size: 1rem; }

/* Filter bar */
.ac-filters { background: var(--m-surface); border: 1px solid var(--m-border); border-radius: 10px; padding: 10px 14px; margin-bottom: 14px; }

/* Matrix table */
.ac-matrix table { font-size: .88rem; }
.ac-matrix tbody tr { transition: background .12s; }
.ac-matrix tbody tr.has-override { background: linear-gradient(90deg, rgba(34,197,94,.06) 0%, transparent 60%); }
.ac-matrix tbody tr.full-access  { background: linear-gradient(90deg, rgba(34,197,94,.12) 0%, transparent 60%); }
.ac-matrix tbody tr:hover { background: rgba(32,107,196,.05) !important; }
.ac-matrix .user-cell { display: flex; align-items: center; gap: 10px; }
.ac-matrix .user-cell .avatar {
    width: 32px; height: 32px; border-radius: 50%;
    background: linear-gradient(135deg, #38bdf8, #a855f7); color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: .72rem; flex-shrink: 0;
}
.ac-matrix .user-cell .avatar.internal { background: linear-gradient(135deg, #206bc4, #4f46e5); }
.ac-matrix .user-cell .avatar.client   { background: linear-gradient(135deg, #16a34a, #0ea5e9); }
.ac-matrix .user-cell .name { font-weight: 600; color: var(--m-text); font-size: .88rem; line-height: 1.2; }
.ac-matrix .user-cell .email { font-size: .72rem; color: var(--m-text-soft); }

.ac-pill { display: inline-block; padding: 2px 8px; border-radius: 99px; font-size: .68rem; font-weight: 600; }
.ac-pill.internal { background: rgba(32,107,196,.12); color: #1e40af; }
.ac-pill.client   { background: rgba(22,163,74,.12); color: #166534; }
html[data-bs-theme="dark"] .ac-pill.internal { background: rgba(56,189,248,.15); color: #93c5fd; }
html[data-bs-theme="dark"] .ac-pill.client   { background: rgba(34,197,94,.15); color: #86efac; }

/* Custom toggle switches */
.ac-switch { position: relative; display: inline-block; width: 36px; height: 20px; }
.ac-switch input { opacity: 0; width: 0; height: 0; }
.ac-switch .slider { position: absolute; cursor: pointer; inset: 0; background: var(--m-border-strong); border-radius: 20px; transition: .12s; }
.ac-switch .slider::before {
    content: ''; position: absolute; height: 14px; width: 14px; left: 3px; bottom: 3px;
    background: #fff; border-radius: 50%; transition: .12s;
    box-shadow: 0 1px 2px rgba(0,0,0,.2);
}
.ac-switch input:checked + .slider { background: #16a34a; }
.ac-switch input:checked + .slider::before { transform: translateX(16px); }
.ac-switch input:focus + .slider { box-shadow: 0 0 0 2px rgba(32,107,196,.25); }

/* Column header toggle-all hint */
.ac-col-toggle { font-size: .65rem; color: var(--m-text-soft); cursor: pointer; user-select: none; }
.ac-col-toggle:hover { color: var(--tblr-primary); text-decoration: underline; }

/* Row quick actions */
.ac-row-actions { white-space: nowrap; }
.ac-row-actions .btn { padding: 2px 8px; font-size: .7rem; }

/* Sticky save bar */
.ac-savebar {
    position: sticky; bottom: 0; z-index: 50;
    background: var(--m-bg-elev);
    border-top: 1px solid var(--m-border);
    padding: 10px 16px;
    margin: 0 -16px -16px;
    display: flex; align-items: center; gap: 12px;
    box-shadow: 0 -4px 12px rgba(15,23,37,.06);
}
.ac-changes-counter {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 10px; border-radius: 99px;
    font-size: .82rem; font-weight: 600;
    background: var(--m-surface-2); color: var(--m-text-soft);
    transition: all .15s;
}
.ac-changes-counter.has-changes { background: #fef3c7; color: #92400e; }
html[data-bs-theme="dark"] .ac-changes-counter.has-changes { background: #3a2f0c; color: #fde68a; }

.ac-help { background: var(--m-surface-2); border: 1px solid var(--m-border); border-radius: 10px; padding: 12px 16px; font-size: .82rem; color: var(--m-text-soft); }
.ac-help code { background: var(--m-surface); padding: 1px 6px; border-radius: 3px; font-size: .78rem; }

.ac-no-report-empty { background: var(--m-surface); border: 1px solid var(--m-border); border-radius: 12px; padding: 60px 20px; text-align: center; }
.ac-no-report-empty .icon { font-size: 3rem; opacity: .3; margin-bottom: 14px; }
</style>

<div class="container-xl">

<!-- ============= TITLE BAR ============= -->
<div class="rv-title-bar">
    <div class="row align-items-center g-3">
        <div class="col">
            <h2 class="page-title mb-0" style="font-size:1.45rem;font-weight:700"><i class="ti ti-key me-2 text-primary"></i>Report Access Control</h2>
            <div class="small text-secondary mt-1">Per-report user × action override. Falls back to role defaults when no row is set.</div>
        </div>
        <div class="col-auto">
            <button type="button" class="btn btn-outline-primary btn-sm" onclick="toggleBulkPanel()" title="Grant one user access to many reports at once">
                <i class="ti ti-stack-2 me-1"></i>Bulk grant
            </button>
        </div>
        <?php if ($currentReport): ?>
            <div class="col-auto">
                <span class="ac-pill internal" style="font-size:.78rem;padding:5px 12px">
                    <i class="ti ti-file-analytics me-1"></i><?= e($currentReport['vertical_name']) ?> › <?= e($currentReport['client_name']) ?> › <?= e($currentReport['name']) ?>
                </span>
            </div>
        <?php endif; ?>
    </div>
</div>

<?php
/* ============= BULK GRANT PANEL (collapsed by default; opens via the toolbar button) =============
   Pick a user, pick clients/processes/reports (any combination — union), pick flags, apply. */
$bgState = $_SESSION['_bulk_grant_state'] ?? [
    'user_id' => 0, 'client_ids' => [], 'process_ids' => [], 'report_ids' => [],
    'flags' => ['can_view'=>0,'can_upload'=>0,'can_download'=>0,'can_delete'=>0,'can_replace'=>0],
    'replace_mode' => false,
];
unset($_SESSION['_bulk_grant_state']);
$bgOpenByDefault = !empty($_GET['bulk']) || (int)$bgState['user_id'] > 0;

$bgUsers     = $pdo->query("SELECT id, name, email, user_type FROM users WHERE status='active' ORDER BY user_type, name")->fetchAll();
$bgClients   = $pdo->query("SELECT id, name, code, vertical_id FROM clients WHERE deleted_at IS NULL ORDER BY name")->fetchAll();
$bgProcesses = $pdo->query("SELECT p.id, p.name, p.client_id, c.name AS client_name, c.vertical_id
                             FROM processes p JOIN clients c ON c.id = p.client_id
                             WHERE p.deleted_at IS NULL ORDER BY c.name, p.name")->fetchAll();
$bgReports   = $pdo->query("SELECT r.id, r.name, r.code, r.process_id, p.client_id, c.name AS client_name, c.vertical_id
                             FROM reports r
                             JOIN processes p ON p.id = r.process_id
                             JOIN clients   c ON c.id = p.client_id
                             WHERE r.deleted_at IS NULL
                             ORDER BY c.name, r.name")->fetchAll();
?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/css/tom-select.bootstrap5.min.css">
<script src="https://cdn.jsdelivr.net/npm/tom-select@2.3.1/dist/js/tom-select.complete.min.js"></script>
<style>
.bg-panel { display: <?= $bgOpenByDefault ? 'block' : 'none' ?>; }
.bg-perms label.form-check { padding: 8px 12px; border: 1px solid var(--m-border); border-radius: 8px; margin-right: 8px; margin-bottom: 6px; cursor: pointer; min-width: 124px; transition: all .12s; }
.bg-perms label.form-check.checked { border-color: #16a34a; background: rgba(34,197,94,.07); }
.bg-perms label.form-check:hover { border-color: var(--m-border-strong); }
.bg-preview { background: var(--m-surface-2); border: 1px dashed var(--m-border-strong); border-radius: 8px; padding: 10px 12px; font-size: .85rem; }
.bg-preview strong { color: var(--tblr-primary); }
.bg-step { font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--m-text-soft); font-weight: 700; margin-bottom: 6px; }
.bg-step .num { display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background:var(--tblr-primary);color:#fff;font-size:.65rem;margin-right:4px; }
.ts-dropdown { background: var(--tblr-body-bg, #fff) !important; border: 1px solid var(--tblr-border-color, #dadfe5) !important; box-shadow: 0 6px 24px rgba(0,0,0,.12) !important; z-index: 1080 !important; font-size: .88rem; }
.ts-dropdown .option.active, .ts-dropdown .active { background: var(--tblr-primary, #206bc4) !important; color: #fff !important; }
</style>

<div class="card mb-3 bg-panel" id="bgPanel">
    <div class="card-header py-2 d-flex align-items-center">
        <h3 class="card-title small mb-0"><i class="ti ti-stack-2 me-2 text-primary"></i>Bulk Grant — one user, many reports</h3>
        <button type="button" class="btn-close ms-auto" onclick="toggleBulkPanel()" aria-label="Close"></button>
    </div>
    <form method="POST" action="<?= e(url('/admin/access.php')) ?>" class="card-body">
        <?= csrf_field() ?>
        <input type="hidden" name="action" value="bulk_grant">
        <?php if ($reportId): ?><input type="hidden" name="report_id" value="<?= (int)$reportId ?>"><?php endif; ?>

        <div class="row g-3">
            <div class="col-md-4">
                <div class="bg-step"><span class="num">1</span>Pick the user</div>
                <select name="user_id" class="form-select form-select-sm" required>
                    <option value="">— Select a user —</option>
                    <?php foreach ($bgUsers as $u): ?>
                        <option value="<?= (int)$u['id'] ?>" <?= (int)$bgState['user_id']===(int)$u['id']?'selected':'' ?>>
                            <?= e($u['name']) ?> &lt;<?= e($u['email']) ?>&gt; [<?= e($u['user_type']) ?>]
                        </option>
                    <?php endforeach; ?>
                </select>
            </div>

            <div class="col-md-8">
                <div class="bg-step"><span class="num">2</span>Pick what to include — any combination is OR-merged</div>
                <?php if ($verticals): ?>
                <div class="mb-2" style="max-width:300px">
                    <select id="bg_vertical" class="form-select form-select-sm">
                        <option value="">All verticals</option>
                        <?php foreach ($verticals as $v): ?><option value="<?= (int)$v['id'] ?>"><?= e($v['name']) ?></option><?php endforeach; ?>
                    </select>
                    <div class="form-hint">Filter the client / process / report lists below to one vertical.</div>
                </div>
                <?php endif; ?>
                <div class="row g-2">
                    <div class="col-md-4">
                        <select name="client_ids[]" id="bg_clients" multiple class="form-select form-select-sm" data-placeholder="By Client…">
                            <?php foreach ($bgClients as $c): ?>
                                <option value="<?= (int)$c['id'] ?>" <?= in_array((int)$c['id'], $bgState['client_ids'], true)?'selected':'' ?>>
                                    <?= e($c['name']) ?> (<?= e($c['code']) ?>)
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="col-md-4">
                        <select name="process_ids[]" id="bg_processes" multiple class="form-select form-select-sm" data-placeholder="By Process…">
                            <?php foreach ($bgProcesses as $p): ?>
                                <option value="<?= (int)$p['id'] ?>" <?= in_array((int)$p['id'], $bgState['process_ids'], true)?'selected':'' ?>>
                                    <?= e($p['client_name']) ?> » <?= e($p['name']) ?>
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                    <div class="col-md-4">
                        <select name="report_ids[]" id="bg_reports" multiple class="form-select form-select-sm" data-placeholder="Specific reports…">
                            <?php foreach ($bgReports as $r): ?>
                                <option value="<?= (int)$r['id'] ?>" <?= in_array((int)$r['id'], $bgState['report_ids'], true)?'selected':'' ?>>
                                    <?= e($r['client_name']) ?> » <?= e($r['name']) ?> (<?= e($r['code']) ?>)
                                </option>
                            <?php endforeach; ?>
                        </select>
                    </div>
                </div>
            </div>
        </div>

        <div class="bg-preview mt-3" id="bg_preview">
            <i class="ti ti-info-circle me-1"></i><span id="bg_preview_text">Select clients, processes, or reports above to see the affected set.</span>
        </div>

        <div class="mt-3">
            <div class="bg-step"><span class="num">3</span>Permissions to grant</div>
            <div class="bg-perms d-flex flex-wrap">
                <?php foreach ([['view','eye','#16a34a'],['upload','upload','#0ea5e9'],['download','download','#7c3aed'],['delete','trash','#dc2626'],['replace','refresh','#f59e0b']] as $p):
                    [$key, $icon, $col] = $p; $fk = 'can_' . $key; $chk = !empty($bgState['flags'][$fk]); ?>
                    <label class="form-check <?= $chk?'checked':'' ?>">
                        <input type="checkbox" class="form-check-input bg-perm" name="<?= $fk ?>" value="1" <?= $chk?'checked':'' ?>>
                        <span class="form-check-label"><i class="ti ti-<?= $icon ?> me-1" style="color:<?= $col ?>"></i><?= ucfirst($key) ?></span>
                    </label>
                <?php endforeach; ?>
            </div>
            <label class="form-check mt-2 small">
                <input type="checkbox" class="form-check-input" name="replace_mode" value="1" <?= !empty($bgState['replace_mode'])?'checked':'' ?>>
                <span class="form-check-label"><strong>Replace existing access</strong> on these reports (otherwise the new flags merge with what the user already has)</span>
            </label>
        </div>

        <div class="d-flex gap-2 mt-3">
            <button type="submit" class="btn btn-primary"><i class="ti ti-check me-1"></i>Apply bulk grant</button>
            <button type="button" class="btn btn-link" onclick="toggleBulkPanel()">Cancel</button>
        </div>
    </form>
</div>

<!-- ============= REPORT SELECTOR ============= -->
<div class="card mb-3"><div class="card-body py-3">
    <form method="GET" class="row g-2 align-items-center">
        <div class="col-auto">
            <label class="form-label mb-0 small text-secondary"><i class="ti ti-file-analytics me-1"></i>Choose report</label>
        </div>
        <?php if ($verticals): ?>
        <div class="col-auto">
            <select id="cr_vertical" class="form-select" style="max-width:200px" title="Filter reports by vertical">
                <option value="">All verticals</option>
                <?php foreach ($verticals as $v): ?><option value="<?= (int)$v['id'] ?>" <?= ($currentReport && (int)($currentReport['vertical_id'] ?? 0)===(int)$v['id'])?'selected':'' ?>><?= e($v['name']) ?></option><?php endforeach; ?>
            </select>
        </div>
        <?php endif; ?>
        <div class="col-md-6">
            <select name="report_id" id="report_id" class="form-select" onchange="this.form.submit()">
                <option value="">— Select a report —</option>
                <?php foreach ($reports as $r): ?>
                    <option value="<?= (int)$r['id'] ?>" <?= $r['id']==$reportId?'selected':'' ?>>
                        <?= e($r['client_name']) ?> » <?= e($r['name']) ?> (<?= e($r['code']) ?>)
                    </option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="col-auto small text-secondary">
            <?= count($reports) ?> active report<?= count($reports)===1?'':'s' ?>
        </div>
    </form>
</div></div>

<?php if (!$reportId): ?>
    <div class="ac-no-report-empty">
        <div class="icon">🔑</div>
        <h3 class="mb-2">Pick a report to manage access</h3>
        <p class="text-secondary mb-0">Select a report above. You can then grant or revoke any of the five actions (View, Upload, Download, Delete, Replace) per user — overriding the role default just for that report.</p>
    </div>
<?php else:
    $users = $pdo->query("SELECT u.id, u.name, u.email, u.user_type, u.last_login_at, c.name AS client_name
        FROM users u LEFT JOIN clients c ON c.id = u.client_id
        WHERE u.status = 'active' ORDER BY u.user_type, u.name")->fetchAll();
    $existing = $pdo->prepare('SELECT * FROM report_access WHERE report_id=?');
    $existing->execute([$reportId]);
    $existingMap = [];
    foreach ($existing->fetchAll() as $r) { $existingMap[$r['user_id']] = $r; }

    // Quick counts for KPI tiles
    $kCount = ['total'=>count($users), 'with_override'=>0, 'view'=>0, 'upload'=>0,
               'download'=>0, 'delete'=>0, 'replace'=>0, 'full'=>0];
    foreach ($existingMap as $r) {
        $kCount['with_override']++;
        $kCount['view']     += (int)$r['can_view'];
        $kCount['upload']   += (int)$r['can_upload'];
        $kCount['download'] += (int)$r['can_download'];
        $kCount['delete']   += (int)$r['can_delete'];
        $kCount['replace']  += (int)$r['can_replace'];
        if ($r['can_view'] && $r['can_upload'] && $r['can_download'] && $r['can_delete'] && $r['can_replace']) $kCount['full']++;
    }
    $lastChange = $pdo->prepare("SELECT MAX(updated_at) FROM report_access WHERE report_id=?");
    $lastChange->execute([$reportId]); $lastChange = $lastChange->fetchColumn();
?>

    <!-- ============= STATS STRIP ============= -->
    <div class="row row-cards mb-3 g-2">
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(32,107,196,.12);color:#206bc4"><i class="ti ti-users"></i></span></div>
            <div class="lbl">Active users</div><div class="val"><?= $kCount['total'] ?></div>
        </div></div>
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(124,58,237,.12);color:#7c3aed"><i class="ti ti-key"></i></span></div>
            <div class="lbl">With override</div><div class="val"><?= $kCount['with_override'] ?></div>
        </div></div>
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(34,197,94,.12);color:#16a34a"><i class="ti ti-eye"></i></span></div>
            <div class="lbl">Can View</div><div class="val"><?= $kCount['view'] ?></div>
        </div></div>
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(14,165,233,.12);color:#0ea5e9"><i class="ti ti-upload"></i></span></div>
            <div class="lbl">Can Upload</div><div class="val"><?= $kCount['upload'] ?></div>
        </div></div>
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(245,158,11,.12);color:#f59e0b"><i class="ti ti-star"></i></span></div>
            <div class="lbl">Full access</div><div class="val"><?= $kCount['full'] ?></div>
        </div></div>
        <div class="col-md-2 col-6"><div class="ac-kpi">
            <div class="d-flex align-items-center mb-1"><span class="ico" style="background:rgba(148,163,184,.12);color:#64748b"><i class="ti ti-clock"></i></span></div>
            <div class="lbl">Last change</div>
            <div class="val" style="font-size:1rem"><?= e(fmt_dt($lastChange)) ?></div>
        </div></div>
    </div>

    <!-- ============= FILTER BAR ============= -->
    <div class="ac-filters">
        <div class="row g-2 align-items-center">
            <div class="col-auto small text-secondary"><i class="ti ti-filter me-1"></i><strong>Filters:</strong></div>
            <div class="col-md-3">
                <div class="input-icon">
                    <span class="input-icon-addon"><i class="ti ti-search"></i></span>
                    <input type="text" id="f_search" class="form-control form-control-sm" placeholder="Search name or email...">
                </div>
            </div>
            <div class="col-md-2">
                <select id="f_type" class="form-select form-select-sm">
                    <option value="">All user types</option>
                    <option value="internal">Internal only</option>
                    <option value="client">Client only</option>
                </select>
            </div>
            <div class="col-md-2">
                <select id="f_status" class="form-select form-select-sm">
                    <option value="">All access states</option>
                    <option value="override">With override</option>
                    <option value="default">No override (role default)</option>
                    <option value="full">Full access (all 5)</option>
                </select>
            </div>
            <div class="col-auto ms-auto small text-secondary">
                <span id="visible_count">—</span> of <?= count($users) ?> users visible
            </div>
        </div>
    </div>

    <!-- ============= MATRIX ============= -->
    <form method="POST" id="ac_form">
        <?= csrf_field() ?>
        <input type="hidden" name="report_id" value="<?= $reportId ?>">

        <div class="card ac-matrix mb-3">
            <div class="table-responsive">
                <table class="table table-vcenter mb-0">
                    <thead style="position:sticky;top:0;background:var(--m-surface);z-index:5">
                        <tr>
                            <th style="min-width:240px">User</th>
                            <th>Type</th>
                            <th>Client</th>
                            <th class="text-end">Last login</th>
                            <?php foreach ([['view','eye','#16a34a'],['upload','upload','#0ea5e9'],['download','download','#7c3aed'],['delete','trash','#dc2626'],['replace','refresh','#f59e0b']] as $col):
                                [$perm, $icon, $color] = $col; ?>
                                <th class="text-center" style="min-width:90px">
                                    <div><i class="ti ti-<?= $icon ?> me-1" style="color:<?= $color ?>"></i><?= ucfirst($perm) ?></div>
                                    <div class="ac-col-toggle" onclick="toggleColumn('<?= $perm ?>')">⇅ all</div>
                                </th>
                            <?php endforeach; ?>
                            <th class="text-center">Quick</th>
                        </tr>
                    </thead>
                    <tbody>
                    <?php foreach ($users as $u):
                        $r = $existingMap[$u['id']] ?? null;
                        $hasOverride = (bool) $r;
                        $isFull = $r && $r['can_view'] && $r['can_upload'] && $r['can_download'] && $r['can_delete'] && $r['can_replace'];
                        $initials = strtoupper(substr($u['name'], 0, 2));
                    ?>
                        <tr class="<?= $hasOverride ? 'has-override' : '' ?><?= $isFull ? ' full-access' : '' ?>"
                            data-name="<?= e(strtolower($u['name'].' '.$u['email'])) ?>"
                            data-type="<?= e($u['user_type']) ?>"
                            data-override="<?= $hasOverride ? '1' : '0' ?>"
                            data-full="<?= $isFull ? '1' : '0' ?>">
                            <td>
                                <div class="user-cell">
                                    <span class="avatar <?= e($u['user_type']) ?>"><?= e($initials) ?></span>
                                    <div>
                                        <div class="name"><?= e($u['name']) ?></div>
                                        <div class="email"><?= e($u['email']) ?></div>
                                    </div>
                                </div>
                            </td>
                            <td><span class="ac-pill <?= e($u['user_type']) ?>"><?= e($u['user_type']) ?></span></td>
                            <td class="small text-secondary"><?= e($u['client_name'] ?? '—') ?></td>
                            <td class="small text-secondary text-end text-nowrap">
                                <?= e(fmt_dt($u['last_login_at'])) ?>
                            </td>
                            <?php foreach (['view','upload','download','delete','replace'] as $perm):
                                $colKey = 'can_' . $perm;
                                $checked = $r && $r[$colKey] ? 'checked' : '';
                            ?>
                                <td class="text-center">
                                    <label class="ac-switch" title="<?= ucfirst($perm) ?>">
                                        <input type="checkbox" name="access[<?= $u['id'] ?>][<?= $perm ?>]" value="1" <?= $checked ?> data-col="<?= $perm ?>" data-uid="<?= $u['id'] ?>" onchange="onToggle()">
                                        <span class="slider"></span>
                                    </label>
                                </td>
                            <?php endforeach; ?>
                            <td class="text-center ac-row-actions">
                                <button type="button" class="btn btn-outline-success btn-sm" onclick="rowSet(<?= $u['id'] ?>, true)"  title="Grant all 5"><i class="ti ti-check"></i></button>
                                <button type="button" class="btn btn-outline-danger  btn-sm" onclick="rowSet(<?= $u['id'] ?>, false)" title="Revoke all 5"><i class="ti ti-x"></i></button>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                    </tbody>
                </table>
            </div>
        </div>

        <!-- ============= STICKY SAVE BAR ============= -->
        <div class="ac-savebar">
            <span class="ac-changes-counter" id="changes_counter">
                <i class="ti ti-pencil"></i><span id="changes_text">No changes yet</span>
            </span>
            <span class="ms-auto d-flex gap-2">
                <button type="button" class="btn btn-outline-secondary btn-sm" onclick="resetForm()">
                    <i class="ti ti-arrow-back-up me-1"></i>Reset
                </button>
                <button type="submit" class="btn btn-primary" id="save_btn">
                    <i class="ti ti-check me-1"></i>Save changes
                </button>
            </span>
        </div>
    </form>

    <div class="ac-help mt-3">
        <strong><i class="ti ti-info-circle me-1"></i>Resolution order:</strong>
        <code>SysAdmin</code> → <code>per-report row above</code> → <code>role default</code> → <code>deny</code>.
        Leave all 5 switches OFF for a user to <strong>remove</strong> the override (user falls back to role-based access).
        Rows with a green tint already have an override. Rows with a darker green have <strong>full access</strong> to all 5 actions.
    </div>

<?php endif; ?>

</div>

<script>
/* ====================== Filtering ====================== */
const tbody = document.querySelector('.ac-matrix tbody');
const fSearch = document.getElementById('f_search');
const fType   = document.getElementById('f_type');
const fStatus = document.getElementById('f_status');
const visibleCount = document.getElementById('visible_count');

function applyFilters() {
    if (!tbody) return;
    const q = (fSearch?.value || '').toLowerCase().trim();
    const t = fType?.value || '';
    const s = fStatus?.value || '';
    let n = 0;
    tbody.querySelectorAll('tr').forEach(tr => {
        const matchName = !q || tr.dataset.name.includes(q);
        const matchType = !t || tr.dataset.type === t;
        let matchStatus = true;
        if (s === 'override') matchStatus = tr.dataset.override === '1';
        if (s === 'default')  matchStatus = tr.dataset.override === '0';
        if (s === 'full')     matchStatus = tr.dataset.full === '1';
        const show = matchName && matchType && matchStatus;
        tr.style.display = show ? '' : 'none';
        if (show) n++;
    });
    if (visibleCount) visibleCount.textContent = n;
}
[fSearch, fType, fStatus].forEach(el => el?.addEventListener('input', applyFilters));
applyFilters();

/* ====================== Column toggle ====================== */
window.toggleColumn = function(perm) {
    const boxes = Array.from(document.querySelectorAll(`input[data-col="${perm}"]`))
        .filter(cb => cb.closest('tr').style.display !== 'none');
    if (!boxes.length) return;
    const allChecked = boxes.every(cb => cb.checked);
    boxes.forEach(cb => cb.checked = !allChecked);
    onToggle();
};

/* ====================== Row quick actions ====================== */
window.rowSet = function(uid, on) {
    document.querySelectorAll(`input[data-uid="${uid}"]`).forEach(cb => cb.checked = on);
    onToggle();
};

/* ====================== Live change counter ====================== */
let originalState = null;
function captureOriginal() {
    originalState = {};
    document.querySelectorAll('.ac-matrix input[type=checkbox]').forEach(cb => {
        originalState[cb.name] = cb.checked;
    });
}
function onToggle() {
    if (!originalState) return;
    let changed = 0;
    document.querySelectorAll('.ac-matrix input[type=checkbox]').forEach(cb => {
        if (originalState[cb.name] !== cb.checked) changed++;
    });
    const counter = document.getElementById('changes_counter');
    const text    = document.getElementById('changes_text');
    if (counter && text) {
        if (changed === 0) {
            counter.classList.remove('has-changes');
            text.textContent = 'No changes yet';
        } else {
            counter.classList.add('has-changes');
            text.textContent = changed + ' pending change' + (changed===1?'':'s');
        }
    }
    /* Recalculate row visual states */
    document.querySelectorAll('.ac-matrix tbody tr').forEach(tr => {
        const boxes = tr.querySelectorAll('input[type=checkbox]');
        const checkedCount = Array.from(boxes).filter(cb => cb.checked).length;
        tr.classList.toggle('has-override', checkedCount > 0);
        tr.classList.toggle('full-access',  checkedCount === 5);
        tr.dataset.override = checkedCount > 0 ? '1' : '0';
        tr.dataset.full     = checkedCount === 5 ? '1' : '0';
    });
}
function resetForm() {
    if (!originalState) return;
    document.querySelectorAll('.ac-matrix input[type=checkbox]').forEach(cb => {
        cb.checked = originalState[cb.name];
    });
    onToggle();
}
window.resetForm = resetForm;
window.onToggle  = onToggle;
captureOriginal();
onToggle();

/* Warn before navigating away with unsaved changes */
window.addEventListener('beforeunload', function(e){
    const counter = document.getElementById('changes_counter');
    if (counter && counter.classList.contains('has-changes')) {
        e.preventDefault();
        return e.returnValue = 'You have unsaved access changes. Leave anyway?';
    }
});
document.getElementById('ac_form')?.addEventListener('submit', function(){
    window.removeEventListener('beforeunload', arguments.callee);
});

/* ====================== Bulk Grant panel ====================== */
window.toggleBulkPanel = function() {
    const p = document.getElementById('bgPanel');
    if (!p) return;
    const show = p.style.display === 'none' || p.style.display === '';
    p.style.display = show ? 'block' : 'none';
    if (show) p.scrollIntoView({ behavior: 'smooth', block: 'start' });
};

(function(){
    if (typeof TomSelect === 'undefined' || !document.getElementById('bg_clients')) return;
    const reports = <?= json_encode(array_map(fn($r)=>['id'=>(int)$r['id'],'client_id'=>(int)$r['client_id'],'process_id'=>(int)$r['process_id']], $bgReports)) ?>;
    // Master option lists tagged with vertical_id, so the Vertical filter can rebuild each picker client-side.
    const ALLC = <?= json_encode(array_map(fn($c)=>['id'=>(string)$c['id'],'text'=>$c['name'].' ('.$c['code'].')','v'=>(int)$c['vertical_id']], $bgClients)) ?>;
    const ALLP = <?= json_encode(array_map(fn($p)=>['id'=>(string)$p['id'],'text'=>$p['client_name'].' » '.$p['name'],'v'=>(int)$p['vertical_id']], $bgProcesses)) ?>;
    const ALLR = <?= json_encode(array_map(fn($r)=>['id'=>(string)$r['id'],'text'=>$r['client_name'].' » '.$r['name'].' ('.$r['code'].')','v'=>(int)$r['vertical_id']], $bgReports)) ?>;
    const opts = { plugins:['remove_button','clear_button'], maxOptions:5000, persist:false, hidePlaceholder:false };
    const tsC = new TomSelect('#bg_clients',   {...opts, placeholder:'By Client…'});
    const tsP = new TomSelect('#bg_processes', {...opts, placeholder:'By Process…'});
    const tsR = new TomSelect('#bg_reports',   {...opts, placeholder:'Specific reports…'});

    const picked = ts => Object.values(ts.options).filter(o => ts.items.includes(o.value)).map(o => parseInt(o.value,10));
    function updatePreview() {
        const c = picked(tsC), p = picked(tsP), r = picked(tsR);
        const hit = new Set();
        reports.forEach(row => {
            if (c.includes(row.client_id))  hit.add(row.id);
            if (p.includes(row.process_id)) hit.add(row.id);
            if (r.includes(row.id))         hit.add(row.id);
        });
        const clients = new Set();
        reports.forEach(row => { if (hit.has(row.id)) clients.add(row.client_id); });
        const t = document.getElementById('bg_preview_text');
        if (!hit.size) t.innerHTML = 'Select clients, processes, or reports above to see the affected set.';
        else t.innerHTML = `This will write <strong>${hit.size}</strong> report-access row${hit.size===1?'':'s'} across <strong>${clients.size}</strong> client${clients.size===1?'':'s'}.`;
    }
    [tsC, tsP, tsR].forEach(ts => ts.on('change', updatePreview));
    updatePreview();

    /* Vertical filter: rebuild each picker's options to the chosen vertical (keeping in-scope selections). */
    function fillTS(ts, data, vid){
        const sel = ts.items.slice();
        ts.clear(true); ts.clearOptions();
        data.filter(o => !vid || o.v === vid).forEach(o => ts.addOption({ value:o.id, text:o.text }));
        ts.refreshOptions(false);
        sel.forEach(v => { if (ts.options[v]) ts.addItem(v, true); });
    }
    const bgV = document.getElementById('bg_vertical');
    if (bgV) bgV.addEventListener('change', function(){
        const vid = parseInt(this.value || '0', 10) || 0;
        fillTS(tsC, ALLC, vid); fillTS(tsP, ALLP, vid); fillTS(tsR, ALLR, vid);
        updatePreview();
    });

    /* Permission cards highlight on check */
    document.querySelectorAll('.bg-perm').forEach(cb => {
        cb.addEventListener('change', function(){ this.closest('label').classList.toggle('checked', this.checked); });
    });
})();

/* ====================== Choose-report vertical filter ====================== */
(function(){
    const crV = document.getElementById('cr_vertical');
    const rep = document.getElementById('report_id');
    if (!crV || !rep) return;
    const ALL = <?= json_encode(array_map(fn($r)=>['id'=>(string)$r['id'],'text'=>$r['client_name'].' » '.$r['name'].' ('.$r['code'].')','v'=>(int)$r['vertical_id']], $reports)) ?>;
    const cur = rep.value;
    function rebuild(){
        const vid = parseInt(crV.value || '0', 10) || 0;
        rep.innerHTML = '<option value="">— Select a report —</option>';
        ALL.filter(o => !vid || o.v === vid).forEach(o => {
            const opt = document.createElement('option');
            opt.value = o.id; opt.textContent = o.text;
            if (o.id === cur) opt.selected = true;
            rep.appendChild(opt);
        });
    }
    crV.addEventListener('change', rebuild);
    if (crV.value) rebuild();   // a report is open → its vertical is preselected, so scope the list to match
})();
</script>

<?php require __DIR__ . '/../includes/footer.php'; ?>
