<?php
declare(strict_types=1);

function app_config(): array
{
    static $config;
    if ($config === null) {
        $configPath = __DIR__ . '/../config/config.php';
        if (!file_exists($configPath)) {
            throw new RuntimeException('Config file missing.');
        }
        $config = require $configPath;
    }

    return $config;
}

function config(string $key, mixed $default = null): mixed
{
    $config = app_config();
    $segments = explode('.', $key);
    $value = $config;

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

    return $value;
}

function url_for(string $path = ''): string
{
    $base = resolve_base_url();
    $path = '/' . ltrim($path, '/');

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

    return rtrim($base, '/') . $path;
}

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

function resolve_base_url(): string
{
    static $base = null;
    if ($base !== null) {
        return $base;
    }

    $configured = config('app.base_url', '');
    if ($configured !== '') {
        if (!preg_match('#^https?://#i', $configured)) {
            $configured = '/' . ltrim($configured, '/');
        }
        $base = rtrim($configured, '/') ?: '/';

        return $base;
    }

    $documentRoot = $_SERVER['DOCUMENT_ROOT'] ?? '';
    $documentRoot = $documentRoot ? rtrim(normalize_path($documentRoot), '/') : '';
    $appRoot = rtrim(normalize_path(dirname(__DIR__)), '/');

    if ($documentRoot && strpos($appRoot, $documentRoot) === 0) {
        $relative = substr($appRoot, strlen($documentRoot));
        $relative = trim($relative, '/');
        $base = $relative === '' ? '' : '/' . $relative;
    } else {
        $base = '';
    }

    return $base;
}

function normalize_path(string $path): string
{
    $real = realpath($path);

    return str_replace('\\', '/', $real ?: $path);
}

function redirect(string $path): void
{
    if (preg_match('#^https?://#i', $path)) {
        $target = $path;
    } else {
        $target = url_for($path);
    }

    header('Location: ' . $target);
    exit;
}

function sanitize(?string $value, int $flags = ENT_QUOTES): string
{
    return htmlspecialchars((string) $value, $flags, 'UTF-8');
}

function add_flash(string $type, string $message): void
{
    $_SESSION['flash'][$type][] = $message;
}

function get_flashes(): array
{
    $messages = $_SESSION['flash'] ?? [];
    unset($_SESSION['flash']);

    return $messages;
}

function is_post(): bool
{
    return strtoupper($_SERVER['REQUEST_METHOD'] ?? '') === 'POST';
}

function random_token(int $bytes = 8): string
{
    return bin2hex(random_bytes($bytes));
}

function format_datetime(?string $value, string $format = 'M d, Y h:i A'): string
{
    if (!$value) {
        return '—';
    }
    $date = new DateTime($value);

    return $date->format($format);
}

function format_date(?string $value, string $format = 'M d, Y'): string
{
    if (!$value) {
        return '—';
    }
    $date = new DateTime($value);

    return $date->format($format);
}

function selected(mixed $current, mixed $value): string
{
    return (string) $current === (string) $value ? 'selected' : '';
}

function checked(bool $condition): string
{
    return $condition ? 'checked' : '';
}

function paginate(PDO $pdo, string $countSql, array $params = [], int $perPage = 10): array
{
    $page = max(1, (int) ($_GET['page'] ?? 1));
    $stmt = $pdo->prepare($countSql);
    $stmt->execute($params);
    $total = (int) $stmt->fetchColumn();
    $pages = max(1, (int) ceil($total / $perPage));
    $page = min($page, $pages);
    $offset = ($page - 1) * $perPage;

    return [
        'page' => $page,
        'per_page' => $perPage,
        'total' => $total,
        'pages' => $pages,
        'offset' => $offset,
    ];
}

function render_pagination(array $pagination, string $basePath = '', array $query = []): void
{
    if (($pagination['pages'] ?? 1) <= 1) {
        return;
    }

    $base = $basePath ?: parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    ?>
    <nav aria-label="Pagination" class="mt-4">
        <ul class="pagination">
            <?php for ($i = 1; $i <= $pagination['pages']; $i++): ?>
                <?php
                $queryString = http_build_query(array_merge($query, ['page' => $i]));
                $href = $base . '?' . $queryString;
                ?>
                <li class="page-item <?= $pagination['page'] === $i ? 'active' : '' ?>">
                    <a class="page-link" href="<?= sanitize($href) ?>"><?= $i ?></a>
                </li>
            <?php endfor; ?>
        </ul>
    </nav>
    <?php
}

function encode_record(array $record): string
{
    return base64_encode(json_encode($record, JSON_UNESCAPED_UNICODE));
}
function ensure_csrf_token(): string
{
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = random_token(16);
    }

    return $_SESSION['csrf_token'];
}

function validate_csrf_token(?string $token): bool
{
    return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], (string) $token);
}
