/**
 * @author 1902 Software
 * @copyright Copyright © 2023 1902 Software (https://1902software.com/magento/)
 * @package WriteTextAI_WriteTextAI
 */

define([
    'jquery',
    'ko',
    'uiComponent',
    'WriteTextAI_WriteTextAI/js/model/grid/prompt',
    'WriteTextAI_WriteTextAI/js/utils/edit/textfields',
    'mage/translate',
    'mage/mage',
    'mage/tabs',
    'mage/validation',
    'jquery/ui'
], function (
    $,
    ko,
    Component,
    prompt,
    textfieldsUtils,
    $t
) {
    'use strict';

    /**
     * @var {Component} self
     */
    var self;

    return Component.extend({
        defaults: {
            fields: [],
            tooltipSelector: '.wtai-bulk-full-automation-form .admin__field-tooltip-action',
            selectedFields: [],
            descMax: '',
            descMin: '',
            excMax: '',
            excMin: '',
            disallowedCombinations: [],
            tonesSelected: [],
            stylesSelected: '',
            audienceSelected: [],
            wordsAllowed: false,
            specialInstructions: '',
            attributesSelected: [],
            autoOptimizeKeywords: true,
            autoTextOptimizationSelected: 'flag',
            searchIntent: [],
            searchIntents: [
                'transactional',
                'commercial',
                'navigational',
                'informational'
            ],
            clusterCount: 4,
            isLoading: true,
            isRestoreGlobalLoading: false,
            customTone: '',
            customStyle: '',
            transferToMagento: false,
            isCronAvailable: true,
            triggerActionNPositionLow: 1,
            triggerActionNPositionLowMid: 1,
            triggerActionNPositionMid: 1,
            triggerActionNPositionMidHigh: 1,
            triggerActionNDaysLow: 1,
            triggerActionNDaysLowMid: 1,
            triggerActionNDaysMid: 1,
            triggerActionNDaysMidHigh: 1,
            subTitleLow: 'Ranking 1 - 10',
            subTitleLowMid: 'Ranking 1 - 10',
            subTitleMid: 'Ranking 1 - 10',
            subTitleMidHigh: 'Ranking 1 - 10',
            allProductFieldsSelected: false,
            productFields: [],
            defaultProductFields: [],
            allProductFields: [],
            triggerActions: {},
            triggerActionChanged: {
                low: ko.observable(false),
                low_mid: ko.observable(false),
                mid: ko.observable(false),
                mid_high: ko.observable(false)
            },
            isAcknowledgedHeadsUp: false,
            messageHeadsUp: '',
            positionHeadsUp: 'top',
            targetElementHeadsUp: null,
            isVisibleHeadsUp: false,
            buttonTextHeadsUp: $t('Yes, I understand'),
            headsupVisibility: {
                'transactional': ko.observable(false),
                'commercial': ko.observable(false),
                'navigational': ko.observable(false),
                'informational': ko.observable(false)
            },
            tones: [],
            styles: [],
            audiences: [],
            attributes: [],
            rules: {},
            attrAllowed: false,
            toneStyleAllowed: false,
            wordsAllowed: false,
            currentTemplateSettings: {},
            minTriggerActionNPosition: 2,
            maxTriggerActionNPosition: 100,
            minTriggerActionNDays: 1,
            maxTriggerActionNDays: 365,
            minClusterCount: 1,
            maxClusterCount: 1,
            minOutputWords: 1,
            maxOutputWords: 1,
            automaticTextOptimizationOptions: [],
        },

        isSpinning: false,
        typingTimer: null,
        isReopening: false,
        isRestoring: false,
        isTonesSelectedChanged: false,
        savingPreferences: {},
        getTemplateSettings: true,

        /** @inheritdoc */
        initialize: function () {
            this._super();

            $('.wtai-bulk-full-automation-form-container > *').applyBindings(this);

            self = this;

            self.attributesSelected.subscribe(function (attributesSelected) {
                if (!self.isReopening) {
                    self.savePreferences('attributes_selected', attributesSelected);
                    self.savePreferences('thumbnail', attributesSelected.includes('thumbnail') ? true : false, 'product', null);
                    self.savePreferences('wtai_product_research_data', attributesSelected.includes('wtai_product_research_data') ? true : false, '', null);
                }
            });

            self.selectedFields.subscribe(function (selectedFields) {
                if (!self.isReopening) {
                    self.savePreferences('generate', selectedFields);
                }
            });

            self.tonesSelected.subscribe(
                function (changes) {
                    if (!self.isTonesSelectedChanged) {
                        self.isTonesSelectedChanged = true;

                        _.each(changes, function (change) {
                            if (
                                change.status === 'added' &&
                                change.value === 'custom'
                            ) {
                                self.tonesSelected.remove(self.isNotCustom);
                            }
                            if (
                                change.status === 'added' &&
                                change.value !== 'custom'
                            ) {
                                self.tonesSelected.remove('custom');
                                self.customTone('');
                            }
                        });

                        self.isTonesSelectedChanged = false;
                    }
                    
                    if (!self.isReopening) {
                        self.saveTonesAndStyles();
                    }
                },
                this,
                'arrayChange'
            );

            self.customTone.subscribe(function (customTone) {
                if (customTone) {
                    self.tonesSelected(['custom']);
                }
            });

            self.stylesSelected.subscribe(function (stylesSelected) {
                if (stylesSelected !== 'custom') {
                    self.customStyle('');
                }
                if (!self.isReopening) {
                    self.saveTonesAndStyles();
                }
            });

            self.customStyle.subscribe(function (customStyle) {
                if (customStyle) {
                    self.stylesSelected('custom');
                }
            });

            self.audienceSelected.subscribe(function (audienceSelected) {
                if (!self.isReopening) {
                    self.savePreferences('audiences', audienceSelected);
                }
            });

            self.descMin.subscribe(function (descMin) {
                if (!self.isSpinning) {
                    self.savePreferences('desc_min', descMin);
                }
            });

            self.descMax.subscribe(function (descMax) {
                if (!self.isSpinning) {
                    self.savePreferences('desc_max', descMax);
                }
            });

            self.excMax.subscribe(function (excMax) {
                if (!self.isSpinning) {
                    self.savePreferences('exc_max', excMax);
                }
            });

            self.excMin.subscribe(function (excMin) {
                if (!self.isSpinning) {
                    self.savePreferences('exc_min', excMin);
                }
            });

            self.autoOptimizeKeywords.subscribe(function (autoOptimizeKeywords) {
                self.savePreferences('auto_optimize_keywords', autoOptimizeKeywords);
            });

            /*
            self.autoTextOptimizationSelected.subscribe(function (autoTextOptimizationSelected) {
                self.savePreferences('automatic_text_optimization', autoTextOptimizationSelected);
            });
            */

            self.searchIntent.subscribe(function (searchIntent) {
                if (!self.isReopening) {
                    self.savePreferences('search_intent', searchIntent.join(','), 'product', '');
                }
            });

            /*
            self.clusterCount.subscribe(function (clusterCount) {
                if (!self.isSpinning) {
                    self.savePreferences('cluster_count', clusterCount);
                }
            });
            */

            /*if (!prompt.initialized()) {
                self.transferToMagento(self.isCronAvailable());
            }*/
            
            self.transferToMagento.subscribe(function (isChecked) {
                if (!self.isReopening) {
                    self.savePreferences('transfer_to_magento', isChecked);
                }
            });

            prompt.templateSettings.subscribe(function (templateSettings) {
                self.currentTemplateSettings(templateSettings);
            }, this);

            prompt.fieldsTemplateSettings.subscribe(function (fieldsTemplateSettings) {
                self.fields(fieldsTemplateSettings);
            }, this);

            self.getSettings();
        },

        /** @inheritdoc */
        initObservable: function () {
            this._super().observe([
                'fields',
                'selectedFields',
                'descMax',
                'descMin',
                'excMax',
                'excMin',
                'disallowedCombinations',
                'tonesSelected',
                'stylesSelected',
                'audienceSelected',
                'specialInstructions',
                'attributesSelected',
                'autoOptimizeKeywords',
                'autoTextOptimizationSelected',
                'searchIntent',
                'clusterCount',
                'isLoading',
                'isRestoreGlobalLoading',
                'customTone',
                'customStyle',
                'transferToMagento',
                'triggerActionNPositionLow',
                'triggerActionNPositionLowMid',
                'triggerActionNPositionMid',
                'triggerActionNPositionMidHigh',
                'triggerActionNDaysLow',
                'triggerActionNDaysLowMid',
                'triggerActionNDaysMid',
                'triggerActionNDaysMidHigh',
                'subTitleLow',
                'subTitleLowMid',
                'subTitleMid',
                'subTitleMidHigh',
                'allProductFieldsSelected',
                'defaultProductFields',
                'productFields',
                'isAcknowledgedHeadsUp',
                'messageHeadsUp',
                'positionHeadsUp',
                'targetElementHeadsUp',
                'isVisibleHeadsUp',
                'tones',
                'styles',
                'audiences',
                'attributes',
                'rules',
                'attrAllowed',
                'toneStyleAllowed',
                'wordsAllowed',
                'currentTemplateSettings',
                'minTriggerActionNPosition',
                'maxTriggerActionNPosition',
                'minTriggerActionNDays',
                'maxTriggerActionNDays',
                'minClusterCount',
                'maxClusterCount',
                'minOutputWords',
                'maxOutputWords',
                'triggerActions',
                'automaticTextOptimizationOptions',
                'isCronAvailable',
                'allProductFields',
                'getTemplateSettings'
            ]);
            
            this.allFieldsSelected = ko.computed({
                read: function () {
                    const selectedFields = this.selectedFields() || [];
                    const allFields = [...this.fields().map(field => field.value), 'alt_text'] || [];
                    return selectedFields.length === allFields.length;
                }.bind(this),
                write: function (value) {
                    const allFields = [...this.fields().map(field => field.value), 'alt_text'] || [];
                    const selectedFields = value ? allFields : [];
                    this.selectedFields(selectedFields);
                }.bind(this)
            }, this);
            
            this.allTonesSelected = ko.computed({
                read: function () {
                    const tones = this.tonesSelected() || [];
                    const allTones = [...this.tones().map(tone => tone.id)] || [];
            
                    /* If style is 'Internet-speak', remove 'Formal' from the comparison */
                    let tonesToCompare = allTones;
                    if (this.stylesSelected() === 'Internet-speak') {
                        tonesToCompare = allTones.filter(tone => tone !== 'Formal');
                    }
            
                    return tones.length === tonesToCompare.length &&
                           tonesToCompare.every(tone => tones.includes(tone));
                }.bind(this),
            
                write: function (value) {
                    let tones = value ? [...this.tones().map(tone => tone.id)] : [];
            
                    if (value && this.stylesSelected() === 'Internet-speak') {
                        tones = tones.filter(tone => tone !== 'Formal');
                    }
            
                    this.tonesSelected(tones);
                }.bind(this)
            }, this);

            this.allAudienceSelected = ko.computed({
                read: function () {
                    const audience = this.audienceSelected() || [];
                    const allAudience = [...this.audiences().map(audience => audience.id)] || [];
                    return audience.length === allAudience.length;
                }.bind(this),
                write: function (value) {
                    const allAudience = [...this.audiences().map(audience => audience.id)]|| [];
                    const audience = value ? allAudience : [];
                    this.audienceSelected(audience);
                }.bind(this)
            }, this);
            
            this.allAttributesSelected = ko.computed({
                read: function () {
                    const attributes = this.attributesSelected() || [];
                    const allAttributes = [...this.attributes().map(attr => attr.value)] || [];
                    return attributes.length === allAttributes.length;
                }.bind(this),
                write: function (value) {
                    const allAttributes = [...this.attributes().map(attr => attr.value)]|| [];
                    const attributes = value ? allAttributes : [];
                    this.attributesSelected(attributes);
                }.bind(this)
            }, this);

            this.getOtherProductDetailsLength = ko.computed(function () {
                return this.specialInstructions().length + '/' + this.rules().maxOtherDetailsLength + ' ' +  $t('Char');
            }, this);

            this.searchIntentCommadSeparated = ko.computed(function () {
                return this.searchIntent().join(', ');
            }, this);

            this.transferActionClass = ko.computed(function () {
                let className = 'wtai-transfer-action';
                if (this.transferToMagento()) {
                    className += ' wtai-auto-transfer-selected';
                }
                /*if (!this.isCronAvailable()) {
                    className += ' wtai-cron-not-available';
                }*/
                return className;
            }, this);
            
            this.isActionNoteVisible = ko.computed(function () {
                return this.transferToMagento();
            }, this);

            this.allProductFieldsSelected = ko.computed({
                read: function () {
                    const productFields = this.productFields() || [];
                    const allProductFields = [...this.allProductFields()] || [];
                    return productFields.length === allProductFields.length;
                }.bind(this),
                write: function (value) {
                    const allProductFields = [...this.allProductFields()]|| [];
                    const fields = value ? allProductFields : [];
                    this.productFields(fields);
                }.bind(this)
            }, this);
            

            this.isOffsetRight = ko.computed(function () {
                return false;
            }, this);

            return this;
        },

        /**
         * Get settings
         */
        getSettings: function () {
            self.showLoader();
            var getTemplateSettings = false;
            /*if (Object.keys(prompt.templateSettings()).length > 0) {
                getTemplateSettings = false;
            }*/
            $.ajax({
                url: self.getSettingsUrl,
                type: 'GET',
                data: {
                    getTemplateSettings: getTemplateSettings
                },
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    } else {
                        console.log(response);

                        self.isReopening = true;
                        self.tones(response.data.tones);
                        self.styles(response.data.styles);
                        self.audiences(response.data.audiences);
                        self.attributes(response.data.attributes);
                        self.attributesSelected(response.data.attributes_selected);
                        self.customTone(response.data.custom_tone);
                        self.customStyle(response.data.custom_style);
                        self.tonesSelected(response.data.tones_selected);
                        self.stylesSelected(response.data.styles_selected);
                        self.audienceSelected(response.data.audience_selected);
                        self.descMin(response.data.desc_min);
                        self.descMax(response.data.desc_max);
                        self.excMin(response.data.exc_min);
                        self.excMax(response.data.exc_max);
                        self.specialInstructions(response.data.special_instructions);
                        self.selectedFields(response.data.selected_fields);
                        self.rules(response.data.rules);
                        self.disallowedCombinations(response.data.disallowedCombinations);
                        self.attrAllowed(response.data.attrAllowed);
                        self.toneStyleAllowed(response.data.toneStyleAllowed);
                        self.wordsAllowed(response.data.wordsAllowed);
                        self.autoTextOptimizationSelected(response.data.autoTextOptimizationSelected);
                        self.searchIntent(response.data.searchIntent);
                        self.clusterCount(response.data.clusterCount);
                        self.maxClusterCount(response.data.maxClusterCount);
                        self.minClusterCount(response.data.minClusterCount);
                        self.isCronAvailable(response.data.isCronAvailable);
                        self.triggerActions(response.data.triggerActions);
                        self.triggerActionNPositionLow(response.data.triggerActionNPositionLow);
                        self.triggerActionNDaysLow(response.data.triggerActionNDaysLow);
                        self.triggerActionNPositionLowMid(response.data.triggerActionNPositionLowMid);
                        self.triggerActionNDaysLowMid(response.data.triggerActionNDaysLowMid);
                        self.triggerActionNPositionMid(response.data.triggerActionNPositionMid);
                        self.triggerActionNDaysMid(response.data.triggerActionNDaysMid);
                        self.triggerActionNPositionMidHigh(response.data.triggerActionNPositionMidHigh);
                        self.triggerActionNDaysMidHigh(response.data.triggerActionNDaysMidHigh);
                        self.minTriggerActionNPosition(response.data.minTriggerActionNPosition);
                        self.maxTriggerActionNPosition(response.data.maxTriggerActionNPosition);
                        self.minTriggerActionNDays(response.data.minTriggerActionNDays);
                        self.maxTriggerActionNDays(response.data.maxTriggerActionNDays);
                        self.productFields(response.data.productFields);
                        self.allProductFields(response.data.allProductFields);
                        self.automaticTextOptimizationOptions(response.data.automaticTextOptimizationOptions);
                        if (response.data.currentTemplateSettings) {
                            prompt.templateSettings(response.data.currentTemplateSettings);
                            prompt.fieldsTemplateSettings(response.data.fields);
                        } else {
                            self.currentTemplateSettings(prompt.templateSettings());
                            self.fields(prompt.fieldsTemplateSettings());
                        }

                        self.isReopening = false;

                        self.initBulkTabs();
                        self.initTooltip();
                        self.initValidations();
                        self.initTriggerUpdate();
                        self.initSpinner();
                        self.initPreferences();
                        self.afterOpenUpdates();
                        self.initTriggerActionsLabels();
                        self.bindHeadsUpClickOutside();
                    }
                }
            }).always(function () {
                self.removeLoader();
            });
        },

        /**
         * Initialize preferences
         *
         * Set model values on page load.
         * Model values updates on change.
         * Retain selected fields when reopening the modal.
         */
        initPreferences: function () {
            if (!prompt.keywordAnalysisPromptInitialized()) {
                prompt.keywordAnalysisPromptInitialized(true);
            } else {
                /* Reset the tooltip acknowledgement status when reopening the modal */
                this.isAcknowledgedHeadsUp(false);
                this.headsupVisibility.transactional(false);
                this.headsupVisibility.commercial(false);
                this.headsupVisibility.navigational(false);
                this.headsupVisibility.informational(false);
            }
            
            if (!prompt.initialized()) {
                prompt.initialized(true);
            }
        },

        /**
         * Initialize update trigger
         */
        initTriggerUpdate: function () {
            $('#wtaiFullAutomationPrompt').trigger('contentUpdated');
        },

        /**
         * Get trigger action name
         */
        getTriggerActionName: function (triggerAction) {
            switch (triggerAction) {
                case 'low':
                    return 'LOW - LOW MID';
                case 'low_mid':
                    return 'LOW MID - MID';
                case 'mid':
                    return 'MID - MID HIGH';
                case 'mid_high':
                    return 'MID HIGH - HIGH';
            }
        },

        /**
         * Format trigger action name
         */
        formatTriggerActionName: function (triggerAction) {
            switch (triggerAction) {
                case 'low':
                    return this.subTitleLow();
                case 'low_mid':
                    return this.subTitleLowMid();
                case 'mid':
                    return this.subTitleMid();
                case 'mid_high':
                    return this.subTitleMidHigh();
            }
        },
        
        /**
         * Show loader
         */
        showLoader: function () {
            self.isLoading(true);
        },

        /**
         * Show restore global loader
         */
        showRestoreGlobalLoader: function () {
            self.isRestoreGlobalLoading(true);
        },

        /**
         * Remove restore global loader
         */
        removeRestoreGlobalLoader: function () {
            setTimeout(function () {
                self.isRestoreGlobalLoading(false);
            }, 100);
        },

        /**
         * Remove loader
         */
        removeLoader: function () {
            setTimeout(function () {
                self.isLoading(false);
            }, 100);
        },

        /**
         * Remove loader
         */
        afterOpenUpdates: function () {
            setTimeout(function () {
                if (!self.transferToMagento()) {
                    self.transferToMagento(true);
                }
            }, 100);
        },

        /**
         * Restore user preferences
         */
        restore: function () {
            self.abortPendingRequests();
            self.showRestoreGlobalLoader();
            
            $.ajax({
                url: self.restoreUrl,
                type: 'GET',
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    } else {
                        console.log(response);
                        self.isRestoring = true;
                        self.descMin(response.data.desc_min);
                        self.descMax(response.data.desc_max);
                        self.excMin(response.data.exc_min);
                        self.excMax(response.data.exc_max);
                        self.selectedFields(response.data.fields);
                        self.tonesSelected(response.data.tones);
                        self.stylesSelected(response.data.styles);
                        self.customTone(response.data.custom_tone);
                        self.customStyle(response.data.custom_style);
                        self.audienceSelected(response.data.audience);
                        self.specialInstructions(response.data.special_instructions);
                        self.attributesSelected([]);
                        self.attributesSelected([...response.data.attributes]);
                        self.autoOptimizeKeywords(response.data.auto_optimize_keywords);
                        self.autoTextOptimizationSelected(response.data.automatic_text_optimization);
                        self.searchIntent([...response.data.search_intent]);
                        self.clusterCount(response.data.cluster_count);
                        self.transferToMagento(self.isCronAvailable);
                        self.triggerActionNPositionLow(self.triggerActions().low.trigger_action_n_position);
                        self.triggerActionNPositionLowMid(self.triggerActions().low_mid.trigger_action_n_position);
                        self.triggerActionNPositionMid(self.triggerActions().mid.trigger_action_n_position);
                        self.triggerActionNPositionMidHigh(self.triggerActions().mid_high.trigger_action_n_position);
                        self.triggerActionNDaysLow(self.triggerActions().low.trigger_action_n_days);
                        self.triggerActionNDaysLowMid(self.triggerActions().low_mid.trigger_action_n_days);
                        self.triggerActionNDaysMid(self.triggerActions().mid.trigger_action_n_days);
                        self.triggerActionNDaysMidHigh(self.triggerActions().mid_high.trigger_action_n_days);
                        self.productFields([...response.data.product_fields]);
                        self.minClusterCount(response.data.min_cluster_count);
                        self.maxClusterCount(response.data.max_cluster_count);
                        self.minOutputWords(response.data.min_output_words);
                        self.maxOutputWords(response.data.max_output_words);

                        /**
                         * Select default trigger action for each position and restore nPosition/nDays values
                         */
                        ['low', 'low_mid', 'mid', 'mid_high'].forEach(function (position) {
                            var defaultAction = self.triggerActions()[position].trigger_action;
                            var radioSelector = 'input[name="trigger_action_' + position + '"][value="' + defaultAction + '"]';
                            $(radioSelector).prop('checked', true).trigger('change');

                            /**
                             * Restore nPosition value
                             */
                            var nPositionInput = $('.wtai-trigger-action-n-position-' + position);
                            if (nPositionInput.length) {
                                nPositionInput.val(self.triggerActions()[position].trigger_action_n_position).trigger('change');
                            }

                            /**
                             * Restore nDays value
                             */
                            var nDaysInput = $('.wtai-trigger-action-after-n-days-' + position);
                            if (nDaysInput.length) {
                                nDaysInput.val(self.triggerActions()[position].trigger_action_n_days).trigger('change');
                            }
                        });

                        self.initTriggerActionsLabels();
                        self.isRestoring = false;
                    }
                }
            }).always(function () {
                self.removeRestoreGlobalLoader();
            });
        },

        /**
         * Handle custom tone and style typing
         */
        handleCustomToneStyle: function () {
            clearTimeout(self.typingTimer);

            self.typingTimer = setTimeout(function () {
                self.saveTonesAndStyles();
            }, 2000);
        },

        /**
         * Save user preferences for tones and styles
         */
        saveTonesAndStyles: function () {
            var url = self.saveUrl,
                tones = self.tonesSelected(),
                customTone = self.customTone(),
                styles = self.stylesSelected(),
                customStyle = self.customStyle();
            
            if (tones.length <= 0) {
                tones = '';
            }

            if (self.isRestoring || self.isReopening) {
                return;
            }

            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    tones: tones,
                    style: styles,
                    custom_tone: customTone,
                    custom_style: customStyle,
                    entity_type: '',
                    scope: ''
                },
                dataType: 'json',
                showWriteTextAILoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    }
                }
            });
        },

        /**
         * Save user preferences
         *
         * @param {String} field
         * @param {String} selected
         * @param {String} entityType
         * @param {String} scope
         *
         * @return {void}
         */
        savePreferences: function (field, selected, entityType = 'product', scope = 'grid') {
            var value = selected;
            
            if (value === null || value.length <= 0) {
                value = '';
            }

            if (self.isRestoring || self.isReopening) {
                return;
            }

            /* Create a unique key for this request */
            var requestKey = field + '_' + entityType + '_' + scope;

            /* Abort previous request with the same key */
            if (self.savingPreferences[requestKey] !== null && self.savingPreferences[requestKey] !== undefined) {
                self.savingPreferences[requestKey].abort();
            }

            self.savingPreferences[requestKey] = $.ajax({
                url: self.saveUrl,
                type: 'POST',
                data: {
                    [field]: value,
                    entity_type: entityType,
                    scope: scope
                },
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    }
                    /* Clean up the reference after successful completion */
                    delete self.savingPreferences[requestKey];
                },
                error: function (xhr, status, error) {
                    if (status !== 'abort') {
                        console.log(error);
                    }
                    /* Clean up the reference after error (except abort) */
                    delete self.savingPreferences[requestKey];
                }
            });
        },

        /**
         * Validate number.
         *
         * @param {Object} data
         * @param {Object} event
         *
         * @return {Boolean}
         */
        ensureNumerical: function (data, event) {
            return textfieldsUtils.ensureNumerical(event.key);
        },

        /**
         * Is intent selected
         */
        isIntentSelected: function (intent) {
            return this.searchIntent().indexOf(intent) !== -1;
        },

        /**
         * Show educational tooltip for non-transactional intent selection
         *
         * @param {String} intent
         * @return {void}
         */
        showEducationalTooltipForIntent: function (intent) {
            if (self.isAcknowledgedHeadsUp()) {
                return;
            }
            var searchIntent = self.searchIntent();
            if (searchIntent.length > 0 && searchIntent.indexOf(intent) !== -1) {
                self.selectIntent(intent);
                return;
            }
            var message = $t('Heads up! Product pages are typically intended for transactional search intent—users looking to make a purchase or take action. Using other intent types may be less effective unless your content is intentionally designed to inform, guide, or compare. Make sure it fits your overall SEO and content strategy.');

            /** Only show tooltip for non-transactional intents */
            if (intent === 'transactional') {
                return;
            }
            

            /** Find the target element for the selected intent */
            const targetSelector = '.wtai-search-intent-option:contains("' + intent + '")';
            const $targetElement = $(targetSelector);

            if ($targetElement.length > 0) {
                this.showHeadsUp(
                    message,
                    'top',
                    intent,
                    $targetElement
                );
            }
        },

        /**
         * Get tooltip text search intent
         *
         * @param {String} intent
         * @return {String}
         */
        getTooltipTextSearchIntent: function (intent) {
            
            if (this.searchIntent().length === 1 && this.searchIntent().indexOf(intent) !== -1) {
                return $t('You need at least one search intent');
            }
            switch (intent) {
                case 'transactional':
                    return $t('Users aim to complete a transaction, such as making a purchase or signing up for a service.');
                case 'commercial':
                    return $t('Users are researching products or services with the intention of making a purchase decision soon.');
                case 'informational':
                    return $t('Users seek information on a specific topic, intending to learn something.');
                case 'navigational':
                    return $t('Users have a specific website or web page in mind and are using search engines to navigate there directly.');
                default:
                    return '';
            }
        },

        /**
         * Select search intent
         *
         * @param {String} intent
         * @return {void}
         */
        selectIntent: function (intent) {
            var searchIntent = self.searchIntent();
            if (searchIntent.length <= 1 &&
                searchIntent.indexOf(intent) !== -1
            ) {
                return;
            }

            if (searchIntent.indexOf(intent) === -1) {
                searchIntent.push(intent);
            } else {
                searchIntent = _.without(searchIntent, intent);
            }
            self.searchIntent(searchIntent);
        },

        /**
         * Handle input special instructions.
         */
        handleInputSpecialInstructions: function () {
            clearTimeout(self.typingTimer);

            self.typingTimer = setTimeout(function () {
                self.savePreferences('special_instructions', self.specialInstructions());
            }, 2000);

            return true;
        },

        /**
         * Initialize spinner
         */
        initSpinner: function () {
            setTimeout(
                function () {
                    $('.wtai-bulk-full-automation-popup .wtai-cluster-count').spinner({
                        numberFormat: 'n',
                        min: this.minClusterCount(),
                        max: this.maxClusterCount(),
                        spin: function (event, ui) {
                            self.isSpinning = true;
                            self.clusterCount(ui.value);
                            self.isSpinning = false;
                        },
                        change: function (event) {
                            self.clusterCount(event.target.value);
                        }
                    });
                    $('.wtai-bulk-full-automation-popup .wtai-input-number').spinner({
                        numberFormat: 'n',
                        min: this.minOutputWords(),
                        max: this.maxOutputWords(),
                        disabled: !self.wordsAllowed,
                        spin: function (event, ui) {
                            var value = ui.value,
                                name = $(event.target).attr('name');
                            
                            self.isSpinning = true;
                            switch (name) {
                                case 'description_min':
                                    self.descMin(value);
                                    break;
                                case 'description_max':
                                    self.descMax(value);
                                    break;
                                case 'excerpt_min':
                                    self.excMin(value);
                                    break;
                                case 'excerpt_max':
                                    self.excMax(value);
                                    break;
                            }
                            self.isSpinning = false;
                        },
                        change: function (event) {
                            var value = event.target.value,
                                name = $(event.target).attr('name');
                            
                            switch (name) {
                                case 'description_min':
                                    self.descMin(value);
                                    break;
                                case 'description_max':
                                    self.descMax(value);
                                    break;
                                case 'excerpt_min':
                                    self.excMin(value);
                                    break;
                                case 'excerpt_max':
                                    self.excMax(value);
                                    break;
                            }
                        }
                    });
                    
                    /** Define spinner configurations */
                    const positionSpinners = [
                        { selector: 'low', action: 'when_page_is_ranking' },
                        { selector: 'low_mid', action: 'when_page_is_ranking' },
                        { selector: 'mid', action: 'when_page_is_ranking' },
                        { selector: 'mid_high', action: 'when_page_is_ranking' }
                    ];

                    const daysSpinners = [
                        { selector: 'low', action: 'after_n_days' },
                        { selector: 'low_mid', action: 'after_n_days' },
                        { selector: 'mid', action: 'after_n_days' },
                        { selector: 'mid_high', action: 'after_n_days' }
                    ];

                    /** Helper function to initialize spinners */
                    const initSpinner = (type, config) => {
                        const isPosition = type === 'position';
                        const prefix = isPosition ? 'n-position' : 'after-n-days';
                        const min = isPosition ? this.minTriggerActionNPosition() : this.minTriggerActionNDays();
                        const max = isPosition ? this.maxTriggerActionNPosition() : this.maxTriggerActionNDays();
                        const selectorCased = config.selector.split('_').map(
                            word =>
                            word.charAt(0).toUpperCase() + word.slice(1)
                        ).join('');
                        const valueProperty = isPosition ?
                            `triggerActionNPosition${selectorCased}` :
                            `triggerActionNDays${selectorCased}`;

                        $(`.wtai-trigger-action-${prefix}-${config.selector}`).spinner({
                            numberFormat: 'n',
                            min: min,
                            max: max,
                            spin: function (event, ui) {
                                self.isSpinning = true;
                                self[valueProperty](ui.value);
                                self.isSpinning = false;
                            },
                            change: function (event) {
                                self[valueProperty](event.target.value);
                                self.selectTriggerAction(config.selector, config.action);
                                $(`input[name="trigger_action_${config.selector}"][value="${config.action}"]`).prop('checked', true).trigger('change');
                            }
                        });
                    };

                    /** Initialize all spinners */
                    positionSpinners.forEach(config => initSpinner('position', config));
                    daysSpinners.forEach(config => initSpinner('days', config));
                }.bind(this),
                100
            );
        },

        /**
         * Initialize tooltip
         */
        initTooltip: function () {
            $(self.tooltipSelector).dropdown({
                parent: '.admin__field-tooltip',
                autoclose: true
            });
        },

        /**
         * Initialize validations
         */
        initValidations: function () {
            $('#wtaiBulkFullAutomationForm').mage('validation', {
                rules: {
                    'fields[]': {
                        required: true
                    },
                    'tones[]': {
                        required: {
                            param: true
                        }
                    },
                    styles: {
                        required: {
                            param: true
                        }
                    },
                    'custom_tone': {
                        required: {
                            param: true,
                            depends: function () {
                                return self.tonesSelected().indexOf('custom') !== -1;
                            }
                        },
                        'validate-no-empty': {
                            depends: function () {
                                return self.tonesSelected().indexOf('custom') !== -1;
                            }
                        }
                    },
                    'custom_style': {
                        required: {
                            param: true,
                            depends: function () {
                                return self.stylesSelected() === 'custom';
                            }
                        },
                        'validate-no-empty': {
                            depends: function () {
                                return self.stylesSelected() === 'custom';
                            }
                        }
                    },
                    'product_texts[]': {
                        required: true
                    }
                },
                messages: {
                    'fields[]': {
                        required: $t('Please select at least one text type.')
                    },
                    'tones[]': {
                        required: $t('Please select at least one tone.')
                    },
                    styles: {
                        required: $t('Please select at least one style.')
                    },
                    'custom_tone': {
                        required: $t('Write your specific tone...'),
                        'validate-no-empty': $t('Write your specific tone...')
                    },
                    'custom_style': {
                        required: $t('Write your specific style...'),
                        'validate-no-empty': $t('Write your specific style...')
                    },
                    'product_texts[]': {
                        required: $t('Please select at least one field to rewrite.')
                    }
                },
                errorPlacement: function (error, element) {
                    $('.wtai-tabs-error-message').html(error);
                },
                invalidHandler: function (form, validator) {
                    if (!validator.numberOfInvalids()) {
                        return;
                    }
                    var lastErrorElement = $(validator.errorList[validator.errorList.length - 1].element);
                    var tabPane = lastErrorElement.closest('.item.content');
                    if (tabPane.length) {
                        if (tabPane.css('display') === 'none') {
                            var tabTrigger = tabPane.prev('.item.title').find('a.switch');
                            if (tabTrigger.length) {
                                tabTrigger.trigger('click');
                            }
                        }
                    }
                    setTimeout(function () {
                        validator.focusInvalid();
                    }, 50);
                }
            });
        },

        /**
         * Initialize trigger actions labels
         */
        initTriggerActionsLabels: function () {
            this.triggerActionChanged.low(false);
            this.triggerActionChanged.low_mid(false);
            this.triggerActionChanged.mid(false);
            this.triggerActionChanged.mid_high(false);
            this.selectTriggerAction('low', this.triggerActions().low.trigger_action);
            this.selectTriggerAction('low_mid', this.triggerActions().low_mid.trigger_action);
            this.selectTriggerAction('mid', this.triggerActions().mid.trigger_action);
            this.selectTriggerAction('mid_high', this.triggerActions().mid_high.trigger_action);
        },

        /**
         * Initialize bulk tabs
         */
        initBulkTabs: function () {
            setTimeout(function () {
                $('.wtai-tabs').tabs({
                    active: 0
                });
            }, 100);
        },

        /**
         * Check if combination is not allowed
         *
         * @param {String} id
         * @param {String} type
         *
         * @return {Boolean}
         */
        isCombinationDisallowed: function (id, type) {
            var result,
                isStyleChecked = false,
                isToneChecked = false,
                isAudienceChecked = false,
                combinationHasAudience = false;

            self = this;

            try {
                /* Check if combination is available */
                result = self
                    .disallowedCombinations()
                    .find(function (combination) {
                        return combination.combination.some(function (obj) {
                            return obj.type === type && obj.id === id;
                        });
                    });

                if (!(self.disallowedCombinations() && result)) {
                    return false;
                }

                switch (type) {
                    case 'Tone':
                        isStyleChecked = result.combination.some(
                            function (obj) {
                                return (
                                    obj.type === 'Style' &&
                                    self.stylesSelected() === obj.id
                                );
                            }
                        );
                        combinationHasAudience =
                            result.combination.some(function (obj) {
                                return obj.type === 'Audience';
                            });

                        if (combinationHasAudience) {
                            isAudienceChecked =
                                self
                                    .audienceSelected()
                                    .indexOf(combinationHasAudience.id) !==
                                -1;

                            return isStyleChecked && isAudienceChecked;
                        }
                        return isStyleChecked;

                    case 'Style':
                        isToneChecked = result.combination.some(
                            function (obj) {
                                return (
                                    obj.type === 'Tone' &&
                                    self.tonesSelected().indexOf(obj.id) !==
                                        -1
                                );
                            }
                        );
                        combinationHasAudience =
                            result.combination.some(function (obj) {
                                return obj.type === 'Audience';
                            });

                        if (combinationHasAudience) {
                            isAudienceChecked =
                                self
                                    .audienceSelected()
                                    .indexOf(combinationHasAudience.id) !==
                                -1;

                            return isToneChecked && isAudienceChecked;
                        }
                        return isToneChecked;

                    case 'Audience':
                        isToneChecked = result.combination.some(
                            function (obj) {
                                return (
                                    obj.type === 'Tone' &&
                                    self.tonesSelected().indexOf(obj.id) !==
                                        -1
                                );
                            }
                        );
                        isStyleChecked = result.combination.some(
                            function (obj) {
                                return (
                                    obj.type === 'Style' &&
                                    self.stylesSelected() === obj.id
                                );
                            }
                        );

                        return isStyleChecked && isToneChecked;

                    default:
                        return false;
                }
            } catch (e) {
                return false;
            }
        },

        /**
         * Get tooltip text based on disallowed combination
         *
         * @param {String} id
         * @param {String} type
         *
         * @return {String}
         */
        getToolTipCombinationDisallowed: function (id, type) {
            if (this.isCombinationDisallowed(id, type)) {
                return this.getTooltipCombinationDisallowedText(id, type);
            }
            return '';
        },

        /**
         * Get tooltip text based on disallowed combination
         *
         * @param {String} id
         * @param {String} type
         *
         * @return {String}
         */
        getTooltipCombinationDisallowedText: function (id, type) {
            var result,
                isStyleChecked = false,
                isToneChecked = false,
                textBase = '';

            self = this;

            try {
                /* Check if combination is available */
                result = self
                    .disallowedCombinations()
                    .find(function (combination) {
                        return combination.combination.some(function (obj) {
                            return obj.type === type && obj.id === id;
                        });
                    });

                if (!result) {
                    return '';
                }

                switch (type) {
                    case 'Tone':
                        isStyleChecked = result.combination.some(
                            function (obj) {
                                if (obj.type === 'Style' && self.stylesSelected() === obj.id) {
                                    textBase = self.processToolTip(obj.id, 'Style');
                                    return true;
                                }
                                return false;
                            }
                        );
                        return textBase;

                    case 'Style':
                        isToneChecked = result.combination.some(
                            function (obj) {
                                if ( obj.type === 'Tone' &&
                                    self.tonesSelected().indexOf(obj.id) !== -1) {
                                    textBase = self.processToolTip(obj.id, 'Tone');
                                    return true;
                                }
                                return false;
                            }
                        );
                        return textBase;

                    default:
                        return '';
                }
            } catch (e) {
                return '';
            }
        },

        /**
         * Process tooltip content
         *
         * @param {String} selector
         * @param {String} stringValue
         *
         * @return {String}
         */
        processToolTip: function (stringValue, type) {
            var textBase = '';
            switch (type) {
                case 'Tone':
                    textBase = $t("Unavailable when the '%1' tone is selected.");
                    break;
                case 'Style':
                    textBase = $t("Unavailable when the '%1' style is selected.");
                    break;
                default:
                    textBase = $t("Unavailable when the '%1' audience is selected.");
                    break;
            }
            return $t(textBase).replace('%1', stringValue);
        },

        /**
         * Validate min and max fields.
         *
         * @param {Object} data
         * @param {Object} event
         *
         * @return {void}
         */
        validateMinMax: function (data, event) {
            var target = event.target,
                value = Number(target.value),
                min = Number(target.min),
                max = Number(target.max),
                name = target.name;

            const mapping = {
                description_min: self.descMin,
                description_max: self.descMax,
                excerpt_min: self.excMin,
                excerpt_max: self.excMax,
                cluster_count: self.clusterCount,
                trigger_action_n_position_low: self.triggerActionNPositionLow,
                trigger_action_n_position_low_mid: self.triggerActionNPositionLowMid,
                trigger_action_n_position_mid: self.triggerActionNPositionMid,
                trigger_action_n_position_mid_high: self.triggerActionNPositionMidHigh,
                trigger_action_n_days_low: self.triggerActionNDaysLow,
                trigger_action_n_days_low_mid: self.triggerActionNDaysLowMid,
                trigger_action_n_days_mid: self.triggerActionNDaysMid,
                trigger_action_n_days_mid_high: self.triggerActionNDaysMidHigh,
            };

            if (value < min || value > max) {
                const func = mapping[name],
                    val = value < min ? min : max;

                $(target).val(val);
                func(val);
            }
        },

        /**
         * Get custom tone length.
         *
         * @return {String}
         */
        getCustomToneLength: function () {
            var length = this.customTone() ? this.customTone().length : 0;
            return length + '/' + this.rules().maxCustomToneLength + ' ' + $.mage.__('Char');
        },

        /**
         * Get custom style length.
         *
         * @return {String}
         */
        getCustomStyleLength: function () {
            var length = this.customStyle() ? this.customStyle().length : 0;
            return length + '/' + this.rules().maxCustomStyleLength + ' ' + $.mage.__('Char');
        },

        /**
         * Select trigger action
         *
         * @param {String} triggerAction
         * @param {String} value
         *
         * @return {void}
         */
        selectTriggerAction: function (triggerAction, value) {
            const actionMap = {
                low: {
                    position: this.triggerActionNPositionLow(),
                    days: this.triggerActionNDaysLow(),
                    subtitle: this.subTitleLow
                },
                low_mid: {
                    position: this.triggerActionNPositionLowMid(),
                    days: this.triggerActionNDaysLowMid(),
                    subtitle: this.subTitleLowMid
                },
                mid: {
                    position: this.triggerActionNPositionMid(),
                    days: this.triggerActionNDaysMid(),
                    subtitle: this.subTitleMid
                },
                mid_high: {
                    position: this.triggerActionNPositionMidHigh(),
                    days: this.triggerActionNDaysMidHigh(),
                    subtitle: this.subTitleMidHigh
                }
            };

            const action = actionMap[triggerAction];
            if (!action) {
                return;
            }

            const { position, days, subtitle } = action;

            /* Get the initial value from triggerActions */
            const initialValue = this.triggerActions()[triggerAction].trigger_action;
            const initialPosition = this.triggerActions()[triggerAction].trigger_action_n_position || 2;
            const initialDays = this.triggerActions()[triggerAction].trigger_action_n_days || 1;
            
            /* Update the changed state */
            if (value !== initialValue ||
                (value === 'when_page_is_ranking' && parseInt(position) !== parseInt(initialPosition)) ||
                (value === 'after_n_days' && parseInt(days) !== parseInt(initialDays))) {
                this.triggerActionChanged[triggerAction](true);
            } else {
                this.triggerActionChanged[triggerAction](false);
            }

            if (value === 'when_page_is_ranking') {
                subtitle($t('Ranking 1 - %1').replace('%1', position));
            } else if (value === 'after_n_days') {
                subtitle($t('After %1 day/s').replace('%1', days));
            } else {
                subtitle($t('None'));
            }
        },

        /**
         * Check if not custom
         *
         * @param {string} value
         * @returns {boolean}
         */
        isNotCustom: function (value) {
            return value !== 'custom';
        },

        /**
         * Show the tooltip
         *
         * @param {string} message - The message to display
         * @param {string} position - Position of the tooltip
         * @param {jQuery|string} targetElement - Target element or selector
         * @returns {void}
         */
        showHeadsUp: function (message, position = 'top', intent = 'transactional', targetElement = null) {
            this.headsupVisibility.transactional(false);
            this.headsupVisibility.commercial(false);
            this.headsupVisibility.navigational(false);
            this.headsupVisibility.informational(false);

            if (this.isAcknowledgedHeadsUp()) {
                return;
            }

            this.messageHeadsUp(message);
            this.positionHeadsUp(position);
            this.targetElementHeadsUp = targetElement;
            this.headsupVisibility[intent](true);
        },

        /**
         * Acknowledge the heads up
         *
         * @param {string} intent - The intent to select
         * @returns {void}
         */
        acknowledgeHeadsUp: function (intent) {
            self.headsupVisibility.transactional(false);
            self.headsupVisibility.commercial(false);
            self.headsupVisibility.navigational(false);
            self.headsupVisibility.informational(false);
            self.selectIntent(intent);
        },

        /**
         * Bind click-outside handler for heads-up popup.
         */
        bindHeadsUpClickOutside: function () {
            $(document).on('click', function (event) {
                /* Don't close if clicking on the intent button itself */
                if ($(event.target).closest('.wtai-search-intent-option').length) {
                    return;
                }
                
                /* Check if any heads-up popup is visible */
                var isAnyHeadsUpVisible = self.headsupVisibility.transactional() ||
                                        self.headsupVisibility.commercial() ||
                                        self.headsupVisibility.navigational() ||
                                        self.headsupVisibility.informational();
                
                if (isAnyHeadsUpVisible && !$(event.target).closest('.wtai-educational-tooltip').length) {
                    /* Close all heads-up popups */
                    self.headsupVisibility.transactional(false);
                    self.headsupVisibility.commercial(false);
                    self.headsupVisibility.navigational(false);
                    self.headsupVisibility.informational(false);
                }
            });
        },

        /**
         * Save product research data selected.
         *
         * @param {Object} data
         * @param {Event} event
         *
         * @returns {void}
         */
        saveProductResearchDataSelected: function (data, event) {
            if (self.isRestoring || self.isReopening) {
                return;
            }
            $.ajax({
                url: self.saveUrl,
                type: 'POST',
                data: {
                    wtai_product_research_data: event.target.checked,
                    entity_type: '',
                },
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    }
                }
            });
        },

        /**
         * Abort all pending AJAX requests
         */
        abortPendingRequests: function () {
            for (var key in self.savingPreferences) {
                if (self.savingPreferences.hasOwnProperty(key) && self.savingPreferences[key] !== null) {
                    self.savingPreferences[key].abort();
                    delete self.savingPreferences[key];
                }
            }
            self.savingPreferences = {};
        }
    });
});
