<?php

declare(strict_types=1);

use Core\App;
use Core\Database;
use Core\MigrationManager;
use Core\Response;
use Core\View;

function app(): App
{
    static $app = null;

    if ($app === null) {
        $app = new App();
    }

    return $app;
}

function view(string $view, array $data = []): Response
{
    return View::render($view, $data);
}

function redirect(string $url): Response
{
    return Response::redirect($url);
}

function database(): Database
{
    static $database = null;

    if ($database === null) {
        /** @var array<string, mixed> $config */
        $config = require __DIR__ . '/../config/database.php';

        prepareSqliteDatabase($config['dsn'] ?? '');

        $database = new Database($config);
    }

    return $database;
}

function migration_manager(): MigrationManager
{
    static $migrationManager = null;

    if ($migrationManager === null) {
        $migrationManager = new MigrationManager(database(), __DIR__ . '/../database/migrations');
    }

    return $migrationManager;
}

function ensureSessionStarted(): void
{
    if (session_status() === PHP_SESSION_NONE) {
        session_start();
    }
}

function prepareSqliteDatabase(string $dsn): void
{
    if (!str_starts_with($dsn, 'sqlite:')) {
        return;
    }

    $path = substr($dsn, 7);

    if ($path === false || $path === '') {
        return;
    }

    $directory = dirname($path);

    if (!is_dir($directory)) {
        mkdir($directory, 0777, true);
    }

    if (!is_writable($directory)) {
        @chmod($directory, 0777);
    }

    if (!file_exists($path)) {
        touch($path);
    }

    if (!is_writable($path)) {
        @chmod($path, 0666);
    }
}

if (!function_exists('e')) {
    function e(?string $value): string
    {
        return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }
}

function asset(string $path): string
{
    return '/' . ltrim($path, '/');
}

function csrf_token(): string
{
    ensureSessionStarted();

    if (!isset($_SESSION['_csrf_token']) || !is_string($_SESSION['_csrf_token'])) {
        $_SESSION['_csrf_token'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['_csrf_token'];
}

function csrf_field(): string
{
    return '<input type="hidden" name="_token" value="' . e(csrf_token()) . '">';
}

function verify_csrf_token(?string $token): bool
{
    ensureSessionStarted();

    if (!is_string($token) || $token === '') {
        return false;
    }

    $sessionToken = $_SESSION['_csrf_token'] ?? null;

    return is_string($sessionToken) && hash_equals($sessionToken, $token);
}

function flash(string $key, string $message): void
{
    ensureSessionStarted();
    $_SESSION['_flash'][$key] = $message;
}

function flash_get(string $key): ?string
{
    ensureSessionStarted();
    $value = $_SESSION['_flash'][$key] ?? null;
    unset($_SESSION['_flash'][$key]);
    return is_string($value) ? $value : null;
}

function paginate_url(int $page, array $merge = []): string
{
    $params = array_merge($_GET, $merge, ['page' => $page]);
    $params = array_filter($params, fn($v) => $v !== '' && $v !== null);
    return '?' . http_build_query($params);
}

function maps_config(): array
{
    static $config = null;
    if ($config === null) {
        $config = require __DIR__ . '/../config/maps.php';
    }
    return $config;
}
