<?php
declare(strict_types=1);

namespace ROITheme\Shared\Infrastructure\Services;

use ROITheme\Shared\Domain\Contracts\ValidationServiceInterface;
use ROITheme\Shared\Domain\ValidationResult;
use ROITheme\Shared\Infrastructure\Persistence\WordPress\WordPressDefaultsRepository;

/**
 * WordPressValidationService - Validación contra schemas
 *
 * RESPONSABILIDAD: Validar y sanitizar datos de componentes
 *
 * ESTRATEGIA:
 * 1. Obtener schema del componente desde BD
 * 2. Validar estructura contra schema
 * 3. Sanitizar datos usando funciones de WordPress
 *
 * @package ROITheme\Infrastructure\Services
 */
final class WordPressValidationService implements ValidationServiceInterface
{
    public function __construct(
        private WordPressDefaultsRepository $defaultsRepository
    ) {}

    /**
     * Validar datos contra schema
     *
     * @param array $data Datos a validar
     * @param string $componentName Nombre del componente (para obtener schema)
     * @return ValidationResult
     */
    public function validate(array $data, string $componentName): ValidationResult
    {
        // 1. Obtener schema
        $schema = $this->defaultsRepository->find($componentName);

        if ($schema === null) {
            return ValidationResult::failure([
                "Schema not found for component: {$componentName}"
            ]);
        }

        // 2. Sanitizar datos primero
        $sanitized = $this->sanitize($data, $componentName);

        // 3. Validar estructura
        $errors = [];

        foreach ($sanitized as $groupName => $fields) {
            // Verificar que el grupo existe en schema
            if (!isset($schema[$groupName])) {
                $errors[$groupName] = "Unknown group: {$groupName}";
                continue;
            }

            // Validar cada campo del grupo
            if (is_array($fields)) {
                foreach ($fields as $key => $value) {
                    if (!isset($schema[$groupName][$key])) {
                        $errors["{$groupName}.{$key}"] = "Unknown field: {$groupName}.{$key}";
                    }

                    // Validaciones adicionales pueden agregarse aquí
                    // Por ejemplo, validar tipos, rangos, formatos, etc.
                }
            }
        }

        if (!empty($errors)) {
            return ValidationResult::failure($errors);
        }

        return ValidationResult::success($sanitized);
    }

    /**
     * Sanitizar datos recursivamente
     *
     * Usa funciones de WordPress según el tipo de dato
     *
     * @param array $data Datos a sanitizar
     * @param string $componentName Nombre del componente
     * @return array Datos sanitizados
     */
    public function sanitize(array $data, string $componentName): array
    {
        $sanitized = [];

        foreach ($data as $key => $value) {
            if (is_array($value)) {
                // Recursivo para arrays anidados
                $sanitized[$key] = $this->sanitizeValue($value);
            } else {
                $sanitized[$key] = $this->sanitizeValue($value);
            }
        }

        return $sanitized;
    }

    /**
     * Sanitizar un valor individual
     *
     * @param mixed $value
     * @return mixed
     */
    private function sanitizeValue(mixed $value): mixed
    {
        if (is_array($value)) {
            $sanitized = [];
            foreach ($value as $k => $v) {
                $sanitized[$k] = $this->sanitizeValue($v);
            }
            return $sanitized;
        }

        if (is_bool($value)) {
            return (bool) $value;
        }

        if (is_numeric($value)) {
            return is_float($value) ? (float) $value : (int) $value;
        }

        if (is_string($value) && filter_var($value, FILTER_VALIDATE_URL)) {
            return esc_url_raw($value);
        }

        if (is_string($value)) {
            return sanitize_text_field($value);
        }

        return $value;
    }

    /**
     * Validar una URL
     *
     * @param string $url
     * @return bool
     */
    public function isValidUrl(string $url): bool
    {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }

    /**
     * Validar un color hexadecimal
     *
     * @param string $color
     * @return bool
     */
    public function isValidColor(string $color): bool
    {
        return preg_match('/^#[0-9A-F]{6}$/i', $color) === 1;
    }

    /**
     * Validar nombre de componente
     *
     * @param string $name
     * @return bool
     */
    public function isValidComponentName(string $name): bool
    {
        // Solo letras minúsculas, números y guiones bajos
        return preg_match('/^[a-z0-9_]+$/', $name) === 1;
    }
}
