<?php

namespace App\Support\Theme;

/**
 * The pre-built theme library — the ONLY way a tenant's colours are chosen.
 *
 * The old implementation exposed four raw hex pickers (primary / secondary /
 * background / foreground) plus four presets that wrote into those same four
 * fields. That could never produce a coherent result: nothing derived the
 * remaining ~26 tokens, so borders, muted text, the sidebar and the login panel
 * stayed on the stock palette whatever was picked.
 *
 * Here a preset is a compact SPEC — a hue, a chroma, a brand lightness and a
 * sidebar treatment — which {@see ThemePalette} expands into the complete token
 * set for both light and dark mode. Adding a theme is one line; it cannot be
 * internally inconsistent, and every token is accounted for.
 *
 * Typography ({@see ThemeFonts}) is deliberately NOT part of a preset, so any
 * font, radius and type scale can be combined with any palette.
 */
final class ThemePresets
{
    /** Matches the palette the app already shipped, so an unset tenant sees no change. */
    public const DEFAULT_KEY = 'corporate-blue';

    /**
     * @var array<string, array<string, mixed>>
     */
    private const PRESETS = [
        // ── Blue & Indigo ────────────────────────────────────────────────────
        'corporate-blue' => ['name' => 'Corporate Blue', 'group' => 'Blue & Indigo', 'hue' => 258, 'chroma' => 0.19, 'primary_l' => 0.52, 'sidebar' => 'dark'],
        'ocean-deep' => ['name' => 'Ocean Deep', 'group' => 'Blue & Indigo', 'hue' => 240, 'chroma' => 0.17, 'primary_l' => 0.48, 'sidebar' => 'deep'],
        'sky-breeze' => ['name' => 'Sky Breeze', 'group' => 'Blue & Indigo', 'hue' => 228, 'chroma' => 0.16, 'primary_l' => 0.56, 'sidebar' => 'light'],
        'steel-navy' => ['name' => 'Steel Navy', 'group' => 'Blue & Indigo', 'hue' => 250, 'chroma' => 0.10, 'primary_l' => 0.45, 'neutral_chroma' => 0.012, 'sidebar' => 'ink'],
        'arctic-frost' => ['name' => 'Arctic Frost', 'group' => 'Blue & Indigo', 'hue' => 215, 'chroma' => 0.08, 'primary_l' => 0.50, 'neutral_hue' => 220, 'sidebar' => 'light'],
        'midnight-indigo' => ['name' => 'Midnight Indigo', 'group' => 'Blue & Indigo', 'hue' => 278, 'chroma' => 0.19, 'primary_l' => 0.50, 'sidebar' => 'ink'],

        // ── Purple & Pink ────────────────────────────────────────────────────
        'royal-violet' => ['name' => 'Royal Violet', 'group' => 'Purple & Pink', 'hue' => 295, 'chroma' => 0.19, 'primary_l' => 0.52, 'sidebar' => 'deep'],
        'plum-orchid' => ['name' => 'Plum Orchid', 'group' => 'Purple & Pink', 'hue' => 320, 'chroma' => 0.18, 'primary_l' => 0.54, 'sidebar' => 'deep'],
        'lavender-haze' => ['name' => 'Lavender Haze', 'group' => 'Purple & Pink', 'hue' => 292, 'chroma' => 0.12, 'primary_l' => 0.56, 'neutral_hue' => 290, 'neutral_chroma' => 0.012, 'sidebar' => 'light'],
        'blush-pink' => ['name' => 'Blush Pink', 'group' => 'Purple & Pink', 'hue' => 350, 'chroma' => 0.15, 'primary_l' => 0.55, 'neutral_hue' => 350, 'neutral_chroma' => 0.012, 'sidebar' => 'light'],
        'magenta-pop' => ['name' => 'Magenta Pop', 'group' => 'Purple & Pink', 'hue' => 340, 'chroma' => 0.20, 'primary_l' => 0.55, 'sidebar' => 'ink'],
        'aubergine' => ['name' => 'Aubergine', 'group' => 'Purple & Pink', 'hue' => 310, 'chroma' => 0.13, 'primary_l' => 0.45, 'neutral_hue' => 305, 'neutral_chroma' => 0.012, 'sidebar' => 'deep'],

        // ── Green & Teal ─────────────────────────────────────────────────────
        'emerald-clean' => ['name' => 'Emerald Clean', 'group' => 'Green & Teal', 'hue' => 158, 'chroma' => 0.15, 'primary_l' => 0.52, 'neutral_hue' => 160, 'sidebar' => 'deep'],
        'forest-pine' => ['name' => 'Forest Pine', 'group' => 'Green & Teal', 'hue' => 148, 'chroma' => 0.11, 'primary_l' => 0.45, 'neutral_hue' => 150, 'neutral_chroma' => 0.012, 'sidebar' => 'ink'],
        'teal-lagoon' => ['name' => 'Teal Lagoon', 'group' => 'Green & Teal', 'hue' => 195, 'chroma' => 0.13, 'primary_l' => 0.52, 'neutral_hue' => 200, 'sidebar' => 'deep'],
        'mint-fresh' => ['name' => 'Mint Fresh', 'group' => 'Green & Teal', 'hue' => 168, 'chroma' => 0.12, 'primary_l' => 0.58, 'neutral_hue' => 170, 'neutral_chroma' => 0.012, 'sidebar' => 'light'],
        'sage-calm' => ['name' => 'Sage Calm', 'group' => 'Green & Teal', 'hue' => 140, 'chroma' => 0.07, 'primary_l' => 0.50, 'neutral_hue' => 140, 'neutral_chroma' => 0.014, 'sidebar' => 'light'],
        'cyan-electric' => ['name' => 'Cyan Electric', 'group' => 'Green & Teal', 'hue' => 210, 'chroma' => 0.15, 'primary_l' => 0.55, 'neutral_hue' => 210, 'sidebar' => 'ink'],

        // ── Warm & Earth ─────────────────────────────────────────────────────
        'amber-glow' => ['name' => 'Amber Glow', 'group' => 'Warm & Earth', 'hue' => 70, 'chroma' => 0.15, 'primary_l' => 0.62, 'neutral_hue' => 75, 'sidebar' => 'ink'],
        'sunset-orange' => ['name' => 'Sunset Orange', 'group' => 'Warm & Earth', 'hue' => 45, 'chroma' => 0.17, 'primary_l' => 0.55, 'neutral_hue' => 50, 'sidebar' => 'ink'],
        'terracotta' => ['name' => 'Terracotta', 'group' => 'Warm & Earth', 'hue' => 40, 'chroma' => 0.12, 'primary_l' => 0.52, 'neutral_hue' => 45, 'neutral_chroma' => 0.014, 'sidebar' => 'deep'],
        'crimson-bold' => ['name' => 'Crimson Bold', 'group' => 'Warm & Earth', 'hue' => 22, 'chroma' => 0.19, 'primary_l' => 0.52, 'neutral_hue' => 25, 'sidebar' => 'ink'],
        'burgundy-wine' => ['name' => 'Burgundy Wine', 'group' => 'Warm & Earth', 'hue' => 15, 'chroma' => 0.13, 'primary_l' => 0.45, 'neutral_hue' => 18, 'neutral_chroma' => 0.012, 'sidebar' => 'deep'],
        'desert-sand' => ['name' => 'Desert Sand', 'group' => 'Warm & Earth', 'hue' => 62, 'chroma' => 0.09, 'primary_l' => 0.55, 'neutral_hue' => 68, 'neutral_chroma' => 0.016, 'sidebar' => 'light'],

        // ── Neutral & Mono ───────────────────────────────────────────────────
        'minimal-slate' => ['name' => 'Minimal Slate', 'group' => 'Neutral & Mono', 'hue' => 250, 'chroma' => 0.045, 'primary_l' => 0.45, 'neutral_chroma' => 0.008, 'sidebar' => 'ink'],
        'graphite-mono' => ['name' => 'Graphite Mono', 'group' => 'Neutral & Mono', 'hue' => 265, 'chroma' => 0.02, 'primary_l' => 0.38, 'neutral_chroma' => 0.004, 'sidebar' => 'ink'],
        'warm-stone' => ['name' => 'Warm Stone', 'group' => 'Neutral & Mono', 'hue' => 65, 'chroma' => 0.035, 'primary_l' => 0.42, 'neutral_hue' => 70, 'neutral_chroma' => 0.01, 'sidebar' => 'light'],
        'paper-white' => ['name' => 'Paper White', 'group' => 'Neutral & Mono', 'hue' => 250, 'chroma' => 0.06, 'primary_l' => 0.40, 'neutral_chroma' => 0.005, 'sidebar' => 'light'],
        'charcoal-ink' => ['name' => 'Charcoal Ink', 'group' => 'Neutral & Mono', 'hue' => 240, 'chroma' => 0.03, 'primary_l' => 0.32, 'neutral_chroma' => 0.006, 'sidebar' => 'ink'],
        'gunmetal' => ['name' => 'Gunmetal', 'group' => 'Neutral & Mono', 'hue' => 225, 'chroma' => 0.055, 'primary_l' => 0.48, 'neutral_hue' => 230, 'neutral_chroma' => 0.009, 'sidebar' => 'dark'],
    ];

