<?php

namespace WPUltimateSecurity\UltimateSecurity\Support\Validation;

/**
 * Validation Result
 *
 * Represents the result of a validation operation.
 *
 * @package WPUltimateSecurity\UltimateSecurity\Support\Validation
 * @since 2.0.0
 */
class ValidationResult
{
    /**
     * Whether the validation passed.
     *
     * @var bool
     */
    private bool $valid;

    /**
     * Validation errors indexed by field name.
     *
     * @var array<string, array<string>>
     */
    private array $errors;

    /**
     * The validated data.
     *
     * @var array
     */
    private array $data;

    /**
     * Create a new validation result.
     *
     * @param bool  $valid  Whether validation passed.
     * @param array $errors Validation errors.
     * @param array $data   The validated data.
     */
    public function __construct(bool $valid, array $errors = [], array $data = [])
    {
        $this->valid = $valid;
        $this->errors = $errors;
        $this->data = $data;
    }

    /**
     * Create a successful validation result.
     *
     * @param array $data The validated data.
     *
     * @return self
     */
    public static function success(array $data = []): self
    {
        return new self(true, [], $data);
    }

    /**
     * Create a failed validation result.
     *
     * @param array $errors The validation errors.
     * @param array $data   The original data.
     *
     * @return self
     */
    public static function failure(array $errors, array $data = []): self
    {
        return new self(false, $errors, $data);
    }

    /**
     * Check if validation passed.
     *
     * @return bool
     */
    public function isValid(): bool
    {
        return $this->valid;
    }

    /**
     * Check if validation failed.
     *
     * @return bool
     */
    public function isFailed(): bool
    {
        return !$this->valid;
    }

    /**
     * Get all errors.
     *
     * @return array<string, array<string>>
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Get errors for a specific field.
     *
     * @param string $field The field name.
     *
     * @return array<string>
     */
    public function getFieldErrors(string $field): array
    {
        return $this->errors[$field] ?? [];
    }

    /**
     * Get the first error for a field.
     *
     * @param string $field The field name.
     *
     * @return string|null
     */
    public function getFirstError(string $field): ?string
    {
        return $this->errors[$field][0] ?? null;
    }

    /**
     * Get all errors as a flat array.
     *
     * @return array<string>
     */
    public function getAllErrors(): array
    {
        $allErrors = [];

        foreach ($this->errors as $fieldErrors) {
            $allErrors = array_merge($allErrors, $fieldErrors);
        }

        return $allErrors;
    }

    /**
     * Get the first error message.
     *
     * @return string|null
     */
    public function getFirstErrorMessage(): ?string
    {
        foreach ($this->errors as $fieldErrors) {
            if (!empty($fieldErrors)) {
                return $fieldErrors[0];
            }
        }

        return null;
    }

    /**
     * Get the validated data.
     *
     * @return array
     */
    public function getData(): array
    {
        return $this->data;
    }

    /**
     * Get a specific validated value.
     *
     * @param string $key     The key to retrieve.
     * @param mixed  $default Default value if not found.
     *
     * @return mixed
     */
    public function getValue(string $key, mixed $default = null): mixed
    {
        return $this->data[$key] ?? $default;
    }

    /**
     * Check if a field has errors.
     *
     * @param string $field The field name.
     *
     * @return bool
     */
    public function hasError(string $field): bool
    {
        return !empty($this->errors[$field]);
    }

    /**
     * Get the error count.
     *
     * @return int
     */
    public function getErrorCount(): int
    {
        return count($this->getAllErrors());
    }

    /**
     * Convert to array.
     *
     * @return array
     */
    public function toArray(): array
    {
        return [
            'valid' => $this->valid,
            'errors' => $this->errors,
            'data' => $this->data,
        ];
    }

    /**
     * Convert to WP_Error for REST API responses.
     *
     * @param string $code The error code.
     *
     * @return \WP_Error
     */
    public function toWpError(string $code = 'validation_error'): \WP_Error
    {
        $wpError = new \WP_Error();

        foreach ($this->errors as $field => $messages) {
            foreach ($messages as $message) {
                $wpError->add($code, $message, ['field' => $field]);
            }
        }

        return $wpError;
    }
}
