<?php

namespace App\Support\Theme;

/**
 * The typography library. Deliberately INDEPENDENT of {@see ThemePresets}: a
 * tenant picks a colour preset and a font pairing separately, so any font can
 * be combined with any palette.
 *
 * Every entry that needs a webfont carries a `bunny` slug. The previous
 * implementation set --font-sans to "'Roboto', sans-serif" without ever loading
 * Roboto, so the browser silently fell back to a system font and the setting
 * appeared to do nothing. {@see TenantTheme::fontUrl()} now emits a matching
 * <link> so the family is actually available.
 */
final class ThemeFonts
{
    /** Appended to every stack so emoji render regardless of the chosen family. */
    private const EMOJI = "'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'";

    /**
     * @var array<string, array{label: string, category: string, family: string|null, stack: string, bunny: string|null}>
     */
    private const FONTS = [
        'system' => ['label' => 'System UI', 'category' => 'Sans', 'family' => null, 'stack' => 'ui-sans-serif, system-ui, -apple-system, sans-serif', 'bunny' => null],
        'inter' => ['label' => 'Inter', 'category' => 'Sans', 'family' => 'Inter', 'stack' => "'Inter', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'inter:400,500,600,700'],
        'dm-sans' => ['label' => 'DM Sans', 'category' => 'Sans', 'family' => 'DM Sans', 'stack' => "'DM Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'dm-sans:400,500,700'],
        'plus-jakarta-sans' => ['label' => 'Plus Jakarta Sans', 'category' => 'Sans', 'family' => 'Plus Jakarta Sans', 'stack' => "'Plus Jakarta Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'plus-jakarta-sans:400,500,600,700'],
        'manrope' => ['label' => 'Manrope', 'category' => 'Sans', 'family' => 'Manrope', 'stack' => "'Manrope', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'manrope:400,500,600,700'],
        'figtree' => ['label' => 'Figtree', 'category' => 'Sans', 'family' => 'Figtree', 'stack' => "'Figtree', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'figtree:400,500,600,700'],
        'outfit' => ['label' => 'Outfit', 'category' => 'Sans', 'family' => 'Outfit', 'stack' => "'Outfit', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'outfit:400,500,600,700'],
        'poppins' => ['label' => 'Poppins', 'category' => 'Sans', 'family' => 'Poppins', 'stack' => "'Poppins', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'poppins:400,500,600,700'],
        'montserrat' => ['label' => 'Montserrat', 'category' => 'Sans', 'family' => 'Montserrat', 'stack' => "'Montserrat', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'montserrat:400,500,600,700'],
        'work-sans' => ['label' => 'Work Sans', 'category' => 'Sans', 'family' => 'Work Sans', 'stack' => "'Work Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'work-sans:400,500,600,700'],
        'nunito-sans' => ['label' => 'Nunito Sans', 'category' => 'Sans', 'family' => 'Nunito Sans', 'stack' => "'Nunito Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'nunito-sans:400,500,600,700'],
        'rubik' => ['label' => 'Rubik', 'category' => 'Sans', 'family' => 'Rubik', 'stack' => "'Rubik', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'rubik:400,500,600,700'],
        'source-sans-3' => ['label' => 'Source Sans 3', 'category' => 'Sans', 'family' => 'Source Sans 3', 'stack' => "'Source Sans 3', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'source-sans-3:400,500,600,700'],
        'ibm-plex-sans' => ['label' => 'IBM Plex Sans', 'category' => 'Sans', 'family' => 'IBM Plex Sans', 'stack' => "'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'ibm-plex-sans:400,500,600,700'],
        'space-grotesk' => ['label' => 'Space Grotesk', 'category' => 'Sans', 'family' => 'Space Grotesk', 'stack' => "'Space Grotesk', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'space-grotesk:400,500,600,700'],
        'lato' => ['label' => 'Lato', 'category' => 'Sans', 'family' => 'Lato', 'stack' => "'Lato', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'lato:400,700'],
        'open-sans' => ['label' => 'Open Sans', 'category' => 'Sans', 'family' => 'Open Sans', 'stack' => "'Open Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'open-sans:400,500,600,700'],
        'roboto' => ['label' => 'Roboto', 'category' => 'Sans', 'family' => 'Roboto', 'stack' => "'Roboto', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'roboto:400,500,700'],
        'karla' => ['label' => 'Karla', 'category' => 'Sans', 'family' => 'Karla', 'stack' => "'Karla', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'karla:400,500,600,700'],
        'public-sans' => ['label' => 'Public Sans', 'category' => 'Sans', 'family' => 'Public Sans', 'stack' => "'Public Sans', ui-sans-serif, system-ui, sans-serif", 'bunny' => 'public-sans:400,500,600,700'],
        'playfair-display' => ['label' => 'Playfair Display', 'category' => 'Serif', 'family' => 'Playfair Display', 'stack' => "'Playfair Display', ui-serif, Georgia, serif", 'bunny' => 'playfair-display:400,500,600,700'],
        'merriweather' => ['label' => 'Merriweather', 'category' => 'Serif', 'family' => 'Merriweather', 'stack' => "'Merriweather', ui-serif, Georgia, serif", 'bunny' => 'merriweather:400,700'],
        'lora' => ['label' => 'Lora', 'category' => 'Serif', 'family' => 'Lora', 'stack' => "'Lora', ui-serif, Georgia, serif", 'bunny' => 'lora:400,500,600,700'],
        'source-serif-4' => ['label' => 'Source Serif 4', 'category' => 'Serif', 'family' => 'Source Serif 4', 'stack' => "'Source Serif 4', ui-serif, Georgia, serif", 'bunny' => 'source-serif-4:400,600,700'],
        'ibm-plex-mono' => ['label' => 'IBM Plex Mono', 'category' => 'Mono', 'family' => 'IBM Plex Mono', 'stack' => "'IBM Plex Mono', ui-monospace, monospace", 'bunny' => 'ibm-plex-mono:400,500,600'],
        'jetbrains-mono' => ['label' => 'JetBrains Mono', 'category' => 'Mono', 'family' => 'JetBrains Mono', 'stack' => "'JetBrains Mono', ui-monospace, monospace", 'bunny' => 'jetbrains-mono:400,500,700'],
    ];

    public const DEFAULT_BODY = 'inter';

    /** Radius options offered in the UI, mapped to the --radius value. */
    public const RADII = [
        'none' => ['label' => 'Sharp', 'value' => '0rem'],
        'xs' => ['label' => 'Subtle', 'value' => '0.25rem'],
        'sm' => ['label' => 'Small', 'value' => '0.375rem'],
        'md' => ['label' => 'Medium', 'value' => '0.5rem'],
        'lg' => ['label' => 'Large', 'value' => '0.75rem'],
        'xl' => ['label' => 'Extra large', 'value' => '1rem'],
    ];

    public const DEFAULT_RADIUS = 'md';

    /**
     * Global type scale. Multiplies the root font size, so every rem-based size
     * in the app moves together rather than only the body copy.
     */
    public const SCALES = [
        'compact' => ['label' => 'Compact', 'value' => '15px'],
        'default' => ['label' => 'Default', 'value' => '16px'],
        'comfortable' => ['label' => 'Comfortable', 'value' => '17px'],
        'large' => ['label' => 'Large', 'value' => '18px'],
    ];

    public const DEFAULT_SCALE = 'default';

    /** @return array<string, array{label: string, category: string, family: string|null, stack: string, bunny: string|null}> */
    public static function all(): array
    {
        return self::FONTS;
    }

    public static function has(string $key): bool
    {
        return isset(self::FONTS[$key]);
    }

    /** Resolve a font key to a full CSS font stack, falling back to the default. */
    public static function stack(?string $key): string
    {
        $font = self::FONTS[$key ?? ''] ?? self::FONTS[self::DEFAULT_BODY];

        return $font['stack'].', '.self::EMOJI;
    }

    /** The bunny.net descriptor (`slug:weights`) for a key, or null for system fonts. */
    public static function bunny(?string $key): ?string
    {
        return self::FONTS[$key ?? '']['bunny'] ?? null;
    }

    public static function radius(?string $key): string
    {
        return self::RADII[$key ?? '']['value'] ?? self::RADII[self::DEFAULT_RADIUS]['value'];
    }

    public static function scale(?string $key): string
    {
        return self::SCALES[$key ?? '']['value'] ?? self::SCALES[self::DEFAULT_SCALE]['value'];
    }

    /**
     * Shape for the Inertia prop that drives the typography controls.
     *
     * @return array<string, mixed>
     */
    public static function catalogue(): array
    {
        return [
            'fonts' => array_map(
                fn (array $f, string $k) => ['key' => $k, 'label' => $f['label'], 'category' => $f['category'], 'stack' => $f['stack']],
                self::FONTS,
                array_keys(self::FONTS),
            ),
            'radii' => array_map(fn (array $r, string $k) => ['key' => $k, 'label' => $r['label'], 'value' => $r['value']], self::RADII, array_keys(self::RADII)),
            'scales' => array_map(fn (array $s, string $k) => ['key' => $k, 'label' => $s['label'], 'value' => $s['value']], self::SCALES, array_keys(self::SCALES)),
        ];
    }
}