    /**
     * Every preset, expanded into what the Theme Manager needs: identity,
     * grouping, the compact swatch set for the grid card, and the full
     * light+dark token set so the live preview can render an accurate app
     * shell and login panel client-side without duplicating {@see ThemePalette}'s
     * derivation (and its contrast guarantees) in TypeScript.
     *
     * @return array<int, array<string, mixed>>
     */
    public static function catalogue(): array
    {
        $out = [];

        foreach (self::PRESETS as $key => $spec) {
            $out[] = [
                'key' => $key,
                'name' => $spec['name'],
                'group' => $spec['group'],
                'swatches' => ThemePalette::swatches($spec),
                'tokens' => [
                    'light' => ThemePalette::light($spec),
                    'dark' => ThemePalette::dark($spec),
                ],
            ];
        }

        return $out;
    }

    /** The group names, in declaration order — drives the filter chips. */
    public static function groups(): array
    {
        $groups = [];

        foreach (self::PRESETS as $spec) {
            if (! in_array($spec['group'], $groups, true)) {
                $groups[] = $spec['group'];
            }
        }

        return $groups;
    }

    public static function has(?string $key): bool
    {
        return $key !== null && isset(self::PRESETS[$key]);
    }

    /** @return array<int, string> */
    public static function keys(): array
    {
        return array_keys(self::PRESETS);
    }

