<?php
/*
 * tools/i18n_collect_keys.php
 *
 * Sammelt alle verwendeten Übersetzungs-Keys aus:
 *  - /public/landingpage/{*}/{*}
 *  - /partials/landing/{*}/{*}
 *  - /partials/structure/{*}.php
 *  - (optional) /partials/partials/{*}/{*}, falls vorhanden
 *
 * und trägt fehlende Keys in public/assets/i18n/de.json ein.
 *
 * WICHTIG (angepasst):
 *  - partials/structure/{name}.php wird jetzt unter
 *    partials.structure.{name}.{key}
 *    abgelegt (nicht mehr im Root).
 *  - meta-Keys werden in jedem Block an erste Stelle gesetzt.
 *
 * Aufruf:
 *  - CLI:   php tools/i18n_collect_keys.php
 *  - HTTP:  https://.../tools/i18n_collect_keys.php
 */

declare(strict_types=1);

$baseDir = dirname(__DIR__);
$deJson  = $baseDir . '/public/assets/i18n/de.json';

// -------------------------------
// 1) Bestehende de.json laden
// -------------------------------
if (!is_file($deJson)) {
    die("de.json nicht gefunden unter: $deJson\n");
}

$raw = file_get_contents($deJson);
if ($raw === false) {
    die("Konnte de.json nicht lesen: $deJson\n");
}

$data = json_decode($raw, true);
if (!is_array($data)) {
    die("Ungültiges JSON in de.json\n");
}

if (!isset($data['meta']) || !is_array($data['meta'])) {
    $data['meta'] = [
        'code'  => 'de',
        'label' => 'Deutsch',
        'flag'  => '🇩🇪',
    ];
}

// -------------------------------
// 2) Verzeichnisse zum Scannen
// -------------------------------
$scanDirs = [
    $baseDir . '/public/landingpage',
    $baseDir . '/partials/landing',
    $baseDir . '/partials/structure',
    $baseDir . '/partials/partials',   // nur, falls vorhanden
];

$allowedExtensions = ['php', 'html', 'htm'];

// -------------------------------
// 3) Helper-Funktionen
// -------------------------------

function dotKeyExists(array $data, string $key): bool
{
    $segments = explode('.', $key);
    $node     = $data;

    foreach ($segments as $seg) {
        if (!is_array($node) || !array_key_exists($seg, $node)) {
            return false;
        }
        $node = $node[$seg];
    }
    return true;
}

function addDotKey(array &$data, string $key, string $default = ''): void
{
    if (dotKeyExists($data, $key)) {
        return;
    }

    $segments = explode('.', $key);
    $node =& $data;

    $last = array_pop($segments);
    foreach ($segments as $seg) {
        if (!isset($node[$seg]) || !is_array($node[$seg])) {
            $node[$seg] = [];
        }
        $node =& $node[$seg];
    }

    if (!array_key_exists($last, $node)) {
        $node[$last] = $default;
    }
}

function simpleKeyExistsRecursive(array $data, string $key): bool
{
    foreach ($data as $k => $v) {
        if ($k === $key) {
            return true;
        }
        if (is_array($v) && simpleKeyExistsRecursive($v, $key)) {
            return true;
        }
    }
    return false;
}

/**
 * Fügt einen einfachen Key irgendwo in der Struktur ein
 * (früher unter $data['auto'], jetzt nur noch für Reste).
 *
 * WICHTIG: $defaultValue ist explizit nullable → keine Deprecation.
 */
function addSimpleKey(array &$data, string $key, ?string $defaultValue = null): void
{
    if (simpleKeyExistsRecursive($data, $key)) {
        return;
    }

    if (!isset($data['auto']) || !is_array($data['auto'])) {
        $data['auto'] = [];
    }

    if ($defaultValue === null || $defaultValue === '') {
        $defaultValue = $key;
    }

    if (!array_key_exists($key, $data['auto'])) {
        $data['auto'][$key] = $defaultValue;
    }
}

