<?php
// Harden session cookies before any session_start() call. Many entry points
// across the app call session_start() before requiring config.php (and thus
// this file), so guard against the "ini settings cannot be changed when a
// session is active" warning that ini_set() raises in that case.
if (session_status() !== PHP_SESSION_ACTIVE) {
    ini_set('session.cookie_httponly', 1);
    ini_set('session.cookie_samesite', 'Strict');
    ini_set('session.use_only_cookies', 1);
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
        ini_set('session.cookie_secure', 1);
    }
}

// Load .env file
$envFile = __DIR__ . '/../.env';
if (file_exists($envFile)) {
    $lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($lines as $line) {
        if (strpos(trim($line), '#') === 0) continue;
        if (strpos($line, '=') !== false) {
            [$key, $value] = explode('=', $line, 2);
            $_ENV[trim($key)] = trim($value);
            putenv(trim($key) . '=' . trim($value));
        }
    }
} 

require_once __DIR__ . '/vendor/autoload.php';

// CSRF helpers — call csrf_token() to get the token, csrf_verify() to validate POST requests
function csrf_token(): string {
    if (session_status() === PHP_SESSION_ACTIVE && empty($_SESSION['_csrf_token'])) {
        $_SESSION['_csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['_csrf_token'] ?? '';
}

function csrf_field(): string {
    return '<input type="hidden" name="_csrf_token" value="' . htmlspecialchars(csrf_token(), ENT_QUOTES, 'UTF-8') . '">';
}

function csrf_verify(): bool {
    $token = $_POST['_csrf_token'] ?? $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
    return hash_equals(csrf_token(), $token);
}

$dsn = getenv('SENTRY_DSN');
if (!empty($dsn)) {
    // Use synchronous HTTP transport — fixes NULL event ID on Windows/XAMPP
    $transport = \Sentry\Transport\HttpTransport::class;

    \Sentry\init([
        'dsn'                => $dsn,
        'environment'        => getenv('APP_ENV') ?: 'production',
        'release'            => getenv('APP_VERSION') ?: 'unknown',
        'traces_sample_rate' => 1.0,
        'http_timeout'       => 10,
        'http_connect_timeout' => 5,
        // This codebase runs with error_reporting(E_ALL), which includes many
        // pre-existing warnings/notices in legacy code paths. Restrict the PHP
        // error listener to real errors so those don't flood the Sentry quota;
        // uncaught exceptions and fatal errors are always captured regardless
        // of this setting (separate listener).
        'error_types' => E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE & ~E_WARNING & ~E_USER_WARNING & ~E_USER_NOTICE & ~E_USER_DEPRECATED,
    ]);

    // Force flush after every request on localhost
    register_shutdown_function(function () {
        $client = \Sentry\SentrySdk::getCurrentHub()->getClient();
        if ($client !== null) {
            $client->flush();
        }
    });
}

if (!function_exists('sentry_set_context')) {
    /**
     * Attach the logged-in user and school (multi-tenant) context to the
     * current Sentry scope. Call once per request, after session_start().
     * Safe to call even when Sentry isn't initialized (SENTRY_DSN unset).
     */
    function sentry_set_context(): void {
        if (!class_exists(\Sentry\State\Scope::class) || !getenv('SENTRY_DSN')) {
            return;
        }
        \Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
            if (!empty($_SESSION['user_id'])) {
                $scope->setUser([
                    'id'       => $_SESSION['user_id'],
                    'username' => $_SESSION['username'] ?? null,
                ]);
            }
            $scope->setTag('role', $_SESSION['role'] ?? 'guest');
            if (defined('SCHOOL_CODE')) {
                $scope->setTag('school_code', SCHOOL_CODE);
            }
        });
    }
}