<?php
declare(strict_types=1);

namespace ROITheme\Shared\Domain\Contracts;

/**
 * ValidationServiceInterface - Contrato para servicio de validación
 *
 * RESPONSABILIDAD: Definir contrato para validación de datos de entrada
 *
 * PROPÓSITO:
 * - Validar datos antes de crear entidades de dominio
 * - Sanitizar entrada del usuario
 * - Retornar errores de validación estructurados
 *
 * UBICACIÓN EN ARQUITECTURA:
 * - Interfaz definida en Domain
 * - Implementación en Infrastructure (puede usar WordPress functions)
 * - Usado por Application Layer (Use Cases)
 *
 * IMPLEMENTACIONES ESPERADAS:
 * - WordPressValidationService (usa sanitize_*, wp_kses, etc.)
 * - StrictValidationService (validación más estricta para prod)
 * - LenientValidationService (validación más permisiva para dev)
 *
 * USO:
 * ```php
 * // En Application Layer
 * class SaveComponentUseCase {
 *     public function __construct(
 *         private ValidationServiceInterface $validator
 *     ) {}
 *
 *     public function execute(SaveComponentRequest $request): void {
 *         $result = $this->validator->validate(
 *             $request->getData(),
 *             $request->getComponentName()
 *         );
 *
 *         if (!$result->isValid()) {
 *             throw new ValidationException($result->getErrors());
 *         }
 *
 *         // ... crear componente con datos validados
 *     }
 * }
 * ```
 *
 * @package ROITheme\Shared\Domain\Contracts
 */
interface ValidationServiceInterface
{
    /**
     * Validar datos de un componente
     *
     * @param array $data Datos a validar
     * @param string $componentName Nombre del componente (para reglas específicas)
     * @return ValidationResult Resultado de validación
     */
    public function validate(array $data, string $componentName): ValidationResult;

    /**
     * Sanitizar datos de entrada
     *
     * @param array $data Datos a sanitizar
     * @param string $componentName Nombre del componente
     * @return array Datos sanitizados
     */
    public function sanitize(array $data, string $componentName): array;

    /**
     * Validar una URL
     *
     * @param string $url URL a validar
     * @return bool
     */
    public function isValidUrl(string $url): bool;

    /**
     * Validar un color hexadecimal
     *
     * @param string $color Color a validar (ej: #000000)
     * @return bool
     */
    public function isValidColor(string $color): bool;

    /**
     * Validar nombre de componente
     *
     * @param string $name Nombre a validar
     * @return bool
     */
    public function isValidComponentName(string $name): bool;
}

/**
 * ValidationResult - Value Object para resultado de validación
 *
 * RESPONSABILIDAD: Encapsular resultado de una validación
 *
 * @package ROITheme\Shared\Domain\Contracts
 */
final readonly class ValidationResult
{
    /**
     * Constructor
     *
     * @param bool $isValid Si la validación pasó
     * @param array $errors Array de errores (campo => mensaje)
     * @param array $sanitizedData Datos sanitizados
     */
    public function __construct(
        private bool $isValid,
        private array $errors = [],
        private array $sanitizedData = []
    ) {}

    /**
     * Verificar si la validación pasó
     *
     * @return bool
     */
    public function isValid(): bool
    {
        return $this->isValid;
    }

    /**
     * Obtener errores de validación
     *
     * @return array Array asociativo campo => mensaje
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Obtener datos sanitizados
     *
     * @return array
     */
    public function getSanitizedData(): array
    {
        return $this->sanitizedData;
    }

    /**
     * Verificar si hay error en campo específico
     *
     * @param string $field
     * @return bool
     */
    public function hasError(string $field): bool
    {
        return isset($this->errors[$field]);
    }

    /**
     * Obtener error de un campo específico
     *
     * @param string $field
     * @return string|null
     */
    public function getError(string $field): ?string
    {
        return $this->errors[$field] ?? null;
    }

    /**
     * Factory: Resultado exitoso
     *
     * @param array $sanitizedData
     * @return self
     */
    public static function success(array $sanitizedData): self
    {
        return new self(
            isValid: true,
            errors: [],
            sanitizedData: $sanitizedData
        );
    }

    /**
     * Factory: Resultado con errores
     *
     * @param array $errors
     * @return self
     */
    public static function failure(array $errors): self
    {
        return new self(
            isValid: false,
            errors: $errors,
            sanitizedData: []
        );
    }
}
