<?php

declare(strict_types=1);

if (!defined('JLFC_ROOT')) {
    define('JLFC_ROOT', dirname(__DIR__, 2));
}

if (!isset($GLOBALS['JLFC_CONFIG'])) {
    $GLOBALS['JLFC_CONFIG'] = [
        'app' => require JLFC_ROOT . '/app/config/app.php',
        'database' => require JLFC_ROOT . '/app/config/database.php',
    ];
}

if (session_status() !== PHP_SESSION_ACTIVE) {
    $appConfig = $GLOBALS['JLFC_CONFIG']['app'];

    if (!headers_sent()) {
        session_name((string) ($appConfig['session_name'] ?? 'jlfc_session'));
        session_set_cookie_params([
            'lifetime' => 0,
            'path' => '/',
            'domain' => '',
            'secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
            'httponly' => true,
            'samesite' => 'Lax',
        ]);
    }

    session_start();
}

date_default_timezone_set((string) config('app.timezone', 'Africa/Lagos'));

function config(string $key, mixed $default = null): mixed
{
    $segments = explode('.', $key);
    $value = $GLOBALS['JLFC_CONFIG'] ?? [];

    foreach ($segments as $segment) {
        if (!is_array($value) || !array_key_exists($segment, $value)) {
            return $default;
        }

        $value = $value[$segment];
    }

    return $value;
}

function app_root(string $path = ''): string
{
    $root = JLFC_ROOT;
    return $path === '' ? $root : $root . '/' . ltrim(str_replace('\\', '/', $path), '/');
}

function inferred_base_url(): string
{
    $scriptName = str_replace('\\', '/', (string) ($_SERVER['SCRIPT_NAME'] ?? ''));

    if ($scriptName === '') {
        return rtrim((string) config('app.base_url', ''), '/');
    }

    foreach (['/app/', '/dashboard.php', '/login.php', '/logout.php'] as $marker) {
        $position = strpos($scriptName, $marker);
        if ($position !== false) {
            return rtrim(substr($scriptName, 0, $position), '/');
        }
    }

    $directory = str_replace('\\', '/', dirname($scriptName));
    return $directory === '/' ? '' : rtrim($directory, '/');
}

function base_url(string $path = ''): string
{
    $configuredBase = trim((string) config('app.base_url', ''));
    $base = preg_match('/^https?:\/\//i', $configuredBase)
        ? rtrim($configuredBase, '/')
        : inferred_base_url();

    return $path === '' ? $base : $base . '/' . ltrim($path, '/');
}

function absolute_base_url(): string
{
    $configuredBase = trim((string) config('app.base_url', ''));

    if (preg_match('/^https?:\/\//i', $configuredBase)) {
        return rtrim($configuredBase, '/');
    }

    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = (string) ($_SERVER['HTTP_HOST'] ?? 'localhost');
    $basePath = inferred_base_url();

    return rtrim($scheme . '://' . $host . $basePath, '/');
}

function absolute_url(string $path = ''): string
{
    $base = absolute_base_url();

    return $path === '' ? $base : $base . '/' . ltrim($path, '/');
}

function current_absolute_url(): string
{
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host = (string) ($_SERVER['HTTP_HOST'] ?? 'localhost');
    $requestUri = (string) ($_SERVER['REQUEST_URI'] ?? '/');

    return $scheme . '://' . $host . $requestUri;
}

function asset_url(string $path = ''): string
{
    return base_url('app/public/assets/' . ltrim($path, '/'));
}

function current_module_page_context(): ?array
{
    $scriptName = str_replace('\\', '/', (string) ($_SERVER['SCRIPT_NAME'] ?? ''));

    if (!preg_match('#/app/modules/([^/]+)/([^/]+)\.php$#', $scriptName, $matches)) {
        return null;
    }

    $module = strtolower((string) $matches[1]);
    $page = strtolower((string) $matches[2]);

    if (in_array($page, ['actions', 'helpers', '_form'], true)) {
        return null;
    }

    return [
        'module' => $module,
        'page' => $page,
    ];
}

function module_navigation_label(string $module): string
{
    return match ($module) {
        'staff' => 'Staff',
        default => ucwords(str_replace('_', ' ', $module)),
    };
}

