<?php
declare(strict_types=1);

header('Content-Type: application/json; charset=utf-8');

const JSON_FLAGS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT;

function respond(array $payload, int $status = 200): void {
    http_response_code($status);
    echo json_encode($payload, JSON_FLAGS);
    exit;
}

function read_json(string $file): array {
    if (!is_file($file)) {
        return [];
    }
    $raw = file_get_contents($file);
    if ($raw === false) {
        return [];
    }
    $data = json_decode($raw, true);
    return is_array($data) ? $data : [];
}

function normalize_id(string $value): string {
    return preg_replace('/[^a-zA-Z0-9_-]/', '', $value) ?? '';
}

function normalize_exts($value, array $fallback): array {
    if (!is_array($value) || $value === []) {
        return $fallback;
    }
    $out = [];
    foreach ($value as $entry) {
        if (!is_string($entry)) {
            continue;
        }
        $ext = strtolower(trim($entry));
        $ext = ltrim($ext, '.');
        if ($ext !== '') {
            $out[] = $ext;
        }
    }
    return $out === [] ? $fallback : array_values(array_unique($out));
}

function starts_with(string $haystack, string $needle): bool {
    if ($needle === '') {
        return true;
    }
    return substr($haystack, 0, strlen($needle)) === $needle;
}

function safe_join(string $base, string $rel): ?string {
    $baseReal = realpath($base);
    if ($baseReal === false) {
        return null;
    }
    $combined = $rel;
    if (!preg_match('/^[a-zA-Z]:[\\\\\\/]/', $rel) && !starts_with($rel, '/')) {
        $combined = $baseReal . DIRECTORY_SEPARATOR . $rel;
    }
    $real = realpath($combined);
    if ($real === false) {
        return null;
    }
    return $real;
}

function is_inside(string $path, string $root): bool {
    $p = str_replace('\\', '/', $path);
    $r = rtrim(str_replace('\\', '/', $root), '/');
    return $p === $r || starts_with($p, $r . '/');
}

function to_web_path(string $absolutePath, string $projectRoot): string {
    $rel = ltrim(str_replace('\\', '/', substr($absolutePath, strlen($projectRoot))), '/');
    return './' . $rel;
}

function normalize_label(string $label): string {
    $label = preg_replace('/[\x00-\x1F\x7F]+/u', ' ', $label) ?? $label;
    $label = preg_replace('/\s+/u', ' ', $label) ?? $label;
    return trim($label);
}

function label_from_file(string $path): string {
    $name = pathinfo($path, PATHINFO_FILENAME);
    $name = str_replace(['_', '-', '.'], ' ', $name);
    return normalize_label($name);
}

function parse_bool($value, bool $fallback = false): bool {
    if (is_bool($value)) {
        return $value;
    }
    if (is_int($value) || is_float($value)) {
        return ((int)$value) !== 0;
    }
    if (is_string($value)) {
        $v = strtolower(trim($value));
        if (in_array($v, ['1', 'true', 'yes', 'on'], true)) {
            return true;
        }
        if (in_array($v, ['0', 'false', 'no', 'off'], true)) {
            return false;
        }
    }
    return $fallback;
}

function relative_path(string $path, string $base): string {
    $p = str_replace('\\', '/', $path);
    $b = rtrim(str_replace('\\', '/', $base), '/');
    if (starts_with($p, $b . '/')) {
        return substr($p, strlen($b) + 1);
    }
    return basename($p);
}

function decode_utf16le_title(string $raw): string {
    $clean = preg_replace('/\x00+$/', '', $raw) ?? $raw;
    if ($clean === '') {
        return '';
    }
    if (function_exists('mb_convert_encoding')) {
        $decoded = @mb_convert_encoding($clean, 'UTF-8', 'UTF-16LE');
        if (is_string($decoded)) {
            return normalize_label($decoded);
        }
    }
    if (function_exists('iconv')) {
        $decoded = @iconv('UTF-16LE', 'UTF-8//IGNORE', $clean);
        if (is_string($decoded)) {
            return normalize_label($decoded);
        }
    }
    return normalize_label(str_replace("\x00", '', $clean));
}

