<?php

namespace App\Support;

use Illuminate\Support\Str;

class CssFontFamily
{
    /**
     * @var list<string>
     */
    private const GENERIC = [
        'serif',
        'sans-serif',
        'monospace',
        'cursive',
        'fantasy',
        'system-ui',
        'ui-sans-serif',
        'ui-serif',
        'ui-monospace',
        'ui-rounded',
        'emoji',
        'math',
        'fangsong',
        'inherit',
        'initial',
        'unset',
        'revert',
        'none',
        '-apple-system',
        'blinkmacsystemfont',
        'apple color emoji',
        'segoe ui emoji',
        'segoe ui symbol',
        'noto color emoji',
    ];

    /**
     * @var list<string>
     */
    private const ICON_NEEDLES = [
        'font awesome',
        'fontawesome',
        'material icons',
        'material symbols',
        'bootstrap-icons',
        'dashicons',
        'glyphicon',
    ];

    /**
     * @var list<string>
     */
    private const WEB_SAFE = [
        'arial',
        'helvetica',
        'helvetica neue',
        'times new roman',
        'times',
        'georgia',
        'courier new',
        'courier',
        'verdana',
        'tahoma',
        'trebuchet ms',
        'palatino',
        'palatino linotype',
        'garamond',
        'comic sans ms',
        'impact',
        'lucida console',
        'lucida sans unicode',
        'lucida grande',
        'geneva',
        'segoe ui',
    ];

    /**
     * @var list<string>
     */
    private const PROMPT_NOISE = [
        'sans',
        'serif',
        'sans-serif',
        'modern',
        'website',
        'same',
        'similar',
        'default',
        'system',
        'landing',
        'brand',
        'their',
        'your',
        'body',
        'heading',
        'google',
        'custom',
        'nice',
        'good',
        'clean',
        'page',
        'site',
        'our',
        'the',
        'a',
        'an',
    ];

    public static function primary(string $stack): ?string
    {
        foreach (explode(',', $stack) as $part) {
            $name = trim($part, " \t\n\r\0\x0B\"'");

            if ($name === '' || self::isGeneric($name)) {
                continue;
            }

            return $name;
        }

        return null;
    }

    public static function cssValue(string $family): string
    {
        $family = trim($family);

        if ($family === '') {
            return 'sans-serif';
        }

        $quoted = str_contains($family, ' ') ? '"'.$family.'"' : $family;

        return $quoted.', sans-serif';
    }

    public static function stylesheetUrl(string $family): ?string
    {
        $family = trim($family);

        if ($family === '' || self::isWebSafe($family)) {
            return null;
        }

        $query = str_replace(' ', '+', $family);

        return 'https://fonts.googleapis.com/css2?family='.$query.':wght@400;500;600;700&display=swap';
    }

    public static function fromGoogleFontsUrl(string $url): ?string
    {
        $query = parse_url($url, PHP_URL_QUERY);

        if (! is_string($query) || $query === '') {
            return null;
        }

        parse_str($query, $params);
        $family = $params['family'] ?? null;

        if (is_array($family)) {
            $family = $family[0] ?? null;
        }

        if (! is_string($family) || $family === '') {
            return null;
        }

        $family = explode(':', $family)[0];
        $family = str_replace('+', ' ', $family);

        return self::primary($family);
    }

    public static function fromUserPrompt(string $prompt): ?string
    {
        $patterns = [
            '/\bfont(?:[ -]?family)?\s*(?:is|=|:|to|as)\s*["\']?([A-Za-z][A-Za-z0-9][A-Za-z0-9 +-]{0,40})["\']?/i',
            '/\b(?:use|using|with)\s+(?:the\s+)?["\']([A-Za-z][A-Za-z0-9][A-Za-z0-9 +-]{0,40})["\']/i',
            '/\b(?:use|using|with)\s+(?:the\s+)?([A-Za-z][A-Za-z0-9][A-Za-z0-9 +-]{0,30})\s+fonts?\b/i',
        ];

        foreach ($patterns as $pattern) {
            if (preg_match($pattern, $prompt, $match) !== 1) {
                continue;
            }

            $name = self::primary(trim($match[1], " \t\n\r\0\x0B\"',.;:"));

            if ($name === null || self::isPromptNoise($name)) {
                continue;
            }

            return $name;
        }

        return null;
    }

    private static function isGeneric(string $name): bool
    {
        $folded = Str::lower($name);

        if (in_array($folded, self::GENERIC, true)) {
            return true;
        }

        foreach (self::ICON_NEEDLES as $needle) {
            if (str_contains($folded, $needle)) {
                return true;
            }
        }

        return false;
    }

    private static function isWebSafe(string $name): bool
    {
        return in_array(Str::lower($name), self::WEB_SAFE, true);
    }

    private static function isPromptNoise(string $name): bool
    {
        return in_array(Str::lower($name), self::PROMPT_NOISE, true);
    }
}