function render_module_page_navigation(): void
{
    $context = current_module_page_context();

    if ($context === null || $context['page'] === 'index') {
        return;
    }

    $module = $context['module'];
    $page = $context['page'];
    $moduleLabel = module_navigation_label($module);
    $moduleBasePath = 'app/modules/' . $module . '/';
    $moduleDirectory = app_root($moduleBasePath);
    $links = [];

    if (is_file($moduleDirectory . '/index.php')) {
        $links[] = [
            'label' => 'Back to ' . $moduleLabel,
            'href' => base_url($moduleBasePath . 'index.php'),
            'class' => 'btn btn-outline-jlfc',
        ];
    }

    if ($page !== 'create' && is_file($moduleDirectory . '/create.php')) {
        $links[] = [
            'label' => 'Add more ' . strtolower($moduleLabel),
            'href' => base_url($moduleBasePath . 'create.php'),
            'class' => 'btn btn-jlfc',
        ];
    }

    if ($links === []) {
        return;
    }

    echo '<div class="context-action-bar">';
    echo '<div class="context-action-bar-copy">';
    echo '<span class="eyebrow">Quick navigation</span>';
    echo '<strong>' . e($moduleLabel) . ' workflow</strong>';
    echo '</div>';
    echo '<div class="context-action-bar-links">';

    foreach ($links as $link) {
        echo '<a class="' . e($link['class']) . '" href="' . e($link['href']) . '">' . e($link['label']) . '</a>';
    }

    echo '</div>';
    echo '</div>';
}

function redirect(string $path): never
{
    $target = preg_match('/^https?:\/\//i', $path) ? $path : base_url($path);
    header('Location: ' . $target);
    exit;
}

function e(null|string|int|float $value): string
{
    return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}

function format_time_12h(?string $time, string $fallback = 'Time TBC'): string
{
    $time = trim((string) $time);

    if ($time === '') {
        return $fallback;
    }

    $timestamp = strtotime('1970-01-01 ' . $time);

    return $timestamp === false ? $fallback : date('g:i A', $timestamp);
}

function format_match_date_time(?string $date, ?string $time, string $dateFallback = 'Date TBC', string $timeFallback = 'Time TBC'): string
{
    $dateValue = trim((string) $date);
    $dateLabel = $dateValue !== '' ? $dateValue : $dateFallback;
    $timeLabel = format_time_12h($time, $timeFallback);

    return $dateLabel . ' ' . $timeLabel;
}

function competition_stage_label(array $fixture, string $default = 'League'): string
{
    $groupLabel = trim((string) ($fixture['group_label'] ?? ''));
    if ($groupLabel !== '') {
        return $groupLabel;
    }

    $knockoutRound = trim((string) ($fixture['knockout_round'] ?? ''));
    if ($knockoutRound !== '') {
        return $knockoutRound;
    }

    $stageType = trim((string) ($fixture['stage_type'] ?? ''));
    $competitionType = trim((string) ($fixture['competition_type'] ?? ''));

    if ($stageType !== '' && strtolower($stageType) !== 'league') {
        return ucwords(str_replace('_', ' ', $stageType));
    }

    if ($competitionType !== '') {
        return ucwords(str_replace('_', ' ', $competitionType));
    }

    if ($stageType !== '') {
        return ucwords(str_replace('_', ' ', $stageType));
    }

    return $default;
}

function flash(string $key, mixed $value = null): mixed
{
    if (func_num_args() === 1) {
        $message = $_SESSION['_flash'][$key] ?? null;
        unset($_SESSION['_flash'][$key]);
        return $message;
    }

    $_SESSION['_flash'][$key] = $value;
    return null;
}

function all_flashes(): array
{
    $messages = $_SESSION['_flash'] ?? [];
    unset($_SESSION['_flash']);
    return is_array($messages) ? $messages : [];
}

function remember_old_input(array $input): void
{
    unset($input['password'], $input['password_confirmation'], $input['_csrf']);
    $_SESSION['_old'] = $input;
}

function clear_old_input(): void
{
    unset($_SESSION['_old']);
}

function old(string $key, mixed $default = ''): mixed
{
    return $_SESSION['_old'][$key] ?? $default;
}

function request_method(): string
{
    return strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
}

function is_post(): bool
{
    return request_method() === 'POST';
}

