/**
* Class for handling country code functionality in Elementor forms.
*/
class FormCCFEF extends elementorModules.frontend.handlers.Base {

    /**
     * Retrieves the default settings for the country code functionality.
     * @returns {Object} An object containing selector configurations.
     */
    getDefaultSettings() {
        return {
            selectors: {
                inputTelTextArea: 'textarea.ccfef_country_code_data_js',
                intlInputSpan: '.ccfef-editor-intl-input',
                submitButton: 'div.elementor-field-type-submit button',
                form: ".elementor-form"
            },
        };
    }

    /**
     * Retrieves the default elements based on the settings defined.
     * @returns {Object} An object containing jQuery elements for the text area and editor span.
     */
    getDefaultElements() {
        const selectors = this.getSettings('selectors');
        return {
            $textArea: this.$element.find(selectors.inputTelTextArea),
            $intlSpanElement: this.$element.find(selectors.intlInputSpan),
            $submitButton: this.$element.find(selectors.submitButton),
            $form: this.$element.find(selectors.form),
        };
    }

    /**
     * Binds events to the elements. This method is intended to be overridden by subclasses to add specific event handlers.
     */
    bindEvents() {
        this.telId = new Array(); // Array to store telephone IDs

        this.includeCountries = {}; // Object to store countries to include

        this.excludeCountries = {}; // Object to store countries to exclude

        this.defaultCountry = {};

        this.commonCountries = {}; // NEW: Object to store flag if common-countries === 'same'

        this.dialCodeVisibility = {};

        this.countryStrictMode = {}; 

        this.iti = {}; // Object to store international telephone input instances

        this.getIntlUserData(); // Retrieves international telephone input data from the DOM and stores them for further processing.

        this.appendCountryCodeHandler(); // Appends a country code handler to each telephone input field to manage country code functionality.

        this.addCountryCodeInputHandler(); // Adds a country code input handler that initializes the international telephone input functionality.

        this.customFlags() // custom load svg flags

        this.removeInputTelSpanEle(); // Removes the telephone input span element from the DOM, typically used to clean up after modifications.

        this.intlInputValidation(); // Validates the international input fields to ensure they meet specific criteria.
    }    

    /**
     * Method to handle appending country code.
     */
    appendCountryCodeHandler() {
        this.telId.forEach(data => {
            this.addCountryCodeIconHandler(data.formId, data.fieldId, data.customId);
        });
    }


    /**
     * Method to handle country code input.
     */
    addCountryCodeInputHandler() {
        const itiArr = this.iti;

        Object.keys(itiArr).forEach(key => {
            const iti = itiArr[key];
            const inputElement = iti.telInput;

            let previousCountryData = iti.getSelectedCountryData();
            let previousCode = `+${previousCountryData.dialCode}`;
            let keyUpEvent = false;

            const resetKeyUpEventStatus = () => {
                keyUpEvent = false;
            };

            const handleCountryChange = (e) => {
                this.customFlags();
                const currentCountryData = iti.getSelectedCountryData();
                const currentCode = `+${currentCountryData.dialCode}`;
                if (e.type === 'keydown' || e.type=== 'input') {
                    keyUpEvent = true;
                    clearTimeout(resetKeyUpEventStatus);
                    setTimeout(resetKeyUpEventStatus, 400);

                    if (previousCountryData.dialCode !== currentCountryData.dialCode) {
                        previousCountryData = currentCountryData;
                    } else if (previousCountryData.dialCode === currentCountryData.dialCode && previousCountryData.iso2 !== currentCountryData.iso2) {
                        iti.setCountry(previousCountryData.iso2);
                    }
                } else if (e.type === "countrychange") {
                    if (keyUpEvent) {
                        return;
                    }

                    previousCountryData = currentCountryData;
                }

                if(e.currentTarget.value.startsWith(currentCode.replace('+',''))){
                    this.updateCountryCodeHandler(e.currentTarget, '+', previousCode, this.dialCodeVisibility[key]);
                }else{
                    this.updateCountryCodeHandler(e.currentTarget, currentCode, previousCode, this.dialCodeVisibility[key]);
                    previousCode = currentCode;
                }
            };

            // Attach event listeners for both keyup and country change events
            inputElement.addEventListener('keydown', handleCountryChange);
            inputElement.addEventListener('input', handleCountryChange);
            inputElement.addEventListener('countrychange', handleCountryChange);
        });
    }