    /**
     * Resolve a preset key to its spec, falling back to the default so a stale
     * key in the database can never render an unstyled app.
     *
     * @return array<string, mixed>
     */
    public static function spec(?string $key): array
    {
        return self::PRESETS[$key ?? ''] ?? self::PRESETS[self::DEFAULT_KEY];
    }

    public static function name(?string $key): string
    {
        return self::spec($key)['name'];
    }

    /**
     * Light + dark token sets for a preset key.
     *
     * @return array{light: array<string, string>, dark: array<string, string>}
     */
    public static function tokens(?string $key): array
    {
        $spec = self::spec($key);

        return [
            'light' => ThemePalette::light($spec),
            'dark' => ThemePalette::dark($spec),
        ];
    }

    /**
     * The full per-preset colour variable sets the Master Control live preview
     * needs, keyed by preset key. Computed once per request and embedded in
     * the page; the preview bridge switches between them client-side when the
     * landlord picks another preset, so it sees exactly what the tenant's app
     * would render — the same sets {@see TenantTheme::previewVariables()}
     * emits for the saved theme.
     *
     * @return array<string, array{light: array<string, string>, dark: array<string, string>}>
     */
    public static function previewSets(): array
    {
        $sets = [];

        foreach (self::PRESETS as $key => $spec) {
            $sets[$key] = TenantTheme::previewColourVars($key);
        }

        return $sets;
    }
}
