<?php

declare(strict_types=1);

/**
 * Config-Wert holen: config('smtp.host') oder config() für das ganze Array.
 */
function config(?string $key = null, mixed $default = null): mixed
{
    $value = $GLOBALS['__config'];
    if ($key === null) {
        return $value;
    }
    foreach (explode('.', $key) as $part) {
        if (!is_array($value) || !array_key_exists($part, $value)) {
            return $default;
        }
        $value = $value[$part];
    }
    return $value;
}

/**
 * HTML-Escaping — für JEDE dynamische Ausgabe verwenden.
 */
function e(string|int|float|null $value): string
{
    return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8');
}

/**
 * Interner Link aus Slug: url('fussball') → '/fussball', url('') → '/'.
 */
function url(string $slug = ''): string
{
    return '/' . trim($slug, '/');
}

/**
 * Absolute URL für Canonical, OG und Sitemap.
 */
function abs_url(string $slug = ''): string
{
    return rtrim((string) config('base_url'), '/') . url($slug);
}

/**
 * Asset-Pfad mit Cache-Busting über filemtime: asset('css/tokens.css').
 */
function asset(string $path): string
{
    $path = ltrim($path, '/');
    $file = PUBLIC_PATH . '/assets/' . $path;
    $version = is_file($file) ? (string) filemtime($file) : '0';
    return '/assets/' . $path . '?v=' . $version;
}

/**
 * JSON-Datendatei laden (data/<name>.json) mit Request-weitem Cache.
 * Wirft bei kaputtem JSON — Datenfehler sollen laut scheitern, nicht leise.
 */
function json_load(string $name): array
{
    static $cache = [];
    if (!array_key_exists($name, $cache)) {
        $file = DATA_PATH . '/' . $name . '.json';
        if (!is_file($file)) {
            return [];
        }
        $cache[$name] = json_decode((string) file_get_contents($file), true, 512, JSON_THROW_ON_ERROR);
    }
    return $cache[$name];
}

/**
 * Komponente rendern: component('hero', ['title' => …]).
 * Props werden als lokale Variablen extrahiert; Komponenten sind dumme Includes.
 */
function component(string $name, array $props = []): void
{
    extract($props, EXTR_SKIP);
    require APP_PATH . '/components/' . $name . '.php';
}

/**
 * Page-Datei ausführen: sie setzt $meta und emittiert ihren Body.
 * Rückgabe: [$meta, $html].
 */
function render_page(string $file): array
{
    $meta = [];
    ob_start();
    require $file;
    return [$meta, (string) ob_get_clean()];
}

/**
 * Signierten Zeitstempel für die Formular-Time-Trap erzeugen.
 */
function form_token(): string
{
    $ts = (string) time();
    return $ts . '.' . hash_hmac('sha256', $ts, (string) config('app_secret'));
}

/**
 * Time-Trap prüfen: Signatur gültig, älter als $min Sekunden, jünger als $max.
 */
function form_token_valid(string $token, int $min = 3, int $max = 7200): bool
{
    $parts = explode('.', $token);
    if (count($parts) !== 2) {
        return false;
    }
    [$ts, $sig] = $parts;
    if (!hash_equals(hash_hmac('sha256', $ts, (string) config('app_secret')), $sig)) {
        return false;
    }
    $age = time() - (int) $ts;
    return $age >= $min && $age <= $max;
}
