<?php
declare(strict_types=1);

namespace ROITheme\Shared\Infrastructure\Services;

use ROITheme\Shared\Domain\Contracts\CSSGeneratorInterface;

/**
 * Class CSSGeneratorService
 *
 * Implementación concreta del generador de CSS.
 * Convierte arrays de configuración de estilos en reglas CSS válidas y formateadas.
 *
 * Responsabilidades:
 * - Generar string CSS a partir de selector y estilos
 * - Convertir propiedades snake_case → kebab-case
 * - Normalizar nombres de propiedades (text_color → color)
 * - Formatear reglas CSS con indentación legible
 * - Sanitizar valores para prevenir inyección
 *
 * @package ROITheme\Shared\Infrastructure\Services
 */
final class CSSGeneratorService implements CSSGeneratorInterface
{
    /**
     * Mapa de nombres de propiedades CSS normalizadas.
     *
     * @var array<string, string>
     */
    private const PROPERTY_MAP = [
        'text-color' => 'color',
        'bg-color' => 'background-color',
    ];

    /**
     * {@inheritDoc}
     */
    public function generate(string $selector, array $styles): string
    {
        if (empty($styles)) {
            return '';
        }

        // Filtrar valores vacíos o null
        $styles = $this->filterEmptyValues($styles);

        if (empty($styles)) {
            return '';
        }

        // Convertir array de estilos a propiedades CSS
        $cssProperties = $this->buildCSSProperties($styles);

        // Formatear regla CSS completa
        return $this->formatCSSRule($selector, $cssProperties);
    }

    /**
     * Filtra valores vacíos, null o que solo contienen espacios en blanco.
     *
     * @param array<string, mixed> $styles Array de estilos
     * @return array<string, string> Array filtrado
     */
    private function filterEmptyValues(array $styles): array
    {
        return array_filter(
            $styles,
            fn($value) => $value !== null && $value !== '' && trim((string)$value) !== ''
        );
    }

    /**
     * Convierte array de estilos a propiedades CSS formateadas.
     *
     * @param array<string, string> $styles Array de estilos
     * @return array<int, string> Array de propiedades CSS formateadas
     */
    private function buildCSSProperties(array $styles): array
    {
        $properties = [];

        foreach ($styles as $property => $value) {
            // Convertir snake_case a kebab-case
            $cssProperty = $this->convertToKebabCase($property);

            // Normalizar nombre de propiedad
            $cssProperty = $this->normalizePropertyName($cssProperty);

            // Sanitizar valor
            $sanitizedValue = $this->sanitizeValue((string)$value);

            // Agregar propiedad formateada
            $properties[] = sprintf('%s: %s;', $cssProperty, $sanitizedValue);
        }

        return $properties;
    }

    /**
     * Convierte snake_case a kebab-case.
     *
     * Ejemplos:
     * - background_color → background-color
     * - font_size → font-size
     * - padding_top → padding-top
     *
     * @param string $property Nombre de propiedad en snake_case
     * @return string Nombre de propiedad en kebab-case
     */
    private function convertToKebabCase(string $property): string
    {
        return str_replace('_', '-', strtolower($property));
    }

    /**
     * Normaliza nombres de propiedades CSS a su forma estándar.
     *
     * Mapea alias comunes a nombres de propiedades CSS estándar:
     * - text-color → color
     * - bg-color → background-color
     *
     * @param string $property Nombre de propiedad
     * @return string Nombre de propiedad normalizado
     */
    private function normalizePropertyName(string $property): string
    {
        return self::PROPERTY_MAP[$property] ?? $property;
    }

    /**
     * Sanitiza valores CSS para prevenir inyección de código.
     *
     * Remueve tags HTML y caracteres potencialmente peligrosos,
     * manteniendo valores CSS válidos como colores, unidades, etc.
     *
     * @param string $value Valor CSS sin sanitizar
     * @return string Valor CSS sanitizado
     */
    private function sanitizeValue(string $value): string
    {
        // Remover tags HTML
        $value = strip_tags($value);

        // Remover caracteres de control excepto espacios
        $value = preg_replace('/[^\P{C}\s]/u', '', $value);

        // Trim espacios
        $value = trim($value);

        return $value;
    }

    /**
     * Formatea la regla CSS completa con selector y propiedades.
     *
     * Genera CSS con formato legible:
     * ```css
     * .selector {
     *     property: value;
     *     property2: value2;
     * }
     * ```
     *
     * @param string $selector Selector CSS
     * @param array<int, string> $properties Array de propiedades formateadas
     * @return string Regla CSS completa
     */
    private function formatCSSRule(string $selector, array $properties): string
    {
        if (empty($properties)) {
            return '';
        }

        return sprintf(
            "%s {\n    %s\n}",
            $selector,
            implode("\n    ", $properties)
        );
    }
}
