<?php
declare(strict_types=1);

namespace ROITheme\Public\CriticalCSS\Infrastructure\Cache;

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

/**
 * Cache de CSS critico en filesystem con auto-invalidacion
 *
 * Almacena CSS critico generado en archivos .critical.css
 * dentro de Assets/CriticalCSS/
 *
 * @package ROITheme\Public\CriticalCSS\Infrastructure\Cache
 */
final class CriticalCSSFileCache implements CriticalCSSCacheInterface
{
    private readonly string $cacheDir;

    public function __construct()
    {
        $this->cacheDir = get_template_directory() . '/Assets/CriticalCSS';
    }

    /**
     * {@inheritDoc}
     */
    public function get(string $key): ?string
    {
        $file = $this->getFilePath($key);

        if (!file_exists($file)) {
            return null;
        }

        $content = file_get_contents($file);

        return $content !== false ? $content : null;
    }

    /**
     * {@inheritDoc}
     */
    public function set(string $key, string $css): bool
    {
        $this->ensureDirectoryExists();
        $file = $this->getFilePath($key);

        return file_put_contents($file, $css) !== false;
    }

    /**
     * {@inheritDoc}
     */
    public function has(string $key): bool
    {
        return file_exists($this->getFilePath($key));
    }

    /**
     * {@inheritDoc}
     */
    public function clear(): void
    {
        $files = glob($this->cacheDir . '/*.critical.css');

        if ($files === false) {
            return;
        }

        foreach ($files as $file) {
            unlink($file);
        }
    }

    /**
     * {@inheritDoc}
     *
     * Compara timestamps para detectar cache desactualizado.
     * Costo: ~0.1ms (2 llamadas a filemtime)
     */
    public function isStale(string $key, string $sourceFile): bool
    {
        $cacheFile = $this->getFilePath($key);

        // Si no existe cache, esta desactualizado
        if (!file_exists($cacheFile)) {
            return true;
        }

        // Si no existe fuente, no esta desactualizado (nada que regenerar)
        if (!file_exists($sourceFile)) {
            return false;
        }

        // Comparar timestamps
        return filemtime($sourceFile) > filemtime($cacheFile);
    }

    /**
     * Genera ruta del archivo cache
     */
    private function getFilePath(string $key): string
    {
        return $this->cacheDir . '/' . $key . '.critical.css';
    }

    /**
     * Asegura que el directorio de cache existe
     */
    private function ensureDirectoryExists(): void
    {
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
    }
}
