<?php
// Active sessions page. Lists nonce rows from the SQLite login DB and
// surfaces a terminate action per row. Non-root users see only their own
// sessions; root sees every row across every account.

require_once('/docker/whp/web/libs/security.php');

$current_user = $_SESSION['user'] ?? '';
$is_root = ($current_user === 'root');
$current_nonce = $_SESSION['nonce'] ?? '';
// Selector half of the caller's persist-token cookie (if any). Used to flag
// the matching token row as "this session" in the table. Verifier stays out.
$current_token_selector = '';
if (!empty($_COOKIE['whp_persist'])
    && preg_match('/^([a-f0-9]{16}):[a-f0-9]{64}$/', $_COOKIE['whp_persist'], $cs_match)) {
    $current_token_selector = $cs_match[1];
}

if (!isset($SecMan) || !($SecMan instanceof security_wrapper)) {
    $SecMan = new security_wrapper();
}

$scope_user = $is_root ? null : $current_user;
$nonce_rows = $SecMan->list_nonces($scope_user);
$token_rows = $SecMan->list_persist_tokens($scope_user);

// Normalize into a single list with a 'source' field so the row renderer and
// the terminate JS can route to the right API action.
$rows = [];
foreach ($nonce_rows as $r) {
    $rows[] = [
        'source'    => 'nonce',
        'id'        => $r['nonce'],
        'user'      => $r['user'],
        'ip'        => $r['ip'],
        'last_time' => (int)$r['last_time'],
        'persist'   => !empty($r['persist']),
        'is_self'   => ($r['nonce'] === $current_nonce),
    ];
}
foreach ($token_rows as $r) {
    $rows[] = [
        'source'    => 'token',
        'id'        => $r['selector'],
        'user'      => $r['user'],
        'ip'        => $r['ip'],
        'last_time' => (int)$r['last_used_time'],
        'persist'   => true,
        'is_self'   => ($current_token_selector !== '' && $r['selector'] === $current_token_selector),
    ];
}
// Most-recently-active first across both kinds.
usort($rows, function($a, $b) { return $b['last_time'] <=> $a['last_time']; });

// Build the list of users for the root bulk-terminate dropdown from whichever
// users currently have an active session. Cheap, no extra DB call needed.
$user_options = [];
if ($is_root) {
    $unique_users = [];
    foreach ($rows as $r) {
        if (!empty($r['user'])) { $unique_users[$r['user']] = true; }
    }
    $user_options = array_keys($unique_users);
    sort($user_options);
}

function fmt_time_ago($ts) {
    $diff = time() - (int)$ts;
    if ($diff < 60)        return $diff . 's ago';
    if ($diff < 3600)      return floor($diff / 60) . 'm ago';
    if ($diff < 86400)     return floor($diff / 3600) . 'h ago';
    return floor($diff / 86400) . 'd ago';
}
?>