     /**
     * Method to handle adding country code icon.
     * @param {string} id - The ID of the element.
     * @param {string} widgetId - The widget ID.
     */
     addCountryCodeIconHandler(formId, widgetId, inputId) {
        const utilsPath = CCFEFCustomData.pluginDir + 'assets/addons/intl-tel-input/js/utils.min.js';
        const telFIeld = jQuery(`.elementor-widget.elementor-widget-form[data-id="${formId}"] .elementor-field-type-tel.elementor-field-group input[type="tel"]#${inputId}`)[0];
        
        if (undefined !== telFIeld) {
            let includeCountries = [];
            let excludeCountries = [];
            let defaultCountry = 'in';
            const defaultCoutiresArr = ['in','us','gb','ru','fr','de','br','cn','jp','it'];
            const uniqueId = `${formId}${widgetId}`;
    
            if (this.includeCountries.hasOwnProperty(uniqueId) && this.includeCountries[uniqueId].length > 0) {
                defaultCountry = this.includeCountries[uniqueId][0];
                includeCountries = [...this.includeCountries[uniqueId]];
            }
    
            if (this.excludeCountries.hasOwnProperty(uniqueId) && this.excludeCountries[uniqueId].length > 0) {
                let uniqueValue = defaultCoutiresArr.filter((value) => !this.excludeCountries[uniqueId].includes(value));
                defaultCountry = uniqueValue[0];
                excludeCountries = [...this.excludeCountries[uniqueId]];
            }
    
            if (this.defaultCountry[uniqueId] && '' !== this.defaultCountry[uniqueId]) {
                defaultCountry = this.defaultCountry[uniqueId];
            }
    
            // Initialize the international telephone input.
            const iti = window.intlTelInput(telFIeld, {
                initialCountry: defaultCountry,
                utilsScript: utilsPath,
                dialCodeVisibility: this.dialCodeVisibility[uniqueId],
                strictMode: (this.countryStrictMode[uniqueId] === 'yes') ? true : false, 
                separateDialCode: this.dialCodeVisibility[uniqueId] === 'separate' ? true : false,
                formatOnDisplay: false,
                formatAsYouType: true,
                autoFormat: false,
                containerClass: 'cfefp-intl-container',
                useFullscreenPopup: false,
                onlyCountries: includeCountries,
                excludeCountries: excludeCountries,
                customPlaceholder: (selectedCountryPlaceholder, selectedCountryData) => {
                    
                    // If the commonAttr flag is 'same', return a simple placeholder.
                    if (this.commonCountries[uniqueId]) {
                        return "No country found";
                    }
                    
                    if (!selectedCountryData || !selectedCountryPlaceholder || !selectedCountryData.dialCode) {
                        return "No country found";
                    }
                    
                    let placeHolder = selectedCountryPlaceholder;
                    if ('in' === selectedCountryData.iso2) {
                        placeHolder = selectedCountryPlaceholder.replace(/^0+/, '');
                    }
                    
                    const placeholderText = this.dialCodeVisibility[uniqueId] === 'separate' || this.dialCodeVisibility[uniqueId] === 'hide' ? `${placeHolder}` : `+${selectedCountryData.dialCode} ${placeHolder}`;
                    return placeholderText;
                },            
            });
            
            // Add styling for separate dial code
            if (this.dialCodeVisibility[uniqueId] === 'separate') {
                const style = document.createElement('style');
                style.textContent = `
                    .cfefp-intl-container .iti__selected-dial-code,
                    .cfefp-intl-container .iti__selected-flag {
                        color: var(--e-form-field-text-color, #7a7a7a) !important;
                    }
                    .cfefp-intl-container .iti__selected-dial-code {
                        font-size: inherit !important;
                        font-family: inherit !important;
                        line-height: inherit !important;
                    }
                `;
                document.head.appendChild(style);
            }
            // Retrieve commonAttr from the hidden span to decide whether to hide the country list.
            const intlSpan = document.querySelector(`.elementor-widget.elementor-widget-form[data-id="${formId}"] .ccfef-editor-intl-input[data-field-id="${widgetId}"]`);
            const commonAttr = intlSpan ? intlSpan.getAttribute('data-common-countries') : '';
            if ('same' === commonAttr && this.commonCountries[uniqueId] && '' !== includeCountries && '' !== excludeCountries) {
                const countryList = iti.countryList;
                if (countryList && countryList.classList.contains('iti__country-list')) {
                    countryList.style.display = 'none';
                }
            }
             else {
                // Filter the country list: show only the countries that are in includeCountries and not in excludeCountries.
                            const countryList = iti.countryList;
                if (countryList && countryList.classList.contains('iti__country-list')) {
                    // Select all individual country items.
                    const countryItems = countryList.querySelectorAll('.iti__country');
                    
                    // Hide items if they are in the excludeCountries list.
                    countryItems.forEach(function(item) {
                        const countryCode = item.getAttribute('data-country-code');
                        if (excludeCountries.includes(countryCode)) {
                            item.style.display = 'none';
                        }
                    });
                    
                    // Get the remaining visible country items.
                    const visibleCountries = Array.from(countryItems).filter(item => item.style.display !== 'none');
                    
                    // Filter those visible items that are present in includeCountries.
                    const includedVisibleCountries = visibleCountries.filter(item => {
                        const countryCode = item.getAttribute('data-country-code');
                        return includeCountries.includes(countryCode);
                    });
                    
                    // If there are any visible items in the include list, select the first one.
                    if (includedVisibleCountries.length > 0) {
                        const selectedItem = includedVisibleCountries.find(item => item.getAttribute('aria-selected') === 'true');
                        if (!selectedItem) {
                            const firstItem = includedVisibleCountries[0];
                            firstItem.setAttribute('aria-selected', 'true');
                            // Update the intlTelInput instance so that the country selection is reflected in the field.
                            const newCountryCode = firstItem.getAttribute('data-country-code');
                            iti.setCountry(newCountryCode);
                        }
                    }
                }
            }

            telFIeld.removeAttribute('pattern');
            this.iti[formId + widgetId] = iti;
            this.setInitialCountry(iti, excludeCountries, uniqueId, telFIeld );
        }
    }
    
    
    /**
     * Sets the initial selected country in the dropdown.
     * @param {Object} itiInstance - The intl-tel-input instance.
     * @param {string} autoDetectCountry - Auto-detect country setting.
     * @param {string} defaultCountry - Default country code.
     * @param {string} apiKey - API key for geo-location services.
     * @param {Array} excludeCountries - List of countries to exclude.
     */
    setInitialCountry(itiInstance, excludeCountries, uniqueId, telField) {       
        const defaultCountry = this.defaultCountry[uniqueId] || "";
        const defaultCountries = ['in', 'us', 'gb', 'ru', 'fr', 'de', 'br', 'cn', 'jp', 'it'];
        const itiCountriesList = itiInstance.countries.map(data => data.iso2);
        const inputElement = itiInstance.telInput;
  
        if (jQuery(telField).closest('.elementor-field-type-country').hasClass('elementor-field-required') &&
            jQuery(telField).closest('.elementor-field-type-country').hasClass('cfef-hidden')) {
            if (defaultCountry === "") {
                itiInstance.setCountry("us");
                jQuery(telField).val("United States");    
                jQuery(telField).focus()  
                jQuery(telField).trigger('change');
            } else {
                itiInstance.setCountry(defaultCountry);
                jQuery(telField).val(defaultCountry);
                jQuery(telField).focus()    
                jQuery(telField).trigger('change');
            }
        } 
     
        const setCountry = (countryCode) => {
            if (itiCountriesList.length <= 0) {
                return;
            }
            const normalizedCountryCode = isNaN(countryCode) && countryCode ? countryCode.toLowerCase() : '';
            if (normalizedCountryCode && itiCountriesList.includes(normalizedCountryCode)) {
                itiInstance.setCountry(normalizedCountryCode);
            } else if (defaultCountry && itiCountriesList.includes(defaultCountry)) {
                itiInstance.setCountry(defaultCountry);
         
            } else {
                const availableCountries = defaultCountries.filter(country =>
                    !excludeCountries.includes(country) && itiCountriesList.includes(country)
                );
              
                const fallbackCountry = availableCountries.length > 0 ? availableCountries[0] : itiCountriesList[0];
                itiInstance.setCountry(fallbackCountry);
            }
  
            const selectedCountry = itiInstance.getSelectedCountryData();
         
            if (selectedCountry.hasOwnProperty('iso2')) {
                // inputElement.value = selectedCountry.name;
            }
        };
  
        if (defaultCountry) {
            setCountry(defaultCountry);
        }      
    }
    /**
     * Method to update country code.
     * @param {Element} element - The input element.
     * @param {string} countryCode - The country code.
     * @param {string} previousCode - The previous country code.
     */
    updateCountryCodeHandler(element, currentCode, previousCode,dialCodeVisibility) {
        let value = element.value;
        
        if(currentCode && '+undefined' === currentCode || ['','+'].includes(value)){
            return;
        }
        
        if (currentCode !== previousCode) {
            value = value.replace(new RegExp(`^\\${previousCode}`), '');
        }
        
        if (!value.startsWith(currentCode)) {
            value = value.replace(/\+/g, '');
            element.value = dialCodeVisibility === 'separate' || dialCodeVisibility === 'hide' ? value : currentCode + value;
        }

        else if (value.length > 12) {
            const plainCode = currentCode.replace('+', '');
            const doublePrefix = `+${plainCode}${plainCode}`;

            if (value.startsWith(doublePrefix)) {
                element.value = `+${value.slice(currentCode.length)}`;
            }
        }
    }

