<?php
declare(strict_types=1);

namespace App\Theme;

use InvalidArgumentException;
use JsonException;

final class ThemePackageService
{
    public const FORMAT = 'quaeriva-theme-package';
    public const SCHEMA = 1;

    /** @param array<string,mixed> $appearance @param array<string,mixed> $manifest */
    public static function export(array $appearance, array $manifest): string
    {
        $safeAppearance = ThemeAppearanceService::normalize($appearance, ThemeAppearanceService::defaults());
        $safeAppearance['active'] = (string) ($appearance['active'] ?? $manifest['name'] ?? 'default');
        $package = [
            'format' => self::FORMAT,
            'schema' => self::SCHEMA,
            'instructions' => 'Edit appearance values and custom_css, then import this package from the administrator appearance page. PHP templates and executable assets are never imported from this file.',
            'theme' => [
                'name' => (string) ($manifest['name'] ?? 'default'),
                'version' => (string) ($manifest['version'] ?? '1.0.0'),
                'author' => (string) ($manifest['author'] ?? ''),
                'directions' => array_values((array) ($manifest['directions'] ?? ['rtl', 'ltr'])),
                'min_core' => (string) ($manifest['min_core'] ?? ''),
            ],
            'appearance' => $safeAppearance,
        ];

        return json_encode($package, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
    }

    /** @return array{appearance:array<string,string>,theme:array<string,mixed>} */
    public static function import(string $json, array $fallback): array
    {
        if (strlen($json) > 512 * 1024) {
            throw new InvalidArgumentException('Theme package is too large.');
        }
        try {
            $package = json_decode($json, true, 32, JSON_THROW_ON_ERROR);
        } catch (JsonException $exception) {
            throw new InvalidArgumentException('Theme package JSON is invalid.', 0, $exception);
        }
        if (!is_array($package) || (string) ($package['format'] ?? '') !== self::FORMAT || (int) ($package['schema'] ?? 0) !== self::SCHEMA) {
            throw new InvalidArgumentException('Theme package format is invalid.');
        }
        $manifest = is_array($package['theme'] ?? null) ? $package['theme'] : [];
        $appearance = is_array($package['appearance'] ?? null) ? $package['appearance'] : [];
        return [
            'appearance' => ThemeAppearanceService::normalize($appearance, $fallback),
            'theme' => $manifest,
        ];
    }
}