/**
 * Key einfügen, mit optionalem Default-Text.
 * Dot-Notation → verschachtelt,
 * Simple-Key   → (Rest) unter "auto".
 *
 * Dynamische Keys mit $ (z.B. pages.$pageKey.meta.title) werden ignoriert.
 */
function addKeyToData(array &$data, string $key, ?string $defaultValue = null): void
{
    $key = trim($key);
    if ($key === '') {
        return;
    }

    // Dynamische Keys mit Variablen wie pages.$pageKey.meta.title ignorieren
    if (strpos($key, '$') !== false) {
        return;
    }

    $default = ($defaultValue !== null && $defaultValue !== '')
        ? $defaultValue
        : $key;

    if (strpos($key, '.') !== false) {
        addDotKey($data, $key, $default);
    } else {
        addSimpleKey($data, $key, $default);
    }
}

/**
 * Extrahiert den „aktuellen Inhalt“ eines data-i18n-Elements
 * grob über Regex:
 *   ... data-i18n="key"> Inhalt </...
 * Ist nur ein Best-Effort; bei komplexeren Strukturen fällt es auf null zurück.
 */
function extractInlineTextForDataI18n(string $content, int $matchOffset, int $matchLength): ?string
{
    $start = $matchOffset + $matchLength;
    $gtPos = strpos($content, '>', $start);
    if ($gtPos === false) {
        return null;
    }

    $closePos = strpos($content, '<', $gtPos + 1);
    if ($closePos === false) {
        return null;
    }

    $inner = substr($content, $gtPos + 1, $closePos - $gtPos - 1);
    $inner = trim($inner);

    if ($inner === '') {
        return null;
    }

    // Ganz grob Tags entfernen
    $inner = strip_tags($inner);
    $inner = trim($inner);

    return $inner !== '' ? $inner : null;
}

/**
 * Scannt eine Datei nach i18n-Keys und möglichen Default-Texten.
 *
 * Rückgabe:
 *   [ 'key1' => 'Default-Text oder null', 'key2' => null, ... ]
 *
 * Dynamische Keys mit $ (pages.$pageKey...) werden bereits hier
 * ignoriert.
 */
