<?php

namespace GriffinForms\Frontend\Security\FieldValidations;

class InputPhone extends Format
{
    protected function customValidate($value, $iteration_index)
    {
        $value = trim((string) $value);
        if ($value === '') {
            return;
        }

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

        $digits = $this->getDigits($value);

        if (!empty($this->validations['min_digits']) && is_numeric($this->validations['min_digits'])) {
            $min_digits = absint($this->validations['min_digits']);
            if ($min_digits > 0 && strlen($digits) < $min_digits) {
                /* translators: %d refers to the minimum number of digits required for the phone number. */
                $this->addError(sprintf(__('Enter at least %d digits.', 'griffinforms-form-builder'), $min_digits), $iteration_index);
            }
        }

        if (!empty($this->validations['max_digits']) && is_numeric($this->validations['max_digits'])) {
            $max_digits = absint($this->validations['max_digits']);
            if ($max_digits > 0 && strlen($digits) > $max_digits) {
                /* translators: %d refers to the maximum number of digits allowed for the phone number. */
                $this->addError(sprintf(__('Enter no more than %d digits.', 'griffinforms-form-builder'), $max_digits), $iteration_index);
            }
        }

        if (!empty($this->validations['format_type']) && $this->validations['format_type'] !== 'any_format') {
            $this->validateFormatType($value, $digits, $iteration_index);
        }

        if (
            isset($this->validations['allow_extension'])
            && (int) $this->validations['allow_extension'] === 0
            && $this->containsExtension($value)
        ) {
            $this->addError(__('Extensions are not allowed in this phone number.', 'griffinforms-form-builder'), $iteration_index);
        }

        if (!empty($this->validations['allowed_country_codes']) && is_array($this->validations['allowed_country_codes'])) {
            $this->validateAllowedCountryCodes($digits, $this->validations['allowed_country_codes'], $iteration_index);
        }

        if (!empty($this->validations['pattern'])) {
            $this->validatePattern($value, $this->validations['pattern'], $iteration_index);
        }
    }

    private function isBasicFormatValid($value)
    {
        $allowed_pattern = '/^[0-9()+\-\\s.#xextEXT]*$/';
        $digits = $this->getDigits($value);

        if (!preg_match($allowed_pattern, $value)) {
            return false;
        }

        return strlen($digits) >= 5;
    }

    private function getDigits($value)
    {
        return preg_replace('/\D+/', '', (string) $value);
    }

    private function containsExtension($value)
    {
        return (bool) preg_match('/(ext\\.?|extension|x|#)\\s*\\d+$/i', $value);
    }

    private function validateFormatType($value, $digits, $iteration_index)
    {
        $format_type = $this->validations['format_type'];

        if ('international_format' === $format_type) {
            if (!(strpos($value, '+') === 0 || strpos($value, '00') === 0)) {
                $this->addError(__('Use the international format (for example, +14155552671).', 'griffinforms-form-builder'), $iteration_index);
                return;
            }

            $length = strlen($digits);
            if ($length < 8 || $length > 15) {
                $this->addError(__('Use the international format (for example, +14155552671).', 'griffinforms-form-builder'), $iteration_index);
            }
        }

        if ('national_format' === $format_type) {
            if (strlen($digits) > 0 && strlen($digits) < 6) {
                $this->addError(__('Use the national format without an international country code.', 'griffinforms-form-builder'), $iteration_index);
            }
        }
    }

    private function validateAllowedCountryCodes($digits, array $codes, $iteration_index)
    {
        $codes = array_filter(array_map('trim', $codes));
        if (empty($codes) || $digits === '') {
            return;
        }

        foreach ($codes as $code) {
            if ($code !== '' && strpos($digits, $code) === 0) {
                return;
            }
        }

        /* translators: %s refers to a list of allowed country codes. */
        $this->addError(sprintf(__('The phone number must start with one of the following country codes: %s.', 'griffinforms-form-builder'), implode(', ', $codes)), $iteration_index);
    }
}