    customFlags() {
        const selectedCountries = this.$element.find('.cfefp-intl-container .iti__country-container .iti__flag:not(.iti__globe)');
    
        // Loop through each flag element
        selectedCountries.each(function() {
            const selectedCountry = this;  // 'this' refers to the current element in the loop
            const classList = selectedCountry.className.split(' '); 
            
            if (classList[1]) {
                const selectedCountryFlag = classList[1].split('__')[1]; 
                const svgFlagPath = CCFEFCustomData.pluginDir + `assets/addons/flags/${selectedCountryFlag}.svg`;

                // Apply the styles dynamically to the current flag
                selectedCountry.style.backgroundImage = `url('${svgFlagPath}')`;
            } 
        });
    }
        
    /**
     * Removes the span element with class 'ccfef-editor-intl-input' from the DOM.
     */
    removeInputTelSpanEle() {
        this.$element.find('span.ccfef-editor-intl-input').remove();
    }

    /**
     * Retrieves and stores unique telephone input IDs from the Elementor editor span elements.
     */
    getIntlUserData() {
        const intelInputElement = this.elements.$intlSpanElement;
        const previousIds = [];
        intelInputElement.each((_, ele) => {
            const element = jQuery(ele);
            const includeCountries=element.data('include-countries');
            const excludeCountries=element.data('exclude-countries');
            const defaultCountry=element.data('defaultCountry');
            const commonAttr=element.data('common-countries');
            const inputId = element.data('id');
            const fieldId = element.data('field-id');
            const dialCodeVisibility=element.data('dial-code-visibility');
            const countryStrictMode = element.data('strict-mode')
            const formId = element.closest('.elementor-element.elementor-widget-form').data('id');
            const currentId = `${formId}${fieldId}`;

            if ('same' === commonAttr && '' === includeCountries && '' !== excludeCountries) {
                // NEW: Store flag for use in the custom placeholder function
                this.commonCountries[currentId] = true;
            } else {
                if ('' !== includeCountries) {
                    if(isNaN(includeCountries)){
                        const splitIncludeCountries = includeCountries.split(',');
                        this.includeCountries[currentId] = splitIncludeCountries;
                    }
                }
                
                if ('' !== excludeCountries) {
                    if(isNaN(excludeCountries)){
                        const splitExcludeCountries = excludeCountries.split(',');
                        this.excludeCountries[currentId] = splitExcludeCountries;
                    }
                }
            
                // NEW: If commonAttr is not 'same' but all values in includeCountries are also present in excludeCountries, set commonCountries flag
                if ('same' !== commonAttr && '' !== includeCountries && '' !== excludeCountries) {
                    if(isNaN(includeCountries)){
                        const includeArray = includeCountries.split(',').map(item => item.trim());
                
                   if(isNaN(excludeCountries)){
                    const excludeArray = excludeCountries.split(',').map(item => item.trim());
                    const allIncludedPresent = includeArray.every(country => excludeArray.includes(country));
                    if (allIncludedPresent) {
                            this.commonCountries[currentId] = true;
                        }
                    }
                }
                }
                
                if('' !== dialCodeVisibility){
                    this.dialCodeVisibility[currentId] = dialCodeVisibility;
                }

                if('' !== countryStrictMode){
                    this.countryStrictMode[currentId] = countryStrictMode
                }

                if ('' !== defaultCountry) {
                     this.defaultCountry[currentId] = defaultCountry;
                }
            }
            

            if (!previousIds.includes(currentId)) {
                this.telId.push({ formId, fieldId, customId: inputId });
                previousIds.push(currentId);
            }
        });
    }