function collectKeysFromFile(string $file): array
{
    $content = file_get_contents($file);
    if ($content === false || $content === '') {
        return [];
    }

    $keysWithDefaults = [];

    // --- data-i18n="key" / 'key' ---
    if (preg_match_all('/data-i18n\s*=\s*(["\'])(.+?)\1/i', $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
        foreach ($matches as $m) {
            $fullMatch   = $m[0][0];
            $fullOffset  = $m[0][1];
            $key         = trim($m[2][0]);

            if (strpos($key, '$') !== false) {
                continue;
            }

            // Versuche, den Inline-Text zu extrahieren: >Text<
            $inlineText = extractInlineTextForDataI18n($content, $fullOffset, strlen($fullMatch));

            if (!array_key_exists($key, $keysWithDefaults)) {
                $keysWithDefaults[$key] = $inlineText;
            } elseif ($keysWithDefaults[$key] === null && $inlineText !== null) {
                // Falls wir bisher keinen Default hatten, aber jetzt einen finden:
                $keysWithDefaults[$key] = $inlineText;
            }
        }
    }

    // --- i18n_get('path.to.key', 'Default') ---
    if (preg_match_all(
        '/\bi18n_get\s*\(\s*(["\'])([^"\']+)\1\s*(,\s*(["\'])(.*?)\4)?/i',
        $content,
        $m2,
        PREG_SET_ORDER
    )) {
        foreach ($m2 as $match) {
            $key = trim($match[2]);

            if (strpos($key, '$') !== false) {
                continue;
            }

            $default = isset($match[5]) ? trim($match[5]) : null;

            if ($default !== null && $default !== '') {
                // expliziter Default im PHP-Code → höchste Priorität
                $keysWithDefaults[$key] = $default;
            } else {
                if (!array_key_exists($key, $keysWithDefaults)) {
                    $keysWithDefaults[$key] = null;
                }
            }
        }
    }

    // --- i18n_get_fmt("path.to.key", "Default", ...) ---
    if (preg_match_all(
        '/\bi18n_get_fmt\s*\(\s*(["\'])([^"\']+)\1\s*(,\s*(["\'])(.*?)\4)?/i',
        $content,
        $m3,
        PREG_SET_ORDER
    )) {
        foreach ($m3 as $match) {
            $key = trim($match[2]);

            if (strpos($key, '$') !== false) {
                continue;
            }

            $default = isset($match[5]) ? trim($match[5]) : null;

            if ($default !== null && $default !== '') {
                $keysWithDefaults[$key] = $default;
            } else {
                if (!array_key_exists($key, $keysWithDefaults)) {
                    $keysWithDefaults[$key] = null;
                }
            }
        }
    }

    return $keysWithDefaults;
}

// -------------------------------
// 4) Dateien durchlaufen & Keys sammeln
// -------------------------------
$foundKeys = []; // key => defaultText|null

foreach ($scanDirs as $dir) {
    if (!is_dir($dir)) {
        continue;
    }

    $it = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
    );

    foreach ($it as $fileInfo) {
        /** @var SplFileInfo $fileInfo */
        if (!$fileInfo->isFile()) {
            continue;
        }

        $ext = strtolower($fileInfo->getExtension());
        if (!in_array($ext, $allowedExtensions, true)) {
            continue;
        }

        $filePath = $fileInfo->getPathname();
        $relPath  = str_replace($baseDir . DIRECTORY_SEPARATOR, '', $filePath);

        $keysInFile = collectKeysFromFile($filePath);

        foreach ($keysInFile as $key => $defaultText) {
            $origKey = $key;

            // Nur für einfache Keys (ohne Punkt) Kontext-basiert umschreiben
            if (strpos($key, '.') === false) {

                // 4a) partials/landing/{slug}/{section}.php
                if (preg_match('~^partials/landing/([^/]+)/([^/]+)\.(php|html?|phtml)$~', $relPath, $m)) {
                    $slug    = $m[1]; // z.B. landing, fakecheck, login, dashboard
                    $section = $m[2]; // z.B. hero, how, problem, features, security, faq, main

                    $key = "pages.$slug.sections.$section.$key";

                // 4b) public/landingpage/{slug}/*.php → Fallback: section "main"
                } elseif (preg_match('~^public/landingpage/([^/]+)/.+\.(php|html?|phtml)$~', $relPath, $m)) {
                    $slug = $m[1]; // z.B. landing, fakecheck, login, dashboard

                    $key = "pages.$slug.sections.main.$key";

                // 4c) partials/structure/{name}.php → z.B. header.*, footer.*, layout_*
                } elseif (preg_match('~^partials/structure/([^/]+)\.(php|html?|phtml)$~', $relPath, $m)) {
                    $section = $m[1]; // header, footer, layout_start, layout_end, app_config, ...

                    // NEU: unter partials.structure.{section}.{key}
                    $key = "partials.structure.$section.$key";
                }
            }

            // Gefilterten Key übernehmen
            if (!array_key_exists($key, $foundKeys)) {
                $foundKeys[$key] = $defaultText;
            } else {
                // Wenn wir bisher keinen Default hatten, aber jetzt einen haben → übernehmen
                if (($foundKeys[$key] === null || $foundKeys[$key] === '')
                    && $defaultText !== null
                    && $defaultText !== ''
                ) {
                    $foundKeys[$key] = $defaultText;
                }
            }
        }
    }
}

// -------------------------------
// 5) Gefundene Keys in de.json eintragen
// -------------------------------
$addedCount   = 0;
$skippedCount = 0;
$newKeys      = [];