function jlfc_seed_payload(): array
{
    return [
        'roles' => [
            'Super Admin' => 'Full access to the JLFC platform.',
            'League Admin' => 'Manages competitions, clubs, fixtures, results, discipline, protests, awards, media, and reports.',
            'Club Admin' => 'Manages own club profile, players, staff, and views fixtures and results.',
            'Coach' => 'Receives match preparation alerts and submits team formations for assigned club fixtures.',
            'Match Commissioner' => 'Submits match reports and match results.',
            'Referee Coordinator' => 'Assigns referees and updates officiating details.',
            'Finance Officer' => 'Manages club payments, fines, appeal fees, and financial reports.',
            'Media Officer' => 'Publishes news, gallery content, and match media.',
            'Viewer' => 'Read-only backend access.',
        ],
        'permissions' => [
            'view_dashboard' => ['name' => 'View dashboard', 'module' => 'dashboard'],
            'manage_users' => ['name' => 'Manage users', 'module' => 'users'],
            'manage_roles' => ['name' => 'Manage roles', 'module' => 'roles'],
            'manage_permissions' => ['name' => 'Manage permissions', 'module' => 'roles'],
            'manage_seasons' => ['name' => 'Manage seasons', 'module' => 'seasons'],
            'manage_competitions' => ['name' => 'Manage competitions', 'module' => 'competitions'],
            'manage_clubs' => ['name' => 'Manage clubs', 'module' => 'clubs'],
            'approve_clubs' => ['name' => 'Approve clubs', 'module' => 'clubs'],
            'manage_players' => ['name' => 'Manage players', 'module' => 'players'],
            'approve_players' => ['name' => 'Approve players', 'module' => 'players'],
            'manage_player_licenses' => ['name' => 'Manage player licenses', 'module' => 'licenses'],
            'verify_player_licenses' => ['name' => 'Verify player licenses', 'module' => 'licenses'],
            'manage_club_staff' => ['name' => 'Manage club staff', 'module' => 'staff'],
            'manage_venues' => ['name' => 'Manage venues', 'module' => 'venues'],
            'manage_referees' => ['name' => 'Manage referees', 'module' => 'referees'],
            'assign_referees' => ['name' => 'Assign referees', 'module' => 'referees'],
            'manage_fixtures' => ['name' => 'Manage fixtures', 'module' => 'fixtures'],
            'manage_match_preparation' => ['name' => 'Manage match preparation', 'module' => 'fixtures'],
            'generate_fixtures' => ['name' => 'Generate fixtures', 'module' => 'fixtures'],
            'submit_results' => ['name' => 'Submit results', 'module' => 'matches'],
            'verify_results' => ['name' => 'Verify results', 'module' => 'matches'],
            'manage_table' => ['name' => 'Manage table', 'module' => 'table'],
            'recalculate_table' => ['name' => 'Recalculate table', 'module' => 'table'],
            'manage_statistics' => ['name' => 'Manage statistics', 'module' => 'statistics'],
            'manage_discipline' => ['name' => 'Manage discipline', 'module' => 'discipline'],
            'manage_suspensions' => ['name' => 'Manage suspensions', 'module' => 'discipline'],
            'manage_finance' => ['name' => 'Manage finance', 'module' => 'finance'],
            'record_payments' => ['name' => 'Record payments', 'module' => 'finance'],
            'manage_protests' => ['name' => 'Manage protests', 'module' => 'protests'],
            'decide_protests' => ['name' => 'Decide protests', 'module' => 'protests'],
            'manage_awards' => ['name' => 'Manage awards', 'module' => 'awards'],
            'manage_media' => ['name' => 'Manage media', 'module' => 'media'],
            'publish_news' => ['name' => 'Publish news', 'module' => 'media'],
            'manage_transfers' => ['name' => 'Manage transfers', 'module' => 'transfers'],
            'approve_transfers' => ['name' => 'Approve transfers', 'module' => 'transfers'],
            'view_reports' => ['name' => 'View reports', 'module' => 'reports'],
            'export_reports' => ['name' => 'Export reports', 'module' => 'reports'],
            'manage_settings' => ['name' => 'Manage settings', 'module' => 'settings'],
        ],
        'role_permissions' => [
            'Super Admin' => [
                'view_dashboard',
                'manage_users',
                'manage_roles',
                'manage_permissions',
                'manage_seasons',
                'manage_competitions',
                'manage_clubs',
                'approve_clubs',
                'manage_players',
                'approve_players',
                'manage_player_licenses',
                'verify_player_licenses',
                'manage_club_staff',
                'manage_venues',
                'manage_referees',
                'assign_referees',
                'manage_fixtures',
                'manage_match_preparation',
                'generate_fixtures',
                'submit_results',
                'verify_results',
                'manage_table',
                'recalculate_table',
                'manage_statistics',
                'manage_discipline',
                'manage_suspensions',
                'manage_finance',
                'record_payments',
                'manage_protests',
                'decide_protests',
                'manage_awards',
                'manage_media',
                'publish_news',
                'manage_transfers',
                'approve_transfers',
                'view_reports',
                'export_reports',
                'manage_settings',
            ],
            'League Admin' => [
                'view_dashboard',
                'manage_seasons',
                'manage_competitions',
                'manage_clubs',
                'approve_clubs',
                'manage_players',
                'approve_players',
                'manage_player_licenses',
                'verify_player_licenses',
                'manage_club_staff',
                'manage_venues',
                'manage_referees',
                'assign_referees',
                'manage_fixtures',
                'manage_match_preparation',
                'generate_fixtures',
                'submit_results',
                'verify_results',
                'manage_table',
                'recalculate_table',
                'manage_statistics',
                'manage_discipline',
                'manage_suspensions',
                'manage_protests',
                'decide_protests',
                'manage_awards',
                'manage_media',
                'publish_news',
                'manage_transfers',
                'approve_transfers',
                'view_reports',
                'export_reports',
            ],
            'Club Admin' => ['view_dashboard', 'manage_clubs', 'manage_players', 'manage_club_staff', 'manage_transfers', 'manage_match_preparation'],
            'Coach' => ['view_dashboard', 'manage_match_preparation'],
            'Match Commissioner' => ['view_dashboard', 'submit_results', 'verify_player_licenses'],
            'Referee Coordinator' => ['view_dashboard', 'manage_referees', 'assign_referees', 'manage_fixtures', 'verify_player_licenses'],
            'Finance Officer' => ['view_dashboard', 'manage_finance', 'record_payments', 'view_reports', 'export_reports'],
            'Media Officer' => ['view_dashboard', 'manage_media', 'publish_news'],
            'Viewer' => ['view_dashboard', 'view_reports'],
        ],
        'settings' => [
            'league_name' => 'JLFC - Jalingo Local Football Council',
            'league_short_name' => 'JLFC',
            'league_logo' => '',
            'organization_name' => 'Jalingo Local Football Council',
            'contact_email' => 'admin@jlfc.com',
            'contact_phone' => '+2340000000000',
            'primary_color' => 'dark green',
            'accent_color' => 'gold',
            'season_mode' => 'single',
            'points_win' => '3',
            'points_draw' => '1',
            'points_loss' => '0',
            'yellow_card_suspension_threshold' => '5',
            'red_card_suspension_default' => '1',
            'protest_deadline_hours' => '48',
            'require_payment_before_approval' => '0',
            'enable_public_registration' => '0',
            'enable_multiple_active_seasons' => '0',
            'enable_match_update_drafts' => '1',
            'verified_match_report_mode' => 'published',
        ],
        'default_admin' => [
            'full_name' => 'JLFC Super Administrator',
            'email' => 'admin@jlfc.com',
            'phone' => '+2340000000000',
            'password_hash' => '$2y$10$VUHzXqRa66/kBfm6okdu2e7yesz1B0TYFrqYPA2.ZKCGkBZEOxh7W',
            'role_name' => 'Super Admin',
            'status' => 'active',
        ],
    ];
}

