<?php

namespace WPUltimateSecurity\UltimateSecurity\Support\Validation\Rules;

/**
 * Array Rule
 *
 * Validates that a value is an array.
 *
 * @package WPUltimateSecurity\UltimateSecurity\Support\Validation\Rules
 * @since 2.0.0
 */
class ArrayRule extends AbstractRule
{
    /**
     * Minimum array size.
     *
     * @var int|null
     */
    private ?int $minSize = null;

    /**
     * Maximum array size.
     *
     * @var int|null
     */
    private ?int $maxSize = null;

    /**
     * Required keys.
     *
     * @var array
     */
    private array $requiredKeys = [];

    /**
     * Set minimum size.
     *
     * @param int $size Minimum size.
     *
     * @return static
     */
    public function min(int $size): static
    {
        $clone = clone $this;
        $clone->minSize = $size;

        return $clone;
    }

    /**
     * Set maximum size.
     *
     * @param int $size Maximum size.
     *
     * @return static
     */
    public function max(int $size): static
    {
        $clone = clone $this;
        $clone->maxSize = $size;

        return $clone;
    }

    /**
     * Set size between min and max.
     *
     * @param int $min Minimum size.
     * @param int $max Maximum size.
     *
     * @return static
     */
    public function between(int $min, int $max): static
    {
        return $this->min($min)->max($max);
    }

    /**
     * Require specific keys to be present.
     *
     * @param array $keys Required keys.
     *
     * @return static
     */
    public function hasKeys(array $keys): static
    {
        $clone = clone $this;
        $clone->requiredKeys = $keys;

        return $clone;
    }

    /**
     * {@inheritDoc}
     */
    public function validate(mixed $value, string $field, array $data = []): bool
    {
        // Allow null values (use RequiredRule if field is required)
        if ($value === null) {
            return true;
        }

        if (!is_array($value)) {
            return false;
        }

        $size = count($value);

        if ($this->minSize !== null && $size < $this->minSize) {
            return false;
        }

        if ($this->maxSize !== null && $size > $this->maxSize) {
            return false;
        }

        // Check required keys
        foreach ($this->requiredKeys as $key) {
            if (!array_key_exists($key, $value)) {
                return false;
            }
        }

        return true;
    }

    /**
     * {@inheritDoc}
     */
    public function getName(): string
    {
        return 'array';
    }

    /**
     * {@inheritDoc}
     */
    protected function getDefaultMessage(string $field): string
    {
        if (!empty($this->requiredKeys)) {
            return sprintf(
                /* translators: 1: field name, 2: required keys */
                __('The %1$s must contain the keys: %2$s.', 'ultimate-security'),
                $field,
                implode(', ', $this->requiredKeys)
            );
        }

        if ($this->minSize !== null && $this->maxSize !== null) {
            return sprintf(
                /* translators: 1: field name, 2: min size, 3: max size */
                __('The %1$s must have between %2$d and %3$d items.', 'ultimate-security'),
                $field,
                $this->minSize,
                $this->maxSize
            );
        }

        if ($this->minSize !== null) {
            return sprintf(
                /* translators: 1: field name, 2: min size */
                __('The %1$s must have at least %2$d items.', 'ultimate-security'),
                $field,
                $this->minSize
            );
        }

        if ($this->maxSize !== null) {
            return sprintf(
                /* translators: 1: field name, 2: max size */
                __('The %1$s must not have more than %2$d items.', 'ultimate-security'),
                $field,
                $this->maxSize
            );
        }

        return sprintf(
            /* translators: %s: field name */
            __('The %s must be an array.', 'ultimate-security'),
            $field
        );
    }
}