<div class="card">
    <div class="card-body">
        <p class="text-muted mb-3">
            <i class="fa fa-info-circle"></i>
            <?php if ($is_root): ?>
                Showing every active session across all users. As root you can terminate any session.
            <?php else: ?>
                Sessions currently logged in to your account. Terminating a session signs that browser out on its next request.
            <?php endif; ?>
        </p>

        <div class="table-responsive">
            <table class="table table-sm table-hover" id="sessions-table">
                <thead>
                    <tr>
                        <?php if ($is_root): ?><th>User</th><?php endif; ?>
                        <th>IP</th>
                        <th>Last activity</th>
                        <th>Type</th>
                        <th>Status</th>
                        <th class="text-end">Action</th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (empty($rows)): ?>
                        <tr><td colspan="<?php echo $is_root ? 6 : 5; ?>" class="text-muted text-center py-3">No active sessions.</td></tr>
                    <?php else: foreach ($rows as $r): ?>
                        <?php
                        $row_id  = htmlspecialchars($r['id'],     ENT_QUOTES);
                        $row_src = htmlspecialchars($r['source'], ENT_QUOTES);
                        $is_self = $r['is_self'];
                        ?>
                        <tr data-id="<?php echo $row_id; ?>" data-source="<?php echo $row_src; ?>">
                            <?php if ($is_root): ?>
                                <td><code><?php echo htmlspecialchars($r['user']); ?></code></td>
                            <?php endif; ?>
                            <td><code><?php echo htmlspecialchars($r['ip']); ?></code></td>
                            <td><?php echo htmlspecialchars(fmt_time_ago($r['last_time'])); ?></td>
                            <td>
                                <?php if ($r['source'] === 'token'): ?>
                                    <span class="badge bg-primary" title="Persistent-auth cookie (selector:verifier) — Stay-Logged-In credential that survives PHPSESSID expiry">Persistent (token)</span>
                                <?php elseif (!empty($r['persist'])): ?>
                                    <span class="badge bg-info" title="Stay-Logged-In session nonce">Persistent</span>
                                <?php else: ?>
                                    <span class="badge bg-secondary">Standard</span>
                                <?php endif; ?>
                            </td>
                            <td>
                                <?php if ($is_self): ?>
                                    <span class="badge bg-success">This session</span>
                                <?php else: ?>
                                    <span class="text-muted">—</span>
                                <?php endif; ?>
                            </td>
                            <td class="text-end">
                                <button class="btn btn-sm btn-outline-danger terminate-btn"
                                        data-id="<?php echo $row_id; ?>"
                                        data-source="<?php echo $row_src; ?>"
                                        data-self="<?php echo $is_self ? '1' : '0'; ?>">
                                    <i class="fa fa-sign-out"></i> Terminate
                                </button>
                            </td>
                        </tr>
                    <?php endforeach; endif; ?>
                </tbody>
            </table>
        </div>

        <?php if ($is_root && !empty($user_options)): ?>
            <hr>
            <h5>Bulk: terminate every session for a user</h5>
            <p class="text-muted small">Useful when an account is reported compromised. Logs every active browser for that account out.</p>
            <form id="bulk-terminate-form" class="row g-2 align-items-center">
                <div class="col-auto">
                    <label for="bulk-user" class="col-form-label">User</label>
                </div>
                <div class="col-auto">
                    <select class="form-select form-select-sm" id="bulk-user">
                        <option value="">— select —</option>
                        <?php foreach ($user_options as $u): ?>
                            <option value="<?php echo htmlspecialchars($u); ?>"><?php echo htmlspecialchars($u); ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="col-auto">
                    <button type="submit" class="btn btn-sm btn-danger">
                        <i class="fa fa-power-off"></i> Terminate all
                    </button>
                </div>
            </form>
        <?php endif; ?>
    </div>
</div>

<script>
(function() {
    const csrfToken = '<?php echo htmlspecialchars($_SESSION['csrf_token'] ?? '', ENT_QUOTES); ?>';

    function api(action, body) {
        return fetch('api/sessions.php?action=' + encodeURIComponent(action), {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'X-CSRF-Token': csrfToken
            },
            body: body
        }).then(function(r) { return r.json(); });
    }

    document.querySelectorAll('.terminate-btn').forEach(function(btn) {
        btn.addEventListener('click', function() {
            const id = btn.dataset.id;
            const source = btn.dataset.source;
            const isSelf = btn.dataset.self === '1';
            const msg = isSelf
                ? 'Terminate THIS session? You will be logged out immediately.'
                : 'Terminate this session?';
            if (!confirm(msg)) return;
            btn.disabled = true;
            // Route to the matching API action: nonce rows use ?action=terminate
            // with a nonce= body, token rows use ?action=terminate_token with a
            // selector= body. The server enforces the same auth rules on both.
            const action = source === 'token' ? 'terminate_token' : 'terminate';
            const body = (source === 'token' ? 'selector=' : 'nonce=') + encodeURIComponent(id);
            api(action, body).then(function(res) {
                if (res.success) {
                    if (res.self_terminated) {
                        window.location.href = '/login.php';
                        return;
                    }
                    const row = btn.closest('tr');
                    if (row) row.remove();
                } else {
                    alert('Terminate failed: ' + (res.error || 'unknown error'));
                    btn.disabled = false;
                }
            }).catch(function(err) {
                alert('Terminate failed: ' + err);
                btn.disabled = false;
            });
        });
    });

    const bulkForm = document.getElementById('bulk-terminate-form');
    if (bulkForm) {
        bulkForm.addEventListener('submit', function(e) {
            e.preventDefault();
            const user = document.getElementById('bulk-user').value;
            if (!user) return;
            if (!confirm('Terminate every active session for ' + user + '?')) return;
            api('terminate_user', 'user=' + encodeURIComponent(user)).then(function(res) {
                if (res.success) {
                    window.location.reload();
                } else {
                    alert('Bulk terminate failed: ' + (res.error || 'unknown error'));
                }
            });
        });
    }
})();
</script>