function jlfc_count_matches(\PDO $pdo, string $table, string $column, array $values): int
{
    if ($values === []) {
        return 0;
    }

    $placeholders = implode(',', array_fill(0, count($values), '?'));
    $statement = $pdo->prepare(sprintf('SELECT COUNT(*) FROM `%s` WHERE `%s` IN (%s)', $table, $column, $placeholders));
    $statement->execute(array_values($values));

    return (int) $statement->fetchColumn();
}

function jlfc_count_expected_role_permissions(\PDO $pdo, array $rolePermissions): int
{
    $conditions = [];
    $params = [];

    foreach ($rolePermissions as $roleName => $permissionKeys) {
        foreach ($permissionKeys as $permissionKey) {
            $conditions[] = '(r.name = ? AND p.permission_key = ?)';
            $params[] = $roleName;
            $params[] = $permissionKey;
        }
    }

    if ($conditions === []) {
        return 0;
    }

    $statement = $pdo->prepare(
        'SELECT COUNT(*)
         FROM role_permissions rp
         INNER JOIN roles r ON r.id = rp.role_id
         INNER JOIN permissions p ON p.id = rp.permission_id
         WHERE ' . implode(' OR ', $conditions)
    );
    $statement->execute($params);

    return (int) $statement->fetchColumn();
}

