<?php

namespace GriffinForms\Frontend\Security\FieldValidations;

class InputNumber extends Format
{
    // Custom validation for input number fields
    protected function customValidate($value, $iteration_index)
    {
        $validations = $this->field->getProp('validations');
    
        // Validate if the value is numeric; if not, add an error and stop further validation
        if (!$this->validateIsNumber($value)) {
            return;
        }
    
        // Minimum number validation
        if (!empty($validations['min']) && is_numeric($validations['min'])) {
            $this->validateMinNumber($value, $validations['min']);
        }
    
        // Maximum number validation
        if (!empty($validations['max']) && is_numeric($validations['max'])) {
            $this->validateMaxNumber($value, $validations['max']);
        }
    
        // Odd number validation
        if (!empty($validations['number_type']) && $validations['number_type'] === 'odd_numbers') {
            $this->validateOddNumber($value);
        }
    
        // Even number validation
        if (!empty($validations['number_type']) && $validations['number_type'] === 'even_numbers') {
            $this->validateEvenNumber($value);
        }
    
        // Whole number validation (no decimal)
        if (!empty($validations['type']) && $validations['type'] === 'custom-parameters' && empty($validations['allow_decimal'])) {
            $this->validateWholeNumber($value);
        }
    
        // Multiples of specific values
        if (!empty($validations['type']) && $validations['type'] === 'multiples_of' && !empty($validations['multiples'])) {
            $this->validateMultiplesOf($value, $validations['multiples']);
        }
    
        if (!empty($validations['pattern'])) {
            $this->validatePattern($value, $validations['pattern'], $iteration_index);
        }
    }

    // Validate if the value is numeric
    private function validateIsNumber($value)
    {
        // Treat 'NaN' as invalid
        if ($value === 'NaN') {
            $this->addError(__('Please enter a valid number.', 'griffinforms-form-builder'));
            return false;
        }

        // Skip validation for empty values
        if ($value === '' || $value === null) {
            return true; // Let validateIsRequired() handle empty checks
        }

        if (!is_numeric($value)) {
            $this->addError(__('Please enter a valid number.', 'griffinforms-form-builder'));
            return false;
        }

        return true;
    }

    // Validate minimum number
    private function validateMinNumber($value, $min)
    {
        $value = floatval($value); // Make sure we are comparing numbers properly
        
        if ($value < $min) {
            /* translators: %d is the minimum allowed value for a numeric field */
            $this->addError(sprintf(__('The number must be at least %d.', 'griffinforms-form-builder'), $min));
        }
    }

    // Validate maximum number
    private function validateMaxNumber($value, $max)
    {
        $value = floatval($value); // Ensure accurate comparison
        if ($value > $max) {
            /* translators: %d is the maximum allowed value for a numeric field */
            $this->addError(sprintf(__('The number must not exceed %d.', 'griffinforms-form-builder'), $max));
        }
    }

    // Validate odd numbers
    private function validateOddNumber($value)
    {
        $value = intval($value); // Ensure we are working with an integer
        if ($value % 2 === 0) { // Even numbers will fail this check
            $this->addError(__('The number must be odd.', 'griffinforms-form-builder'));
        }
    }

    // Validate even numbers
    private function validateEvenNumber($value)
    {
        $value = intval($value); // Convert to integer
        if ($value % 2 !== 0) { // Odd numbers will fail this check
            $this->addError(__('The number must be even.', 'griffinforms-form-builder'));
        }
    }

    // Validate whole numbers (no decimal places)
    private function validateWholeNumber($value)
    {
        if (is_float($value) && floor($value) != $value) {
            $this->addError(__('The number must be a whole number (no decimals).', 'griffinforms-form-builder'));
        }
    }

    // Validate multiples of specific values
    private function validateMultiplesOf($value, $multiples)
    {
        // Ensure $multiples is a string before using explode
        if (is_array($multiples)) {
            $multiples = implode(',', $multiples); // Convert array to comma-separated string
        }

        // Convert comma-separated string into an array, trim spaces, and ensure all values are numeric
        $multiples_array = array_map('trim', explode(',', $multiples));
        $multiples_array = array_filter($multiples_array, function ($val) {
            return is_numeric($val) && $val != 0; // Ensure valid numeric values and ignore zero
        });

        // Handle case where multiples array is empty after filtering
        if (empty($multiples_array)) {
            $this->addError(__('Multiples list is empty or invalid.', 'griffinforms-form-builder'));
            return;
        }

        $failed_multiples = [];

        // Convert $value to integer/float for accurate division
        $numeric_value = floatval($value);

        // Check if the value is a multiple of any number in the array
        foreach ($multiples_array as $multiple) {
            if ($numeric_value % floatval($multiple) !== 0) {
                $failed_multiples[] = $multiple;
            }
        }

        // If all multiples fail, add an error
        if (count($failed_multiples) === count($multiples_array)) {
            /* translators: %s is a comma-separated list of valid multiples for the numeric field */
            $this->addError(sprintf(__('The number must be a multiple of one of the following values: %s.', 'griffinforms-form-builder'), implode(', ', $multiples_array)));
        }
    }
}