<?php
/**
 * rounds.php – centralised exam-round state + auto bell scheduler.
 *
 * v2.3: rounds are facility-scoped.
 *   - facility_id NULL  → global round (super_admin only); broadcast to everyone.
 *   - facility_id = N   → that facility only; super_admins still see it.
 *
 * One round at a time per facility (and one global).
 */

function round_current_for_user(PDO $pdo, ?array $user): ?array
{
    if (!$user) return null;
    // super sees any running round (prefer facility-specific if their facility_id matches)
    if (perms_is_super($user)) {
        $stmt = $pdo->query("SELECT * FROM exam_rounds WHERE status = 'running' ORDER BY id DESC LIMIT 1");
        return $stmt->fetch() ?: null;
    }
    $fac = (int)($user['facility_id'] ?? 0);
    $stmt = $pdo->prepare("SELECT * FROM exam_rounds WHERE status = 'running' AND (facility_id IS NULL OR facility_id = ?) ORDER BY id DESC LIMIT 1");
    $stmt->execute([$fac]);
    return $stmt->fetch() ?: null;
}

function round_current_for_facility(PDO $pdo, ?int $facilityId): ?array
{
    if ($facilityId === null) {
        $stmt = $pdo->query("SELECT * FROM exam_rounds WHERE status = 'running' AND facility_id IS NULL ORDER BY id DESC LIMIT 1");
        return $stmt->fetch() ?: null;
    }
    $stmt = $pdo->prepare("SELECT * FROM exam_rounds WHERE status = 'running' AND facility_id = ? ORDER BY id DESC LIMIT 1");
    $stmt->execute([$facilityId]);
    return $stmt->fetch() ?: null;
}

function round_start(PDO $pdo, ?int $facilityId, ?string $label, int $durationMin, int $warnMin, int $userId): array
{
    $durationMin = max(1, min(60, $durationMin));
    $warnMin     = max(1, min($durationMin - 1, $warnMin));

    if ($facilityId === null) {
        $pdo->exec("UPDATE exam_rounds SET status='aborted', ended_at = NOW() WHERE status='running' AND facility_id IS NULL");
    } else {
        $s = $pdo->prepare("UPDATE exam_rounds SET status='aborted', ended_at = NOW() WHERE status='running' AND facility_id = ?");
        $s->execute([$facilityId]);
    }

    $pdo->prepare("
        INSERT INTO exam_rounds (facility_id, round_label, duration_minutes, warn_minutes, started_at, started_by, status)
        VALUES (?, ?, ?, ?, NOW(), ?, 'running')
    ")->execute([$facilityId, $label ?: null, $durationMin, $warnMin, $userId]);

    $id = (int)$pdo->lastInsertId();
    bell_fire($pdo, $id, 'start', $userId);

    return round_current_for_facility($pdo, $facilityId) ?? [];
}

function round_end(PDO $pdo, int $roundId, int $userId, string $how = 'ended'): void
{
    $cur = $pdo->prepare("SELECT * FROM exam_rounds WHERE id = ? AND status = 'running'");
    $cur->execute([$roundId]);
    $row = $cur->fetch();
    if (!$row) return;
    $pdo->prepare("UPDATE exam_rounds SET status = ?, ended_at = NOW() WHERE id = ?")
        ->execute([$how === 'aborted' ? 'aborted' : 'ended', $roundId]);
    if ($how !== 'aborted') {
        bell_fire($pdo, $roundId, 'end', $userId);
    }
}

function bell_fire(PDO $pdo, ?int $roundId, string $eventType, ?int $userId): int
{
    $pdo->prepare("INSERT INTO bell_events (round_id, event_type, triggered_at, triggered_by) VALUES (?, ?, NOW(), ?)")
        ->execute([$roundId, $eventType, $userId]);
    return (int)$pdo->lastInsertId();
}

/** Schedule auto bells for all currently running rounds. */
function round_tick_all(PDO $pdo): void
{
    $stmt = $pdo->query("SELECT * FROM exam_rounds WHERE status = 'running'");
    foreach ($stmt->fetchAll() as $cur) {
        $startTs    = strtotime($cur['started_at']);
        $now        = time();
        $elapsedSec = $now - $startTs;
        $durSec     = (int)$cur['duration_minutes'] * 60;
        $warnSec    = $durSec - ((int)$cur['warn_minutes'] * 60);

        $ev = $pdo->prepare("SELECT event_type FROM bell_events WHERE round_id = ?");
        $ev->execute([$cur['id']]);
        $existing = array_column($ev->fetchAll(), 'event_type');

        if ($elapsedSec >= $warnSec && !in_array('warn_2min', $existing, true)) {
            bell_fire($pdo, (int)$cur['id'], 'warn_2min', null);
        }
        if ($elapsedSec >= $durSec && !in_array('end', $existing, true)) {
            bell_fire($pdo, (int)$cur['id'], 'end', null);
            $pdo->prepare("UPDATE exam_rounds SET status='ended', ended_at = NOW() WHERE id = ?")
                ->execute([$cur['id']]);
        }
    }
}

/** Recent bell events visible to the given user (own facility + global). */
function bell_recent_for_user(PDO $pdo, ?array $user, int $sinceId = 0, int $limit = 50): array
{
    if (!$user) return [];
    if (perms_is_super($user)) {
        $stmt = $pdo->prepare("SELECT be.id, be.round_id, be.event_type, be.triggered_at, er.facility_id FROM bell_events be LEFT JOIN exam_rounds er ON er.id = be.round_id WHERE be.id > ? ORDER BY be.id DESC LIMIT $limit");
        $stmt->execute([$sinceId]);
    } else {
        $stmt = $pdo->prepare("
            SELECT be.id, be.round_id, be.event_type, be.triggered_at, er.facility_id
            FROM bell_events be
            LEFT JOIN exam_rounds er ON er.id = be.round_id
            WHERE be.id > ? AND (er.facility_id IS NULL OR er.facility_id = ?)
            ORDER BY be.id DESC LIMIT $limit");
        $stmt->execute([$sinceId, (int)$user['facility_id']]);
    }
    return array_reverse($stmt->fetchAll());
}

/** Snapshot for the current user. */
function round_state_snapshot_for_user(PDO $pdo, ?array $user): array
{
    round_tick_all($pdo);
    $now = time();
    $cur = round_current_for_user($pdo, $user);
    if ($cur) {
        $startTs    = strtotime($cur['started_at']);
        $durSec     = (int)$cur['duration_minutes'] * 60;
        $endTs      = $startTs + $durSec;
        return [
            'running'           => true,
            'round_id'          => (int)$cur['id'],
            'facility_id'       => $cur['facility_id'] !== null ? (int)$cur['facility_id'] : null,
            'label'             => $cur['round_label'],
            'duration_minutes'  => (int)$cur['duration_minutes'],
            'warn_minutes'      => (int)$cur['warn_minutes'],
            'started_at'        => $cur['started_at'],
            'started_ts_ms'     => $startTs * 1000,
            'end_ts_ms'         => $endTs * 1000,
            'server_now_ms'     => $now * 1000,
            'remaining_seconds' => max(0, $endTs - $now),
        ];
    }
    return [
        'running'       => false,
        'server_now_ms' => $now * 1000,
    ];
}