    // Helper: Validate all telephone fields
    validateTelInputs(e, trigger = 'submit') {

        const itiArr = this.iti;

        if (Object.keys(itiArr).length > 0) {
            Object.keys(itiArr).forEach(data => {
                const iti = itiArr[data];
              
                const inputTelElement = iti.telInput;
                
                if(jQuery(inputTelElement).closest('.elementor-field-type-tel').hasClass('cfef-hidden')){

                    inputTelElement.value = '+1234567890';

                    return;
                }

                if('' !== inputTelElement.value){
                    inputTelElement.value=inputTelElement.value.replace(/[^0-9+]/g, '');
                                                
                    // Always ensure dial code is present in the value before validation
                    const currentCountryData = iti.getSelectedCountryData();
                    const dialCode = `+${currentCountryData.dialCode}`;
                        
                    // If using separate or hide mode, ensure dial code is in the value
                    if (this.dialCodeVisibility[data] === 'separate' || this.dialCodeVisibility[data] === 'hide') {
                        if (!inputTelElement.value.startsWith('+')) {
                            inputTelElement.value = dialCode + inputTelElement.value;
                        }
                    }
                }

                const parentWrp = inputTelElement.closest('.elementor-field-group');
                const telContainer=parentWrp.querySelector('.cfefp-intl-container');

                if (telContainer && inputTelElement.offsetHeight) {
                    telContainer.style.setProperty('--cfefp-intl-tel-button-height', `${inputTelElement.offsetHeight}px`);
                }

                const errorContainer = jQuery(inputTelElement).parent();
                errorContainer.find('span.elementor-message').remove();

                const errorMap = CCFEFCustomData.errorMap;
                let errorMsgHtml = '<span class="elementor-message elementor-message-danger elementor-help-inline elementor-form-help-inline" role="alert">';
                if('' === inputTelElement.value){
                    return;
                };
                if (iti.isValidNumber()) {
                    jQuery(inputTelElement).closest('.cfefp-intl-container').removeClass('elementor-error');
                    this.elements.$submitButton.removeClass('cfkef-prevent-submit');
                    // const $visibleFlexErrors = this.elements.$form.find('.mask-error').filter(function() {
                    //     return jQuery(this).css('display') === 'flex';
                    // });

                    const maskInputs =this.elements.$form.find('.fme-mask-input');

                    if(maskInputs.length === 0){

                        this.elements.$form[0].classList.remove('elementor-form-waiting');
                    }
                } else {
                    this.elements.$submitButton.addClass('cfkef-prevent-submit')

                    const errorType = iti.getValidationError();
                    if (errorType !== undefined && errorMap[errorType]) {
                        // Remove dial code from input field if validation fails
                        if (this.dialCodeVisibility[data] === 'separate' || this.dialCodeVisibility[data] === 'hide') {
                            const currentCountryData = iti.getSelectedCountryData();
                            const dialCode = `+${currentCountryData.dialCode}`;
                            if (inputTelElement.value.startsWith(dialCode)) {
                                inputTelElement.value = inputTelElement.value.substring(dialCode.length);
                            }
                        }
                        errorMsgHtml += errorMap[errorType] + '</span>';
                        jQuery(inputTelElement).closest('.cfefp-intl-container').addClass('elementor-error');
                        jQuery(inputTelElement).after(errorMsgHtml);
                        e.preventDefault();
                        if (trigger === 'submit') {
                            this.elements.$form[0].classList.add('elementor-form-waiting');
                        }
                        if(this.elements.$form.find('.elementor-field-type-recaptcha_v3').length > 0){
                            e.stopImmediatePropagation()
                        }
                    }
                }
            });
        }
    }



    /**
     * Validates the international telephone input fields when the submit button is clicked.
     * It checks if the number is valid and displays appropriate error messages next to the input field.
     */
    intlInputValidation() {

        this.elements.$submitButton.on('click', (e) => {
            this.validateTelInputs(e, 'button');
        });

        this.elements.$form.on('submit', (e) => {
            this.validateTelInputs(e, 'submit');
        });
    }
    
}


jQuery(window).on('elementor/frontend/init', () => {
    const addHandler = ($element) => {
        elementorFrontend.elementsHandler.addHandler(FormCCFEF, {
            $element,
        });
    };

    elementorFrontend.hooks.addAction('frontend/element_ready/form.default', addHandler);
});