function jlfc_seed_state_is_complete(\PDO $pdo): bool
{
    $seed = jlfc_seed_payload();
    $expectedRolePermissionCount = array_sum(array_map('count', $seed['role_permissions']));

    try {
        return jlfc_count_matches($pdo, 'roles', 'name', array_keys($seed['roles'])) === count($seed['roles'])
            && jlfc_count_matches($pdo, 'permissions', 'permission_key', array_keys($seed['permissions'])) === count($seed['permissions'])
            && jlfc_count_matches($pdo, 'system_settings', 'setting_key', array_keys($seed['settings'])) === count($seed['settings'])
            && jlfc_count_expected_role_permissions($pdo, $seed['role_permissions']) === $expectedRolePermissionCount
            && (int) db_fetch_value('SELECT COUNT(*) FROM users WHERE email = :email', ['email' => $seed['default_admin']['email']], 0) > 0;
    } catch (\Throwable) {
        return false;
    }
}

function jlfc_ensure_seed_data(\PDO $pdo): void
{
    static $seedChecked = false;

    if ($seedChecked) {
        return;
    }

    $seedChecked = true;

    if (jlfc_seed_state_is_complete($pdo)) {
        return;
    }

    $seed = jlfc_seed_payload();
    $startedTransaction = false;

    try {
        if (!$pdo->inTransaction()) {
            $pdo->beginTransaction();
            $startedTransaction = true;
        }

        $roleStatement = $pdo->prepare(
            'INSERT INTO roles (name, description)
             VALUES (:name, :description)
             ON DUPLICATE KEY UPDATE description = VALUES(description)'
        );
        foreach ($seed['roles'] as $name => $description) {
            $roleStatement->execute([
                'name' => $name,
                'description' => $description,
            ]);
        }

        $permissionStatement = $pdo->prepare(
            'INSERT INTO permissions (permission_key, permission_name, module_name)
             VALUES (:permission_key, :permission_name, :module_name)
             ON DUPLICATE KEY UPDATE
                 permission_name = VALUES(permission_name),
                 module_name = VALUES(module_name)'
        );
        foreach ($seed['permissions'] as $permissionKey => $permissionMeta) {
            $permissionStatement->execute([
                'permission_key' => $permissionKey,
                'permission_name' => $permissionMeta['name'],
                'module_name' => $permissionMeta['module'],
            ]);
        }

        $rolePermissionStatement = $pdo->prepare(
            'INSERT IGNORE INTO role_permissions (role_id, permission_id)
             SELECT r.id, p.id
             FROM roles r
             INNER JOIN permissions p ON p.permission_key = :permission_key
             WHERE r.name = :role_name'
        );
        foreach ($seed['role_permissions'] as $roleName => $permissionKeys) {
            foreach ($permissionKeys as $permissionKey) {
                $rolePermissionStatement->execute([
                    'role_name' => $roleName,
                    'permission_key' => $permissionKey,
                ]);
            }
        }

        $settingStatement = $pdo->prepare(
            'INSERT INTO system_settings (setting_key, setting_value)
             VALUES (:setting_key, :setting_value)
             ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)'
        );
        foreach ($seed['settings'] as $settingKey => $settingValue) {
            $settingStatement->execute([
                'setting_key' => $settingKey,
                'setting_value' => $settingValue,
            ]);
        }

        $adminExistsStatement = $pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1');
        $adminExistsStatement->execute(['email' => $seed['default_admin']['email']]);
        $adminExists = $adminExistsStatement->fetchColumn();

        if ($adminExists === false) {
            $roleIdStatement = $pdo->prepare('SELECT id FROM roles WHERE name = :name LIMIT 1');
            $roleIdStatement->execute(['name' => $seed['default_admin']['role_name']]);
            $roleId = (int) $roleIdStatement->fetchColumn();

            if ($roleId > 0) {
                $createAdminStatement = $pdo->prepare(
                    'INSERT INTO users (full_name, email, phone, password_hash, role_id, club_id, status, created_at, updated_at)
                     VALUES (:full_name, :email, :phone, :password_hash, :role_id, NULL, :status, NOW(), NOW())'
                );
                $createAdminStatement->execute([
                    'full_name' => $seed['default_admin']['full_name'],
                    'email' => $seed['default_admin']['email'],
                    'phone' => $seed['default_admin']['phone'],
                    'password_hash' => $seed['default_admin']['password_hash'],
                    'role_id' => $roleId,
                    'status' => $seed['default_admin']['status'],
                ]);
            }
        }

        if ($startedTransaction) {
            $pdo->commit();
        }
    } catch (\Throwable) {
        if ($startedTransaction && $pdo->inTransaction()) {
            $pdo->rollBack();
        }
    }
}