function extract_label_from_metadata(string $file): string {
    $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
    if (function_exists('exif_read_data') && in_array($ext, ['jpg', 'jpeg', 'tif', 'tiff'], true)) {
        $exif = @exif_read_data($file, null, true, false);
        if (is_array($exif)) {
            $candidates = [
                $exif['IFD0']['ImageDescription'] ?? '',
                $exif['IFD0']['Title'] ?? '',
                $exif['EXIF']['UserComment'] ?? ''
            ];
            foreach ($candidates as $cand) {
                if (is_string($cand) && normalize_label($cand) !== '') {
                    return normalize_label($cand);
                }
            }
            $xpTitle = $exif['IFD0']['XPTitle'] ?? '';
            if (is_string($xpTitle) && $xpTitle !== '') {
                $decoded = decode_utf16le_title($xpTitle);
                if ($decoded !== '') {
                    return $decoded;
                }
            }
        }
    }
    if (function_exists('getimagesize') && function_exists('iptcparse')) {
        $info = [];
        @getimagesize($file, $info);
        if (isset($info['APP13']) && is_string($info['APP13'])) {
            $iptc = @iptcparse($info['APP13']);
            if (is_array($iptc)) {
                $objectName = $iptc['2#005'][0] ?? '';
                if (is_string($objectName) && normalize_label($objectName) !== '') {
                    return normalize_label($objectName);
                }
                $caption = $iptc['2#120'][0] ?? '';
                if (is_string($caption) && normalize_label($caption) !== '') {
                    return normalize_label($caption);
                }
            }
        }
    }
    return '';
}

function extract_label_from_sidecar(string $file): string {
    $dir = dirname($file);
    $base = pathinfo($file, PATHINFO_FILENAME);
    $candidates = [
        $dir . DIRECTORY_SEPARATOR . $base . '.meta.json',
        $dir . DIRECTORY_SEPARATOR . $base . '.json'
    ];
    foreach ($candidates as $jsonFile) {
        $meta = read_json($jsonFile);
        if ($meta === []) {
            continue;
        }
        foreach (['label', 'title', 'name'] as $key) {
            if (isset($meta[$key]) && is_string($meta[$key]) && normalize_label($meta[$key]) !== '') {
                return normalize_label($meta[$key]);
            }
        }
    }
    return '';
}

function resolve_label(string $file, bool $useMetadata): string {
    $fromSidecar = extract_label_from_sidecar($file);
    if ($fromSidecar !== '') {
        return $fromSidecar;
    }
    if ($useMetadata) {
        $fromMeta = extract_label_from_metadata($file);
        if ($fromMeta !== '') {
            return $fromMeta;
        }
    }
    return label_from_file($file);
}

function scan_images(string $dir, array $extensions, bool $recursive = false): array {
    if (!is_dir($dir)) {
        return [];
    }
    $allowed = array_flip($extensions);
    $files = [];
    if ($recursive) {
        $iterator = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        foreach ($iterator as $item) {
            if (!$item->isFile()) {
                continue;
            }
            $path = $item->getPathname();
            $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
            if (isset($allowed[$ext])) {
                $files[] = $path;
            }
        }
    } else {
        $entries = scandir($dir);
        if ($entries === false) {
            return [];
        }
        foreach ($entries as $entry) {
            if ($entry === '.' || $entry === '..') {
                continue;
            }
            $path = $dir . DIRECTORY_SEPARATOR . $entry;
            if (!is_file($path)) {
                continue;
            }
            $ext = strtolower(pathinfo($entry, PATHINFO_EXTENSION));
            if (isset($allowed[$ext])) {
                $files[] = $path;
            }
        }
    }
    natsort($files);
    return array_values($files);
}

function make_scanned_assets(
    string $baseDir,
    array $extensions,
    bool $recursive,
    bool $useMetadataLabels,
    bool $includeFolderInLabel,
    string $projectRoot,
    bool $withDefaultFlag = false
): array {
    $out = [];
    foreach (scan_images($baseDir, $extensions, $recursive) as $file) {
        $label = resolve_label($file, $useMetadataLabels);
        if ($includeFolderInLabel) {
            $rel = relative_path($file, $baseDir);
            $subDir = dirname(str_replace('\\', '/', $rel));
            if ($subDir !== '.' && $subDir !== '') {
                $subDirLabel = normalize_label(str_replace(['/', '\\', '_', '-'], ' ', $subDir));
                if ($subDirLabel !== '') {
                    $label = $subDirLabel . ' - ' . $label;
                }
            }
        }
        $item = [
            'path' => to_web_path($file, $projectRoot),
            'label' => $label
        ];
        if ($withDefaultFlag) {
            $item['isDefault'] = false;
        }
        $out[] = $item;
    }
    return $out;
}

