<?php

namespace WPUltimateSecurity\UltimateSecurity\Support\Validation\Rules;

/**
 * Boolean Rule
 *
 * Validates that a value is a boolean or boolean-like.
 *
 * @package WPUltimateSecurity\UltimateSecurity\Support\Validation\Rules
 * @since 2.0.0
 */
class BooleanRule extends AbstractRule
{
    /**
     * Whether to use strict mode (only true/false).
     *
     * @var bool
     */
    private bool $strict = false;

    /**
     * Additional truthy values.
     *
     * @var array
     */
    private array $truthyValues = ['1', 'true', 'yes', 'on', 1];

    /**
     * Additional falsy values.
     *
     * @var array
     */
    private array $falsyValues = ['0', 'false', 'no', 'off', 0, ''];

    /**
     * Use strict mode (only true/false).
     *
     * @return static
     */
    public function strict(): static
    {
        $clone = clone $this;
        $clone->strict = true;

        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;
        }

        // Strict mode: only true/false
        if ($this->strict) {
            return is_bool($value);
        }

        // Loose mode: accept boolean-like values
        if (is_bool($value)) {
            return true;
        }

        // Check truthy values
        if (in_array($value, $this->truthyValues, true)) {
            return true;
        }

        // Check falsy values
        if (in_array($value, $this->falsyValues, true)) {
            return true;
        }

        return false;
    }

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

    /**
     * {@inheritDoc}
     */
    protected function getDefaultMessage(string $field): string
    {
        return sprintf(
            /* translators: %s: field name */
            __('The %s must be true or false.', 'ultimate-security'),
            $field
        );
    }

    /**
     * Convert a value to boolean.
     *
     * @param mixed $value The value to convert.
     *
     * @return bool|null Returns null if not a valid boolean-like value.
     */
    public static function toBoolean(mixed $value): ?bool
    {
        if (is_bool($value)) {
            return $value;
        }

        $truthyValues = ['1', 'true', 'yes', 'on', 1];
        $falsyValues = ['0', 'false', 'no', 'off', 0, ''];

        if (in_array($value, $truthyValues, true)) {
            return true;
        }

        if (in_array($value, $falsyValues, true)) {
            return false;
        }

        return null;
    }
}
