<?php
declare(strict_types=1);

namespace ROITheme\Public\CriticalCSS\Infrastructure\Services;

use ROITheme\Public\CriticalCSS\Domain\Contracts\CriticalCSSCacheInterface;
use ROITheme\Public\CriticalCSS\Domain\Contracts\CriticalCSSExtractorInterface;

/**
 * Extrae CSS critico de archivos fuente
 *
 * Estrategia simple:
 * - Variables: Todo el archivo (siempre critico)
 * - Responsive: Solo breakpoints mobile-first criticos
 *
 * @package ROITheme\Public\CriticalCSS\Infrastructure\Services
 */
final class CriticalCSSExtractor implements CriticalCSSExtractorInterface
{
    // Archivos fuente
    private const SOURCE_VARIABLES = '/Assets/Css/css-global-variables.css';
    private const SOURCE_RESPONSIVE = '/Assets/Css/css-global-responsive.css';

    // Breakpoints criticos (mobile-first)
    // NOTA: El regex maneja 1 nivel de anidamiento.
    // Si el CSS tiene @supports dentro de @media, no se capturara correctamente.
    // Esto es aceptable para css-global-responsive.css que es simple.
    private const CRITICAL_BREAKPOINTS = [
        '@media (max-width: 575.98px)',
        '@media (min-width: 576px)',
        '@media (max-width: 767.98px)',
        '@media (min-width: 768px)',
        '@media (min-width: 992px)',
    ];

    public function __construct(
        private readonly CriticalCSSCacheInterface $cache
    ) {}

    /**
     * {@inheritDoc}
     */
    public function extractVariables(): string
    {
        $sourceFile = get_template_directory() . self::SOURCE_VARIABLES;

        if (!file_exists($sourceFile)) {
            return '';
        }

        $css = file_get_contents($sourceFile);

        if ($css === false) {
            return '';
        }

        // Para variables, todo el contenido es critico
        return $this->minify($css);
    }

    /**
     * {@inheritDoc}
     */
    public function extractResponsive(): string
    {
        $sourceFile = get_template_directory() . self::SOURCE_RESPONSIVE;

        if (!file_exists($sourceFile)) {
            return '';
        }

        $css = file_get_contents($sourceFile);

        if ($css === false) {
            return '';
        }

        $criticalCSS = '';

        // Extraer solo media queries criticas
        // Regex: captura @media (...) { contenido con 1 nivel de {} }
        foreach (self::CRITICAL_BREAKPOINTS as $breakpoint) {
            $pattern = '/' . preg_quote($breakpoint, '/') . '\s*\{([^{}]*(?:\{[^{}]*\}[^{}]*)*)\}/s';

            if (preg_match_all($pattern, $css, $matches)) {
                foreach ($matches[0] as $match) {
                    $criticalCSS .= $match . "\n";
                }
            }
        }

        return $this->minify($criticalCSS);
    }

    /**
     * {@inheritDoc}
     */
    public function generateAll(): array
    {
        $results = [];

        // Variables CSS
        $variablesCSS = $this->extractVariables();
        if (!empty($variablesCSS)) {
            $this->cache->set('variables', $variablesCSS);
            $results['variables'] = strlen($variablesCSS);
        }

        // Responsive critico
        $responsiveCSS = $this->extractResponsive();
        if (!empty($responsiveCSS)) {
            $this->cache->set('responsive', $responsiveCSS);
            $results['responsive'] = strlen($responsiveCSS);
        }

        return $results;
    }

    /**
     * {@inheritDoc}
     */
    public function needsRegeneration(): bool
    {
        $templateDir = get_template_directory();

        return $this->cache->isStale('variables', $templateDir . self::SOURCE_VARIABLES)
            || $this->cache->isStale('responsive', $templateDir . self::SOURCE_RESPONSIVE);
    }

    /**
     * Minifica CSS eliminando espacios y comentarios innecesarios
     */
    private function minify(string $css): string
    {
        // Eliminar comentarios
        $css = preg_replace('/\/\*[\s\S]*?\*\//', '', $css) ?? $css;

        // Eliminar espacios innecesarios
        $css = preg_replace('/\s+/', ' ', $css) ?? $css;
        $css = preg_replace('/\s*([{};:,>+~])\s*/', '$1', $css) ?? $css;

        // Eliminar ultimo punto y coma antes de }
        $css = preg_replace('/;}/', '}', $css) ?? $css;

        return trim($css);
    }
}