function normalize_manual_assets(array $entries, ?string $dirAbs, string $projectRoot): array {
    $out = [];
    foreach ($entries as $entry) {
        $item = ['path' => '', 'label' => '', 'isDefault' => false];
        if (is_string($entry)) {
            $item['path'] = $entry;
        } elseif (is_array($entry)) {
            if (isset($entry['path']) && is_string($entry['path'])) {
                $item['path'] = $entry['path'];
            } elseif (isset($entry['file']) && is_string($entry['file'])) {
                if ($dirAbs && is_file($dirAbs . DIRECTORY_SEPARATOR . $entry['file'])) {
                    $item['path'] = to_web_path($dirAbs . DIRECTORY_SEPARATOR . $entry['file'], $projectRoot);
                } else {
                    $item['path'] = $entry['file'];
                }
            }
            if (isset($entry['label']) && is_string($entry['label'])) {
                $item['label'] = $entry['label'];
            }
            if (!empty($entry['isDefault'])) {
                $item['isDefault'] = true;
            }
        }
        if ($item['path'] === '') {
            continue;
        }
        if ($item['label'] === '') {
            $item['label'] = label_from_file($item['path']);
        }
        $out[] = $item;
    }
    return $out;
}

$projectRoot = realpath(dirname(__DIR__));
$configRoot = realpath(__DIR__);
if ($projectRoot === false || $configRoot === false) {
    respond(['ok' => false, 'error' => 'Pfadauflösung fehlgeschlagen.'], 500);
}

$variantsManifest = read_json($configRoot . DIRECTORY_SEPARATOR . 'variants.json');
$variants = isset($variantsManifest['variants']) && is_array($variantsManifest['variants']) ? $variantsManifest['variants'] : [];
if ($variants === []) {
    respond(['ok' => false, 'error' => 'Keine Varianten in variants.json gefunden.'], 500);
}

$defaultVariant = '';
if (isset($variantsManifest['defaultVariant']) && is_string($variantsManifest['defaultVariant'])) {
    $defaultVariant = normalize_id($variantsManifest['defaultVariant']);
}
if ($defaultVariant === '' && isset($variants[0]['id']) && is_string($variants[0]['id'])) {
    $defaultVariant = normalize_id($variants[0]['id']);
}

$requestedVariant = isset($_GET['variant']) && is_string($_GET['variant']) ? normalize_id($_GET['variant']) : '';
$selectedVariant = $requestedVariant !== '' ? $requestedVariant : $defaultVariant;

$selected = null;
$variantList = [];
foreach ($variants as $v) {
    if (!is_array($v)) {
        continue;
    }
    $id = isset($v['id']) && is_string($v['id']) ? normalize_id($v['id']) : '';
    if ($id === '') {
        continue;
    }
    $label = isset($v['label']) && is_string($v['label']) ? $v['label'] : $id;
    $variantList[] = ['id' => $id, 'label' => $label];
    if ($id === $selectedVariant) {
        $selected = $v;
    }
}

if ($selected === null && isset($variants[0]) && is_array($variants[0])) {
    $selected = $variants[0];
    $selectedVariant = normalize_id((string)($selected['id'] ?? ''));
}
if ($selected === null) {
    respond(['ok' => false, 'error' => 'Keine gültige Variante gefunden.'], 500);
}

$configFile = isset($selected['config']) && is_string($selected['config']) ? $selected['config'] : '';
$configPath = $configFile !== '' ? safe_join($configRoot, $configFile) : null;
if ($configPath === null || !is_file($configPath) || !is_inside($configPath, $configRoot)) {
    respond(['ok' => false, 'error' => 'Varianten-Konfigurationsdatei fehlt oder ist ungültig.'], 500);
}

$variantCfg = read_json($configPath);

$backgroundDirRel = isset($variantCfg['backgroundDir']) && is_string($variantCfg['backgroundDir']) ? $variantCfg['backgroundDir'] : '';
$logoDirRel = isset($variantCfg['logoDir']) && is_string($variantCfg['logoDir']) ? $variantCfg['logoDir'] : '';

$backgroundDirAbs = $backgroundDirRel !== '' ? safe_join($configRoot, $backgroundDirRel) : null;
$logoDirAbs = $logoDirRel !== '' ? safe_join($configRoot, $logoDirRel) : null;

if ($backgroundDirAbs !== null && !is_inside($backgroundDirAbs, $projectRoot)) {
    $backgroundDirAbs = null;
}
if ($logoDirAbs !== null && !is_inside($logoDirAbs, $projectRoot)) {
    $logoDirAbs = null;
}