function db(): \PDO
{
    static $pdo = null;

    if ($pdo instanceof \PDO) {
        return $pdo;
    }

    $config = config('database');
    $dsn = sprintf(
        'mysql:host=%s;dbname=%s;charset=%s',
        $config['host'],
        $config['database'],
        $config['charset']
    );

    try {
        $pdo = new \PDO($dsn, $config['username'], $config['password'], [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
            \PDO::ATTR_EMULATE_PREPARES => false,
        ]);
    } catch (\PDOException $exception) {
        http_response_code(500);
        exit('Database connection failed. Check silkhea2_jlfc import and credentials.');
    }

    jlfc_ensure_seed_data($pdo);

    return $pdo;
}

function db_query(string $sql, array $params = []): \PDOStatement
{
    $statement = db()->prepare($sql);
    $statement->execute($params);
    return $statement;
}

function db_fetch_one(string $sql, array $params = []): ?array
{
    $record = db_query($sql, $params)->fetch();
    return $record === false ? null : $record;
}

function db_fetch_all(string $sql, array $params = []): array
{
    return db_query($sql, $params)->fetchAll();
}

function db_fetch_value(string $sql, array $params = [], mixed $default = 0): mixed
{
    $value = db_query($sql, $params)->fetchColumn();
    return $value === false ? $default : $value;
}

function site_setting(string $key, mixed $default = null): mixed
{
    static $settings = null;

    if ($settings === null) {
        $settings = [];

        try {
            foreach (db_fetch_all('SELECT setting_key, setting_value FROM system_settings') as $row) {
                $settings[$row['setting_key']] = $row['setting_value'];
            }
        } catch (Throwable) {
            $settings = [];
        }
    }

    return $settings[$key] ?? $default;
}

function league_name(): string
{
    return (string) site_setting('league_name', config('app.name', 'JLFC'));
}

function league_short_name(): string
{
    return (string) site_setting('league_short_name', config('app.short_name', 'JLFC'));
}

function league_logo_path(): ?string
{
    $logoPath = trim((string) site_setting('league_logo', ''));
    return $logoPath !== '' ? $logoPath : null;
}

function organization_name(): string
{
    return (string) site_setting('organization_name', config('app.organization_name', 'Jalingo Local Football Council'));
}

function current_path(): string
{
    return trim((string) parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH), '/');
}

function is_active_route(array|string $paths): string
{
    $current = current_path();
    $paths = (array) $paths;

    foreach ($paths as $path) {
        $expected = trim((string) parse_url(base_url($path), PHP_URL_PATH), '/');
        if ($current === $expected) {
            return 'active';
        }
    }

    return '';
}

function user_club_id(): ?int
{
    $clubId = $_SESSION['user_club_id'] ?? null;
    return $clubId === null ? null : (int) $clubId;
}

function abort_request(int $statusCode, string $title, string $message): never
{
    http_response_code($statusCode);
?>
    <!doctype html>
    <html lang="en">

    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=0.4">
        <title><?php echo e($title); ?> - <?php echo e(league_short_name()); ?></title>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
        <link href="<?php echo e(asset_url('css/app.css')); ?>" rel="stylesheet">
    </head>

    <body class="error-body">
        <div class="container py-5">
            <div class="error-card mx-auto">
                <span class="error-code"><?php echo e((string) $statusCode); ?></span>
                <h1 class="h3 fw-bold mb-3"><?php echo e($title); ?></h1>
                <p class="text-muted mb-4"><?php echo e($message); ?></p>
                <a class="btn btn-jlfc" href="<?php echo e(base_url('dashboard.php')); ?>">Return to dashboard</a>
            </div>
        </div>
    </body>

    </html>
<?php
    exit;
}