foreach ($foundKeys as $key => $defaultText) {
    $before = json_encode($data);
    addKeyToData($data, $key, $defaultText);
    $after  = json_encode($data);

    if ($before === $after) {
        $skippedCount++;
    } else {
        $addedCount++;
        $newKeys[] = $key;
    }
}

// -------------------------------
// 5b) Metadaten für alle Landingpages ergänzen
//     /public/landingpage/{slug}/ → pages.{slug}.meta.{title,description}
// -------------------------------
$landingRoot = $baseDir . '/public/landingpage';
if (is_dir($landingRoot)) {
    foreach (new DirectoryIterator($landingRoot) as $entry) {
        if ($entry->isDot() || !$entry->isDir()) {
            continue;
        }

        $slug = $entry->getFilename();

        // einfache Heuristik: Landingpage gilt als "aktiv", wenn irgendeine .php drin liegt
        $hasPhp = false;
        foreach (new DirectoryIterator($entry->getPathname()) as $file) {
            if ($file->isFile() && strtolower($file->getExtension()) === 'php') {
                $hasPhp = true;
                break;
            }
        }
        if (!$hasPhp) {
            continue;
        }

        $titleKey = "pages.$slug.meta.title";
        $descKey  = "pages.$slug.meta.description";

        if (!dotKeyExists($data, $titleKey)) {
            $defaultTitle = '{{primary_domain}} – ' . ucfirst($slug);
            addDotKey($data, $titleKey, $defaultTitle);
            $newKeys[] = $titleKey;
            $addedCount++;
        }

        if (!dotKeyExists($data, $descKey)) {
            $defaultDesc = 'Beschreibung für ' . ucfirst($slug) . ' auf {{primary_domain}}';
            addDotKey($data, $descKey, $defaultDesc);
            $newKeys[] = $descKey;
            $addedCount++;
        }
    }
}

// -------------------------------
// 5c) meta-Keys in jedem Block nach vorne ziehen
// -------------------------------
function reorderMetaFirstRecursive(array &$node): void
{
    // Zuerst rekursiv in die Tiefe gehen
    foreach ($node as $k => &$v) {
        if (is_array($v)) {
            reorderMetaFirstRecursive($v);
        }
    }
    unset($v);

    // Wenn es in diesem Block einen 'meta'-Key gibt, diesen an erste Stelle setzen
    if (array_key_exists('meta', $node) && count($node) > 1) {
        $metaValue = $node['meta'];
        unset($node['meta']);

        // Rest in aktueller Reihenfolge behalten
        $rest = $node;

        // Neu zusammensetzen: meta zuerst
        $node = ['meta' => $metaValue] + $rest;
    }
}

reorderMetaFirstRecursive($data);

// -------------------------------
// 6) de.json zurückschreiben
// -------------------------------
$newJson = json_encode(
    $data,
    JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);

if ($newJson === false) {
    die("Fehler beim JSON-Encode von de.json\n");
}

if (file_put_contents($deJson, $newJson) === false) {
    die("Konnte de.json nicht schreiben: $deJson\n");
}

// -------------------------------
// 7) Ausgabe
// -------------------------------
$isCli = (php_sapi_name() === 'cli');

$output  = "i18n-Collect abgeschlossen.\n";
$output .= "Gefundene Keys gesamt: " . count($foundKeys) . "\n";
$output .= "Neu hinzugefügt:       " . $addedCount . "\n";
$output .= "Übersprungen (bereits vorhanden): $skippedCount\n";
$output .= "Datei aktualisiert:    $deJson\n";

if (!empty($newKeys)) {
    $output .= "\nNeu angelegte Keys:\n";
    foreach ($newKeys as $k) {
        $output .= "  - " . $k . "\n";
    }
}

if ($isCli) {
    echo $output;
} else {
    if (!headers_sent()) {
        header('Content-Type: text/plain; charset=utf-8');
    }
    echo $output;
}