$bgExts = normalize_exts($variantCfg['backgroundExtensions'] ?? null, ['jpg', 'jpeg', 'png', 'webp']);
$logoExts = normalize_exts($variantCfg['logoExtensions'] ?? null, ['png', 'svg', 'jpg', 'jpeg', 'webp']);

$backgroundsMode = isset($variantCfg['backgroundsMode']) && is_string($variantCfg['backgroundsMode']) ? strtolower($variantCfg['backgroundsMode']) : 'scan';
$logosMode = isset($variantCfg['logosMode']) && is_string($variantCfg['logosMode']) ? strtolower($variantCfg['logosMode']) : 'scan';
$backgroundRecursive = parse_bool($variantCfg['backgroundRecursive'] ?? false, false);
$logoRecursive = parse_bool($variantCfg['logoRecursive'] ?? false, false);
$useMetadataLabels = parse_bool($variantCfg['useMetadataLabels'] ?? true, true);
$includeFolderInLabels = parse_bool($variantCfg['includeFolderInLabels'] ?? false, false);

$scannedBackgrounds = [];
if ($backgroundDirAbs !== null) {
    $scannedBackgrounds = make_scanned_assets(
        $backgroundDirAbs,
        $bgExts,
        $backgroundRecursive,
        $useMetadataLabels,
        $includeFolderInLabels,
        $projectRoot,
        false
    );
}
$scannedLogos = [];
if ($logoDirAbs !== null) {
    $scannedLogos = make_scanned_assets(
        $logoDirAbs,
        $logoExts,
        $logoRecursive,
        $useMetadataLabels,
        $includeFolderInLabels,
        $projectRoot,
        true
    );
}

$manualBackgrounds = normalize_manual_assets(is_array($variantCfg['backgrounds'] ?? null) ? $variantCfg['backgrounds'] : [], $backgroundDirAbs, $projectRoot);
$manualLogos = normalize_manual_assets(is_array($variantCfg['logos'] ?? null) ? $variantCfg['logos'] : [], $logoDirAbs, $projectRoot);

$backgrounds = $scannedBackgrounds;
if ($backgroundsMode === 'manual') {
    $backgrounds = $manualBackgrounds;
} elseif ($backgroundsMode === 'merge') {
    $backgrounds = array_merge($scannedBackgrounds, $manualBackgrounds);
}

$logos = $scannedLogos;
if ($logosMode === 'manual') {
    $logos = $manualLogos;
} elseif ($logosMode === 'merge') {
    $logos = array_merge($scannedLogos, $manualLogos);
}

$defaultLogo = isset($variantCfg['defaultLogo']) && is_string($variantCfg['defaultLogo']) ? trim($variantCfg['defaultLogo']) : '';
if ($defaultLogo !== '' && $logos !== []) {
    foreach ($logos as &$logo) {
        $pathFile = basename((string)$logo['path']);
        $logo['isDefault'] = ($pathFile === $defaultLogo);
    }
    unset($logo);
}
if ($logos !== []) {
    $hasDefault = false;
    foreach ($logos as $logo) {
        if (!empty($logo['isDefault'])) {
            $hasDefault = true;
            break;
        }
    }
    if (!$hasDefault) {
        $logos[0]['isDefault'] = true;
    }
}

$responseConfig = [
    'name' => isset($variantCfg['name']) && is_string($variantCfg['name']) ? $variantCfg['name'] : $selectedVariant,
    'backgrounds' => $backgrounds,
    'logos' => $logos
];

if (isset($variantCfg['palettes']) && is_array($variantCfg['palettes'])) {
    $responseConfig['palettes'] = $variantCfg['palettes'];
}
if (isset($variantCfg['formats']) && is_array($variantCfg['formats'])) {
    $responseConfig['formats'] = $variantCfg['formats'];
}
if (isset($variantCfg['presets']) && is_array($variantCfg['presets'])) {
    $responseConfig['presets'] = $variantCfg['presets'];
}
if (isset($variantCfg['branding']) && is_array($variantCfg['branding'])) {
    $responseConfig['branding'] = $variantCfg['branding'];
}
if (isset($variantCfg['defaults']) && is_array($variantCfg['defaults'])) {
    $responseConfig['defaults'] = $variantCfg['defaults'];
}

respond([
    'ok' => true,
    'variant' => $selectedVariant,
    'variantLabel' => isset($selected['label']) && is_string($selected['label']) ? $selected['label'] : $selectedVariant,
    'variants' => $variantList,
    'config' => $responseConfig
]);
