<?php
declare(strict_types=1);

use App\Support\View;

function config(?string $key = null, mixed $default = null): mixed
{
    static $config;

    if ($config === null) {
        $config = require BASE_PATH . '/config/app.php';
    }

    if ($key === null) {
        return $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 translations(): array
{
    static $translations;

    if ($translations === null) {
        $translations = require BASE_PATH . '/config/translations.php';
    }

    return $translations;
}

function supported_languages(): array
{
    return (array) config('supported_languages', []);
}

function normalize_locale(?string $locale, ?string $fallback = null): string
{
    $fallback ??= (string) config('default_language', 'en');
    $locale = trim((string) $locale);

    return array_key_exists($locale, supported_languages()) ? $locale : $fallback;
}

function locale_scope(?string $path = null): string
{
    $path ??= request_path();

    return str_starts_with($path, '/admin') ? 'admin' : 'participant';
}

function set_ui_locale(?string $locale, ?string $scope = null): void
{
    $scope ??= locale_scope();
    $_SESSION['_ui_locale'][$scope] = normalize_locale($locale);
}

function current_locale(): string
{
    $scope = locale_scope();
    $queryLocale = trim((string) ($_GET['lang'] ?? ''));

    if (array_key_exists($queryLocale, supported_languages())) {
        set_ui_locale($queryLocale, $scope);
        return $queryLocale;
    }

    $storedLocale = $_SESSION['_ui_locale'][$scope] ?? null;

    if (is_string($storedLocale) && array_key_exists($storedLocale, supported_languages())) {
        return $storedLocale;
    }

    if ($scope === 'participant') {
        $participantLocale = $_SESSION['participant_test']['participant']['language']
            ?? $_SESSION['participant_report']['participant']['language']
            ?? old('language', '');

        if (array_key_exists((string) $participantLocale, supported_languages())) {
            return (string) $participantLocale;
        }
    }

    return normalize_locale(is_string($storedLocale) ? $storedLocale : null);
}

function trans(string $key, array $replace = [], ?string $locale = null): string
{
    $locale ??= current_locale();
    $catalog = translations();
    $segments = explode('.', $key);
    $value = $catalog[$locale] ?? [];

    foreach ($segments as $segment) {
        if (!is_array($value) || !array_key_exists($segment, $value)) {
            $value = null;
            break;
        }

        $value = $value[$segment];
    }

    if (!is_string($value)) {
        $value = $locale !== 'en' ? trans($key, $replace, 'en') : $key;
    }

    if ($replace === []) {
        return $value;
    }

    $formatted = [];

    foreach ($replace as $placeholder => $replacement) {
        $formatted[':' . $placeholder] = (string) $replacement;
    }

    return strtr($value, $formatted);
}

function trans_list(string $key, ?string $locale = null): array
{
    $locale ??= current_locale();
    $catalog = translations();
    $segments = explode('.', $key);
    $value = $catalog[$locale] ?? [];

    foreach ($segments as $segment) {
        if (!is_array($value) || !array_key_exists($segment, $value)) {
            $value = null;
            break;
        }

        $value = $value[$segment];
    }

    if (is_array($value)) {
        return $value;
    }

    return $locale !== 'en' ? trans_list($key, 'en') : [];
}

function area_name(string $areaCode, ?string $locale = null): string
{
    $fallback = (string) config('riasec_areas.' . $areaCode . '.name', $areaCode);
    $translated = trans('areas.' . $areaCode, [], $locale);

    return $translated === 'areas.' . $areaCode ? $fallback : $translated;
}

function current_query_params(array $exclude = []): array
{
    $params = $_GET;

    foreach ($exclude as $key) {
        unset($params[$key]);
    }

    return $params;
}

function locale_url(string $locale): string
{
    $params = array_merge(current_query_params(['lang']), ['lang' => normalize_locale($locale)]);
    $query = http_build_query($params);

    return base_url(request_path()) . ($query !== '' ? '?' . $query : '');
}

function js_value(mixed $value): string
{
    return (string) json_encode($value, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
}

function base_url(string $path = ''): string
{
    $basePath = app_base_path();
    $normalizedPath = '/' . ltrim($path, '/');

    return $basePath . ($path === '' ? '' : $normalizedPath);
}

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

function request_path(): string
{
    $uriPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
    $basePath = app_base_path();

    if ($basePath !== '' && str_starts_with($uriPath, $basePath)) {
        $uriPath = substr($uriPath, strlen($basePath));
    }

    return $uriPath === '' ? '/' : $uriPath;
}

function app_base_path(): string
{
    $configured = rtrim((string) config('base_path', ''), '/');
    $requestUri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';

    if ($configured !== '' && str_starts_with($requestUri, $configured)) {
        return $configured;
    }

    $scriptDirectory = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? ''));

    if ($scriptDirectory === '/' || $scriptDirectory === '\\') {
        return '';
    }

    return rtrim($scriptDirectory, '/');
}

function redirect(string $path): never
{
    header('Location: ' . base_url($path));
    exit;
}

function render(string $template, array $data = [], string $layout = 'main'): void
{
    View::render($template, $data, $layout);
}

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

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

function flash(string $key, ?string $value = null): ?string
{
    if ($value !== null) {
        $_SESSION['_flash'][$key] = $value;
        return null;
    }

    $message = $_SESSION['_flash'][$key] ?? null;

    if ($message !== null) {
        unset($_SESSION['_flash'][$key]);
    }

    return $message;
}

function set_old_input(array $input): void
{
    $_SESSION['_old'] = $input;
}

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

function csrf_token(): string
{
    if (!isset($_SESSION['_csrf'])) {
        $_SESSION['_csrf'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['_csrf'];
}

function verify_csrf(?string $token): bool
{
    $sessionToken = $_SESSION['_csrf'] ?? '';

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

function is_admin_authenticated(): bool
{
    return isset($_SESSION['admin_user']);
}

function require_admin(): void
{
    if (!is_admin_authenticated()) {
        flash('error', trans('alerts.admin_login_required', [], 'en'));
        redirect('/admin/login');
    }
}