<?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;
}

/**
 * Bootstrap-Icon als Inline-SVG ausgeben (lokal aus public/assets/icons/<name>.svg).
 * Standard: dekorativ (aria-hidden). Mit $label wird es als beschriftetes Bild
 * (role="img") ausgegeben. Größe/Farbe steuert CSS über die Klasse .icon.
 * Quelle: Bootstrap Icons (MIT) — neue Icons via bin/icons-add.php hinzufügen.
 */
function icon(string $name, string $class = '', ?string $label = null): string
{
    static $cache = [];
    if (!array_key_exists($name, $cache)) {
        $file = PUBLIC_PATH . '/assets/icons/' . basename($name) . '.svg';
        $cache[$name] = is_file($file) ? trim((string) file_get_contents($file)) : '';
    }
    if ($cache[$name] === '') {
        return '';
    }
    $attrs = 'class="icon' . ($class !== '' ? ' ' . e($class) : '') . '"';
    $attrs .= $label !== null && $label !== ''
        ? ' role="img" aria-label="' . e($label) . '"'
        : ' aria-hidden="true" focusable="false"';

    return preg_replace('/<svg\b/', '<svg ' . $attrs, $cache[$name], 1);
}

/**
 * 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;
}

/**
 * BreadcrumbList-Knoten: $items = [['name'=>…, 'slug'=>…], …] (Reihenfolge = Pfad).
 */
function breadcrumb_schema(array $items): array
{
    $list = [];
    foreach (array_values($items) as $i => $item) {
        $list[] = [
            '@type'    => 'ListItem',
            'position' => $i + 1,
            'name'     => $item['name'],
            'item'     => abs_url($item['slug']),
        ];
    }
    return ['@type' => 'BreadcrumbList', 'itemListElement' => $list];
}

/**
 * FAQPage-Knoten aus [['q'=>…, 'a'=>…], …]. Leere Paare werden übersprungen;
 * ohne Fragen wird ein leerer Array zurückgegeben (Aufrufer filtert das raus).
 */
function faq_schema(array $faq): array
{
    $questions = [];
    foreach ($faq as $item) {
        if (empty($item['q']) || empty($item['a'])) {
            continue;
        }
        $questions[] = [
            '@type'          => 'Question',
            'name'           => $item['q'],
            'acceptedAnswer' => ['@type' => 'Answer', 'text' => $item['a']],
        ];
    }
    return $questions === [] ? [] : ['@type' => 'FAQPage', 'mainEntity' => $questions];
}

/**
 * Seiten-Schema-Knoten zusammenstellen (für $meta['schema']):
 * Breadcrumb + optional FAQPage. Generisch für Übersichts-/Jugendseiten.
 */
function page_schema(array $breadcrumb, array $faq = []): array
{
    $nodes = [];
    if ($breadcrumb !== []) {
        $nodes[] = breadcrumb_schema($breadcrumb);
    }
    if ($faq !== [] && ($faqNode = faq_schema($faq)) !== []) {
        $nodes[] = $faqNode;
    }
    return $nodes;
}

/**
 * Schema-Knoten für eine Mannschafts-Seite: SportsTeam (verweist auf den Club
 * via #club) + Breadcrump (Start → Fußball → Team) + optional FAQPage.
 * $team: Eintrag aus data/teams.json; $slug: voller Seiten-Slug.
 */
function team_schema(array $team, string $slug): array
{
    $teamNode = [
        '@type'    => 'SportsTeam',
        'name'     => $team['name'],
        'sport'    => 'Fußball',
        'url'      => abs_url($slug),
        'memberOf' => ['@id' => abs_url() . '#club'],
    ];
    if (!empty($team['hero']['text'])) {
        $teamNode['description'] = $team['hero']['text'];
    }

    $nodes = [$teamNode];
    $nodes = array_merge($nodes, page_schema(
        [
            ['name' => 'Startseite', 'slug' => ''],
            ['name' => 'Fußball', 'slug' => 'fussball'],
            ['name' => $team['name'], 'slug' => $slug],
        ],
        $team['faq'] ?? []
    ));
    return $nodes;
}
