<?php

namespace GriffinForms\Frontend\Security\FieldValidations;

/**
 * Class InputCheckbox
 * Handles validation for checkbox fields in GriffinForms.
 */
class InputCheckbox extends Format
{
    /**
     * Perform custom validation for the input checkbox field.
     *
     * @param array $values The selected checkbox values.
     */
    protected function customValidate($values, $iteration_index)
    {
        $validations = $this->field->getProp('validations');
        $fieldOptions = $this->field->getProp('field_options');
    
        // ✅ Ensure values is always an array
        if (!is_array($values)) {
            $values = is_string($values) ? json_decode($values, true) : [];
            if (!is_array($values)) {
                $values = []; // Force it to be an empty array if decoding fails
            }
        }
    
        // Ensure all selected values are valid options.
        if (!empty($fieldOptions) && is_array($fieldOptions)) {
            $validValues = $this->extractValidOptions($fieldOptions);
            $this->validateOptionExists($values, $validValues);
        }
    
        // Min checks validation: Ensure at least 'min_checks' checkboxes are selected.
        if (!empty($validations['min_checks']) && is_numeric($validations['min_checks'])) {
            if (count($values) < (int) $validations['min_checks']) {
                /* translators: %d is the minimum number of checkboxes the user must select */
                $this->addError(sprintf(__('You must select at least %d options.', 'griffinforms-form-builder'), $validations['min_checks']));
            }
        }
    
        // Max checks validation: Ensure no more than 'max_checks' checkboxes are selected.
        if (!empty($validations['max_checks']) && is_numeric($validations['max_checks'])) {
            if (count($values) > (int) $validations['max_checks']) {
                /* translators: %d is the maximum number of checkboxes the user is allowed to select */
                $this->addError(message: sprintf(__('You can select a maximum of %d options.', 'griffinforms-form-builder'), $validations['max_checks']));
            }
        }
    }

    /**
     * Validate minimum number of selections.
     *
     * @param array $values The selected checkbox values.
     * @param int $min_checks The minimum number of required selections.
     */
    private function validateMinChecks($values, $min_checks)
    {
        if (count($values) < $min_checks) {
            /* translators: %d is the minimum number of checkboxes the user must select */
            $this->addError(sprintf(__('You must select at least %d options.', 'griffinforms-form-builder'), $min_checks));
        }
    }

    /**
     * Validate maximum number of selections.
     *
     * @param array $values The selected checkbox values.
     * @param int $max_checks The maximum number of allowed selections.
     */
    private function validateMaxChecks($values, $max_checks)
    {
        if (count($values) > $max_checks) {
            /* translators: %d is the maximum number of checkboxes the user is allowed to select */
            $this->addError(sprintf(__('You cannot select more than %d options.', 'griffinforms-form-builder'), $max_checks));
        }
    }

    /**
     * Extracts valid checkbox options from field_options.
     *
     * @param array $fieldOptions The field options stored in the database.
     * @return array The valid option values.
     */
    private function extractValidOptions($fieldOptions)
    {
        $validValues = [];

        foreach ($fieldOptions as $optionGroup) {
            if (is_array($optionGroup)) {
                foreach ($optionGroup as $label => $value) {
                    $validValues[] = $value; // Extract value from associative array
                }
            }
        }

        return $validValues;
    }

    /**
     * Validates that all selected checkboxes exist in the predefined options.
     *
     * @param array $values The selected checkbox values.
     * @param array $validValues The list of allowed checkbox values.
     */
    private function validateOptionExists($values, $validValues)
    {
        foreach ($values as $selectedValue) {
            if (!in_array($selectedValue, $validValues, true)) {
                /* translators: Message shown when selected checkbox values do not match allowed options */
                $this->addError(__('Invalid selection: One or more selected values are not valid options.', 'griffinforms-form-builder'));
                return; // Stop further checks after detecting an invalid value
            }
        }
    }
}