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

define([
    'jquery',
    'underscore',
    'ko',
    'uiComponent',
    'WriteTextAI_WriteTextAI/js/model/edit/product',
    'WriteTextAI_WriteTextAI/js/categories/model/edit',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/category',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/textfields',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/invalid-image',
    'WriteTextAI_WriteTextAI/js/model/edit/additional-prompt',
    'WriteTextAI_WriteTextAI/js/utils/edit/toolbar',
    'WriteTextAI_WriteTextAI/js/utils/edit/textfields',
    'WriteTextAI_WriteTextAI/js/model/edit/settings',
    'WriteTextAI_WriteTextAI/js/model/edit/audience',
    'WriteTextAI_WriteTextAI/js/model/total-credits',
    'WriteTextAI_WriteTextAI/js/model/edit/custom-tone-style',
    'WriteTextAI_WriteTextAI/js/model/edit/error-messages',
    'WriteTextAI_WriteTextAI/js/model/edit/generate/settings',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/representative-products',
    'WriteTextAI_WriteTextAI/js/model/edit/generate/keyword-analysis',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keywords',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keyword-analysis',
    'WriteTextAI_WriteTextAI/js/model/edit/mark-reviewed',
    'WriteTextAI_WriteTextAI/js/model/edit/preferences',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/image',
    'WriteTextAI_WriteTextAI/js/utils/edit/generate',
    'WriteTextAI_WriteTextAI/js/model/signalr',
    'WriteTextAI_WriteTextAI/js/model/edit/select-template',
    'Magento_Ui/js/modal/confirm',
    'Magento_Ui/js/modal/alert',
    'mage/translate',
    'WriteTextAI_WriteTextAI/js/model/grid/popups/image-upload-progressbar',
    'accordion'
], function (
    $,
    _,
    ko,
    Component,
    product,
    editData,
    category,
    textfields,
    invalidImageModel,
    additionalPrompt,
    toolbarUtils,
    textfieldsUtils,
    settings,
    audience,
    totalCredits,
    customToneStyle,
    errorMessagesModel,
    generateSettings,
    representativeProducts,
    genKeywordAnalysis,
    keywordsData,
    keywordAnalysisData,
    markReviewed,
    preferences,
    categoryImageModel,
    generateUtils,
    signalRModel,
    selectTemplateModel,
    confirm,
    alert,
    $t,
    imageUploadProgressbarModel
) {
    'use strict';

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

    /**
     * @var {Component} self2
     */
    var self2 = {
        targetFieldId: null,
        targetFieldClass: null,
        generatedFieldId: null,
        generatedFieldIdSecondary: null,
        generatedOpenGraphEditor: null,
        generatedImageContainer: null,
        customPageTitle: null,
        customPageDescription: null,
        customProductDescription: null,
        customShortDescription: null,
        bulkGenerateImageContainer: null,
        baseUrl: null,
        activeGenerateRequest: null,  // Track active generate request
        activeUploadRequest: null,   // Track active upload request
        pendingRetryData: null       // Store data for retry
    };

    return Component.extend({
        defaults: {
            toggleSelectAllSelector: 'input[name=select_all]',
            accordionSelector: '.wtai-edit-modal-wrapper .wtai-accordions',
            accordionToggleSelector: '.wtai-wtai-toolbar .wtai-toggle-accordion',
            accordionTargetSelector: '.wtai-fieldset.wtai-text-editor',
            accordionKeywordAttributesSelector: '.wtai-keywords-attributes',
            tonesSelected: [],
            stylesSelected: '',
            suggestedAudience: [],
            selectedAudience: '',
            audienceSelected: [],
            additionalPrompt: '',
            selectAllTonesValue: null,
            selectAllAudienceValue: null,
            customTone: '',
            customStyle: '',
            guideSteps: false,
            defaultTones: [],
            defaultStyle: '',
            submitAction: 'generate',
            highlightPronouns: false,
            entityType: 'category',
            error: ''
        },

        isTonesSelectedChanged: false,
        widgetsInitialized: false,
        accordionExpanded: true,
        canUpdateTones: true,
        canUpdateAudience: true,
        isAudienceChange: false,
        isHighlightPronounsChange: false,
        typingTimer: null,

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

            self = this;
            
            self.initAjaxRetryHandler();

            this.submitAction.subscribe(function (submitAction) {
                settings.submitAction(submitAction);
            });

            this.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);
                                self.selectAllTonesValue(false);
                            }
                            if (change.status === 'added'
                                && change.value !== 'custom'
                            ) {
                                self.tonesSelected.remove('custom');
                                self.customTone('');
                            }
                        }, self);

                        if (self.canUpdateTones) {
                            self.observeTonesSelected();
                        }

                        textfields.formal(
                            self.tonesSelected().indexOf('Formal') !== -1
                        );

                        self.isTonesSelectedChanged = false;
                    }
                    
                    preferences.tonesSelected(self.tonesSelected());
                },
                this,
                'arrayChange'
            );

            this.stylesSelected.subscribe(function (style) {
                if (style !== 'custom') {
                    this.customStyle('');
                }
                preferences.stylesSelected(style);
            }, this);

            this.audienceSelected.subscribe(function (audienceSelected) {
                if (this.canUpdateAudience) {
                    this.observeAudienceSelected();
                }
                preferences.audienceSelected(audienceSelected);
                if (!this.isAudienceChange) {
                    this.savePreferences('audiences', audienceSelected);
                }
            }, this);

            this.customTone.subscribe(function (customTone) {
                if (customTone) {
                    this.tonesSelected(['custom']);
                }
                preferences.customTone(customTone);
            }, this);

            this.customStyle.subscribe(function (customStyle) {
                if (customStyle) {
                    this.stylesSelected('custom');
                }
                preferences.customTone(customStyle);
            }, this);

            editData.opened.subscribe(function (opened) {
                if (opened) {
                    this.submitAction('generate');

                    /* reset accordions */
                    $(this.accordionKeywordAttributesSelector).accordion('activate', 0);
                    $(this.accordionKeywordAttributesSelector).accordion('activate', 1);
                    $(this.accordionKeywordAttributesSelector).accordion('activate', 2);
                    $(this.accordionSelector).each(function () {
                        if ($(this).hasClass('wtai-fieldset')) {
                            $(this).accordion('activate');
                        }
                    });
                }
                if (opened && !this.widgetsInitialized) {
                    this.bindCollapsible();
                    this.bindCheckboxToggle();
                    this.bindAccordionToggle();
                    this.widgetsInitialized = true;
                }
            }, this);

            settings.guideSteps.subscribe(function (guideSteps) {
                self.guideSteps(guideSteps);
            });

            self.highlightPronouns.subscribe(function (highlightPronouns) {
                if (!self.isHighlightPronounsChange) {
                    textfields.highlightPronouns(highlightPronouns);
                    self.saveHighlightPronouns(highlightPronouns);
                }
            });

            textfields.highlightPronouns.subscribe(
                function (highlightPronouns) {
                    self.isHighlightPronounsChange = true;
                    self.highlightPronouns(highlightPronouns);
                    self.isHighlightPronounsChange = false;
                }
            );

            self.selectedAudience.subscribe(function (selectedAudience) {
                if (!self.selectedAudiencechanged) {
                    audience.selectedAudience(selectedAudience);
                }
            });

            audience.selectedAudience.subscribe(function (selectedAudience) {
                self.selectedAudiencechanged = true;
                self.selectedAudience(selectedAudience);
                self.selectedAudiencechanged = false;
            });

            audience.suggestedAudience.subscribe(function (suggestedAudience) {
                self.suggestedAudience(suggestedAudience);
            });

            customToneStyle.customTone.subscribe(function (customTone) {
                self.customTone(customTone);
            });

            customToneStyle.customStyle.subscribe(function (customStyle) {
                self.customStyle(customStyle);
            });

            additionalPrompt.promptValue.subscribe(function (promptValue) {
                self.additionalPrompt(promptValue);
            });
        },

        /** @inheritdoc */
        initObservable: function () {
            this._super().observe([
                'suggestedAudience',
                'selectedAudience',
                'tonesSelected',
                'stylesSelected',
                'audienceSelected',
                'selectAllTonesValue',
                'selectAllAudienceValue',
                'customTone',
                'customStyle',
                'submitAction',
                'guideSteps',
                'highlightPronouns',
                'error',
                'additionalPrompt'
            ]);

            this.keywords = ko.computed(function () {
                var optimizingKeywords = keywordAnalysisData.optimizationData().allOptimizingKeywords || [];
                
                if (optimizingKeywords && optimizingKeywords.length > 0) {
                    return optimizingKeywords;
                } else {
                    return keywordsData.selectedKeywords();
                }
            }, this);

            this.formalLanguageSupport = ko.computed(function () {
                return settings.formalLanguageSupport();
            });
            
            this.formalLanguages = ko.computed(function () {
                return settings.formalLanguages();
            });

            this.language = ko.computed(function () {
                return product.language();
            });

            this.disallowedCombinations = ko.computed(function () {
                return settings.disallowedCombinations();
            });

            this.tones = ko.computed(function () {
                var tones = settings.tones(),
                    selected = tones
                        .filter(function (tone) {
                            return tone.default;
                        })
                        .map(function (tone) {
                            return tone.id;
                        });

                if (selected.length > 0) {
                    this.tonesSelected(selected);
                }

                return tones;
            }, this);

            this.styles = ko.computed(function () {
                var styles = settings.styles(),
                    selected = styles
                        .filter(function (style) {
                            return style.default;
                        })
                        .map(function (style) {
                            return style.id;
                        });

                if (selected.length > 0) {
                    this.stylesSelected(selected.shift());
                }

                return styles;
            }, this);

            this.audience = ko.computed(function () {
                var audiences = settings.audience(),
                    selected = audiences
                        .filter(function (item) {
                            return item.default;
                        })
                        .map(function (item) {
                            return item.id;
                        });

                this.isAudienceChange = true;
                this.audienceSelected(selected);
                this.isAudienceChange = false;
                    
                return audiences;
            }, this);

            this.getTonesStylesSelected = ko.computed(function () {
                var tonesCount = this.tonesSelected() ? this.tonesSelected().length : 0,
                    stylesCount = this.stylesSelected() ? 1 : 0,
                    total = tonesCount + stylesCount;

                return total + ' ' + $t('selected');
            }, this);

            this.getAudienceSelected = ko.computed(function () {
                var audienceCount = this.audienceSelected() ? this.audienceSelected().length : 0;

                return audienceCount + ' ' + $t('selected');
            }, this);
            
            this.getCustomStyleLength = ko.computed(function () {
                return textfieldsUtils.getCharCount(this.customStyle(), this.rules.maxCustomStyleLength);
            },  this);

            this.getCustomToneLength = ko.computed(function () {
                return textfieldsUtils.getCharCount(this.customTone(), this.rules.maxCustomToneLength);
            },  this);

            this.getCustomAudienceLength = ko.computed(function () {
                return textfieldsUtils.getCharCount(this.selectedAudience(), this.rules.maxCustomAudienceLength);
            },  this);

            this.selectedFields = ko.computed(function () {
                return textfields.selectedFields();
            });

            this.allFieldsSelected = ko.computed(function () {
                var allFields = [
                    'page_title',
                    'page_description',
                    'category_description'
                ];
                return allFields.every(field => this.selectedFields().includes(field));
            }, this);

            this.canGenerate = ko.computed(function () {
                var isProductOptimizing = Number(keywordAnalysisData.optimizingId()) === Number(editData.currentCategory().categoryId) &&
                        Number(keywordAnalysisData.optimizingStoreId()) === Number(editData.currentCategory().storeId),
                    keywordAnalysisOngoing = (keywordAnalysisData.optimizing() ||
                        keywordAnalysisData.isUploading()) &&
                        !keywordAnalysisData.optimized() &&
                        !keywordAnalysisData.optimizationFailed() &&
                        !keywordAnalysisData.imageUploadFailed();

                if (keywordAnalysisOngoing && isProductOptimizing) {
                    return false;
                }
                
                return textfields.selectedFields() ? textfields.selectedFields().length > 0 : false;
            }, this);

            this.rewriteAvailable = ko.computed(function () {
                var isProductOptimizing = Number(keywordAnalysisData.optimizingId()) === Number(editData.currentCategory().categoryId) &&
                    Number(keywordAnalysisData.optimizingStoreId()) === Number(editData.currentCategory().storeId),
                keywordAnalysisOngoing = (keywordAnalysisData.optimizing() ||
                    keywordAnalysisData.isUploading()) &&
                    !keywordAnalysisData.optimized() &&
                    !keywordAnalysisData.optimizationFailed() &&
                    !keywordAnalysisData.imageUploadFailed();

                if (keywordAnalysisOngoing && isProductOptimizing) {
                    return false;
                }

                var mapping = {
                    'page_title': textfields.mgPageTitle(),
                    'page_description': textfields.mgPageDescription(),
                    'category_description': textfields.mgCategoryDescription()
                };
                return textfields.selectedFields.some(field => mapping[field] !== '');
            }, this);

            this.enableHighlightPronouns = ko.computed(function () {
                return this.tonesSelected().indexOf('Formal') !== -1;
            }, this);

            return this;
        },

        /**
         * Process click functionality of select all
         * Important to always return true
         * in order for checked binding to continue working
         *
         * @returns {boolean}
         */
        processClick: function () {
            return true;
        },

        /**
         * Bind select text fields checkbox toggle.
         */
        bindCheckboxToggle: function () {
            const fields = [
                'page_title',
                'page_description',
                'category_description'
            ];
        
            $(this.toggleSelectAllSelector).on('click', (event) => {
                let value = [];
        
                if (event.target.checked) {
                    value = fields;
                }
                
                textfields.selectedFields(value);
                self.savePreferences('single_editor', value, self.entityType, 'edit');
            });
        },

        /**
         * Bind settings dropdown toggle.
         */
        bindCollapsible: function () {
            toolbarUtils.bindCollapsible();
        },

        /**
         * Bind text field accordion toggle.
         */
        bindAccordionToggle: function () {
            $(self.accordionToggleSelector).on('click', function () {
                if (self.accordionExpanded) {
                    $(self.accordionTargetSelector).accordion('deactivate');
                    $(self.accordionKeywordAttributesSelector).accordion('deactivate');
                    self.accordionExpanded = false;
                } else {
                    $(self.accordionTargetSelector).accordion('activate');
                    $(self.accordionKeywordAttributesSelector).accordion('activate');
                    self.accordionExpanded = true;
                }
            });
        },

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

        /**
         * Check if combination is not allowed
         *
         * @param {string} id
         * @param {string} type
         *
         * @returns {boolean}
         */
        isCombinationDisallowed: function (id, type) {
            return toolbarUtils.isCombinationDisallowed(id, type, self);
        },

        /**
         * Select a suggested audience.
         *
         * @param {string} selected
         * @return void
         */
        selectAudience: function (selected = null) {
            var url = self.audienceSelectUrl,
                storeId = editData.currentCategory().storeId,
                categoryId = editData.currentCategory().categoryId;

            selected = selected || self.selectedAudience();
            
            errorMessagesModel.messages([]);

            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    category_id: categoryId,
                    store_id: storeId,
                    selected: selected,
                    category_name: category.categoryName()
                },
                dataType: 'json',
                showWriteTextAILoader: true,
                showAudienceLoader: true,
                success: function (response) {
                    if (response.success) {
                        self.selectedAudience(response.selected.shift());
                        self.suggestedAudience(response.values);
                    } else {
                        errorMessagesModel.messages.push(response.message);
                    }
                }
            });
        },

        /**
         * Regenerate suggested audience.
         */
        getAudience: function () {
            var url = self.audienceGetUrl,
                storeId = editData.currentCategory().storeId,
                categoryId = editData.currentCategory().categoryId;

            self.selectedAudience('');
            self.suggestedAudience('');

            errorMessagesModel.messages([]);

            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    category_id: categoryId,
                    store_id: storeId,
                    keywords: self.keywords(),
                    category_name: category.categoryName()
                },
                dataType: 'json',
                showWriteTextAILoader: true,
                showAudienceLoader: true,
                success: function (response) {
                    if (response.success) {
                        self.selectedAudience(response.selected.shift());
                        self.suggestedAudience(response.values);
                    } else {
                        errorMessagesModel.messages.push(response.message);
                    }
                }
            });
        },

        /**
         * Get tooltip text based on disallowed combination
         *
         * @param {string} id
         * @param {string} type
         *
         * @returns {string}
         */
        getTooltipCombinationDisallowedText: function (id, type) {
            return toolbarUtils.getTooltipCombinationDisallowedText(id, type, self);
        },

        /**
         * Select all tones.
         */
        selectAllTones: function () {
            var tones = self.tones().map(function (tone) {
                if (!$('[name="tones[]"][value="' + tone.id + '"]').attr('disabled')
                    && !$('[name="tones[]"][value="' + tone.id + '"]').hasClass('wtai-disabled')) {
                    return tone.id;
                }
            }).filter(function (element) {
                return element != null;
            });

            this.canUpdateTones = false;
            if (this.selectAllTonesValue()) {
                self.tonesSelected(tones);
            } else {
                self.tonesSelected([]);
            }
            this.canUpdateTones = true;

            self.saveTonesAndStyles();
        },

        /**
         * Observe tones selected.
         */
        observeTonesSelected: function () {
            var tonesSelectedCount = self.tonesSelected() ? self.tonesSelected().length : 0;

            if (settings.tones().length === tonesSelectedCount) {
                this.selectAllTonesValue(true);
            } else {
                this.selectAllTonesValue(false);
            }
        },

        /**
         * Handle input custom audience.
         */
        handleInputAudience: function () {
            clearTimeout(self.typingTimer);

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

        /**
         * Select all audience.
         */
        selectAllAudience: function () {
            var allAudience = self.audience().map(function (data) {
                if (!$('[name="audience[]"][value="' + data.id + '"]').attr('disabled')) {
                    return data.id;
                }
            });

            this.canUpdateAudience = false;
            if (this.selectAllAudienceValue()) {
                self.audienceSelected(allAudience);
            } else {
                self.audienceSelected([]);
            }
            this.canUpdateAudience = true;
        },

        /**
         * Observe audience selected.
         */
        observeAudienceSelected: function () {
            var audienceSelectedCount = self.audienceSelected() ? self.audienceSelected().length : 0;

            if (settings.audience().length === audienceSelectedCount &&
                settings.audience().length > 0
            ) {
                this.selectAllAudienceValue(true);
            } else {
                this.selectAllAudienceValue(false);
            }
        },

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

        /**
         * Check if checkboxes are valid.
         */
        isCheckboxesValid: function () {
            var tonesSelectedCount = this.tonesSelected() ? this.tonesSelected().length : 0;

            if (tonesSelectedCount === 0) {
                this.error($t('Please select at least one tone.'));
                return false;
            } else if (
                tonesSelectedCount === 1 &&
                this.tonesSelected()[0] === 'custom' &&
                this.customTone().trim() === ''
            ) {
                this.error($t('Write your specific tone...'));
                return false;
            }

            if (this.stylesSelected() === '') {
                this.error($t('Please select a style.'));
                return false;
            } else if (
                this.stylesSelected() === 'custom' &&
                this.customStyle().trim() === ''
            ) {
                this.error($t('Write your specific style...'));
                return false;
            }

            return true;
        },

        /**
         * Generate action.
         *
         * @param {boolean} rewrite
         * @param {boolean} keywordAnalysis
         *
         * @returns {void}
         */
        generateAction: function (rewrite = false, keywordAnalysis = false) {
            if (!this.isCheckboxesValid()) {
                keywordsData.showProgress(false);
                keywordAnalysisData.isUploading(false);
                keywordAnalysisData.optimizing(false);
                alert({
                    content: this.error()
                });
                return;
            }

            let categoryImageValid = (categoryImageModel.categoryImageSelected()
                    || textfields.selectedFields().includes('category_description')) && category.image(),
                representativeProductsSelected = representativeProducts.selected().length > 0,
                representativeProductsHaveImages = representativeProducts.selected().some(product => product.image_id),
                representativeProductsValid = representativeProductsSelected && representativeProductsHaveImages;
            
            invalidImageModel.invalidImages([]);
            invalidImageModel.invalid([]);
            invalidImageModel.notSupported([]);
            invalidImageModel.downloadFailed([]);
            invalidImageModel.general([]);
            invalidImageModel.errorMessages([]);
            
            if (categoryImageValid || representativeProductsValid || keywordAnalysis) {
                this.uploadImages(rewrite, keywordAnalysis);
            } else {
                this._generate(rewrite, keywordAnalysis);
            }
        },

        /**
         * Generate validations.
         *
         * @param {boolean} rewrite
         * @param {boolean} keywordAnalysis
         *
         * @returns {void}
         */
        generate: function (rewrite = false, keywordAnalysis = false) {
            if ((textfields.selectedFields().includes('page_title') &&
                textfields.originalPageTitle() !== textfields.pageTitle()
            ) || (textfields.selectedFields().includes('page_description') &&
                textfields.originalPageDescription() !== textfields.pageDescription()
            ) || (textfields.selectedFields().includes('category_description') &&
                textfields.originalCategoryDescription() !== textfields.categoryDescription())
            ) {
                confirm({
                    content: $t('You have unsaved changes. Are you sure you want to regenerate and replace text?'),
                    buttons: [{
                        text: $t('Cancel'),
                        class: 'action-secondary action-dismiss',
                        click: function (event) {
                            keywordsData.showProgress(false);
                            keywordAnalysisData.isUploading(false);
                            keywordAnalysisData.optimizing(false);
                            this.closeModal(event);
                        }
                    }, {
                        text: $t('Ok'),
                        class: 'action-primary action-accept',
                        click: function (event) {
                            this.closeModal(event, true);
                            self.generateAction(rewrite, keywordAnalysis);
                        }
                    }]
                });
            } else {
                self.generateAction(rewrite, keywordAnalysis);
            }
        },

        /**
         * Upload images.
         *
         * @param {boolean} rewrite
         * @param {boolean} keywordAnalysis
         *
         * @returns {void}
         */
        uploadImages: function (rewrite = false, keywordAnalysis = false) {
            let data = {
                category_id: editData.currentCategory().categoryId,
                store_id: editData.currentCategory().storeId,
                products: representativeProducts.selected()
            };
            
            keywordAnalysisData.imageUploadFailed(false);

            if (category.image() && (categoryImageModel.categoryImageSelected() ||
                textfields.selectedFields().includes('category_description'))) {
                data.category_image = category.image();
            }

            if (!keywordAnalysis) {
                imageUploadProgressbarModel.visible(true);
                imageUploadProgressbarModel.toCancel(false);
                imageUploadProgressbarModel.progress(0);

                let total = data.products.filter(function (product) {
                    return product.image_id;
                }).length;
                if (data.category_image) {
                    total += 1;
                }

                imageUploadProgressbarModel.total(total);
            }

            // Track active upload request for retry mechanism
            self2.activeUploadRequest = {
                url: this.uploadUrl,
                data: data,
                rewrite: rewrite,
                keywordAnalysis: keywordAnalysis,
                startTime: Date.now()
            };

            var uploadErrorMessages = invalidImageModel.errorMessages();
            var ajaxRequest = $.ajax({
                url: this.uploadUrl,
                type: 'POST',
                data: data,
                dataType: 'json',
                success: function (response) {
                    /* Clear active upload request */
                    self2.activeUploadRequest = null;
                    
                    if (response.success) {
                        invalidImageModel.categoryImage(response.category_image);
                        if (!response.category_image) {
                            invalidImageModel.invalidImages.push(data.category_image);
                        }
                        if (response.products.failed.length > 0) {
                            response.products.failed.forEach(product => {
                                invalidImageModel.invalidImages.push(product.image);
                            });
                        }
                        if (!response.category_image || response.products.failed.length > 0) {
                            invalidImageModel.errorMessages({...uploadErrorMessages, ...response.error_messages});
                            invalidImageModel.invalid.push(...response.invalid);
                            invalidImageModel.notSupported.push(...response.not_supported);
                            invalidImageModel.downloadFailed.push(...response.download_failed);
                            invalidImageModel.general.push(...response.general);
                            
                            invalidImageModel.products(response.products);
                            if (data.category_image) {
                                invalidImageModel.categoryImage(response.category_image);
                            }
                            invalidImageModel.keywordAnalysis(keywordAnalysis);
                            invalidImageModel.isRewrite(rewrite);
                            if (keywordAnalysis) {
                                keywordAnalysisData.imageUploadFailed(true);
                            }
                            keywordsData.showProgress(false);
                            $('.wtai-categories-invalid-image-popup').modal('openModal');
                        } else {
                            self._generate(rewrite, keywordAnalysis);
                        }
                    }
                    imageUploadProgressbarModel.visible(false);
                    keywordAnalysisData.customProgressText($t('Initializing...'));
                    keywordAnalysisData.isUploading(false);
                },
                error: function (xhr, status, error) {
                    /* Clear active upload request */
                    self2.activeUploadRequest = null;
                    
                    /* Check if this was due to page being backgrounded */
                    if (status === 'abort' || (xhr && xhr.readyState === 0)) {
                        console.log('WriteText.ai: Category upload request interrupted, will retry on page focus');
                        /* Store for retry */
                        self2.pendingRetryData = {
                            type: 'category_upload',
                            data: data,
                            rewrite: rewrite,
                            keywordAnalysis: keywordAnalysis
                        };
                    } else {
                        /* Normal error handling */
                        keywordAnalysisData.imageUploadFailed(true);
                        errorMessagesModel.messages.push($t('Image upload failed. Please try again.'));
                    }
                }
            });
            
            /* Store the jqXHR object for potential abort */
            if (self2.activeUploadRequest) {
                self2.activeUploadRequest.jqXHR = ajaxRequest;
            }
        },

        /**
         * Generate request.
         *
         * @param {boolean} rewrite
         * @param {boolean} keywordAnalysis
         *
         * @returns {void}
         */
        _generate: function (rewrite = false, keywordAnalysis = false) {
            /**clear error */
            $('body').notification('clear');

            /* remove error messages */
            errorMessagesModel.messages([]);

            if (keywordAnalysis) {
                keywordsData.showProgress(true);
            }

            /* empty text fields */
            generateUtils.clearCategoryFields(self.selectedFields(), rewrite);

            let failedImageIds = [];
            let failedProducts = invalidImageModel.products() ? (invalidImageModel.products().failed ?? []) : [];
            failedProducts.forEach(product => {
                failedImageIds.push(product.image_id);
            });
            
            let products = [];
            representativeProducts.selected().forEach(product => {
                let representativeProduct = {...product};
                if (failedImageIds.includes(representativeProduct.image_id)) {
                    representativeProduct.image_id = '';
                }
                products.push(representativeProduct);
            });
            var data = {
                category_id: editData.currentCategory().categoryId,
                store_id: editData.currentCategory().storeId,
                products: products,
                category_image: invalidImageModel.categoryImage() ? category.image() : '',
                category_image_selected: categoryImageModel.categoryImageSelected(),
                name: category.categoryName(),
                tones: self.tonesSelected(),
                style: self.stylesSelected(),
                audience: self.audienceSelected(),
                custom_tone: self.customTone(),
                custom_style: self.customStyle(),
                additional_prompt: self.additionalPrompt(),
                custom_audience: self.selectedAudience(),
                selected_fields: self.selectedFields(),
                current_values: {
                    page_title: textfields.mgPageTitle(),
                    page_description: textfields.mgPageDescription(),
                    category_description: textfields.mgCategoryDescription()
                },
                min_words: generateSettings.descMin(),
                max_words: generateSettings.descMax(),
                other_details_checked: representativeProducts.otherDetailsChecked(),
                other_details: representativeProducts.otherDetails(),
                rewrite: rewrite,
                keyword_analysis_views: genKeywordAnalysis.views(),
                keywords: self.keywords(),
                search_intent_selected: keywordsData.searchIntentSelected(),
                keyword_analysis: keywordAnalysis,
                product_research_data: representativeProducts.productResearchData(),
                templates_used: selectTemplateModel.selectedTemplates,
                url: product.productUrl()
            };
            
            // Track active generate request for retry mechanism
            self2.activeGenerateRequest = {
                url: self.generateUrl,
                data: data,
                startTime: Date.now()
            };
            

            var ajaxRequest = $.ajax({
                url: self.generateUrl,
                type: 'POST',
                data: data,
                dataType: 'json',
                showWriteTextAILoader: true,
                showPageTitleLoader: self.selectedFields().includes('page_title'),
                showPageDescriptionLoader: self.selectedFields().includes('page_description'),
                showCategoryDescriptionLoader: self.selectedFields().includes('category_description'),
                success: function (response) {
                    /* Clear active request */
                    self2.activeGenerateRequest = null;
                    
                    if (response.success) {
                        markReviewed.reviewed(response.reviewed);
                        genKeywordAnalysis.views(0);
                    } else {
                        keywordAnalysisData.optimizationFailed(true);
                        keywordAnalysisData.optimizing(false);
                        keywordsData.showProgress(false);
                        self.getGenerated(self.selectedFields(), rewrite);
                        if (response.message) {
                            errorMessagesModel.messages.push(response.message);
                        }
                        signalRModel.generating(false);
                        
                        generateUtils.removeIdentifierFromCurrentlyGeneratingRecordIdentifiers('Category');
                        if (response.unauthorized) {
                            window.location.href = response.login_url;
                        }
                    }
                },
                error: function(xhr, status, error) {

                    // Clear active request
                    self2.activeGenerateRequest = null;
                    
                    // Check if this was due to page being backgrounded
                    if (status === 'abort' || (xhr && xhr.readyState === 0)) {
                        console.log('WriteText.ai: Generate request interrupted, will retry on page focus');
                        // Store for retry
                        self2.pendingRetryData = {
                            url: self.generateUrl,
                            data: data
                        };
                    } else {
                        // Normal error handling
                        errorMessagesModel.messages.push($t('An error occurred while generating content. Please try again.'));
                        signalRModel.generating(false);
                        generateUtils.removeIdentifierFromCurrentlyGeneratingRecordIdentifiers('Product');
                    }
                }
            });
            
            /* Store the jqXHR object for potential abort */
            if (self2.activeGenerateRequest) {
                self2.activeGenerateRequest.jqXHR = ajaxRequest;
            }
        },

        /**
         * Get generated texts.
         *
         * @param {array} selectedFields
         * @param {boolean} rewrite
         *
         * @returns {void}
         */
        getGenerated: function (selectedFields, rewrite) {
            errorMessagesModel.messages([]);

            $.ajax({
                url: self.getGeneratedUrl,
                type: 'POST',
                data: {
                    category_id: editData.currentCategory().categoryId,
                    store_id: editData.currentCategory().storeId,
                },
                dataType: 'json',
                showWriteTextAILoader: true,
                showPageTitleLoader: selectedFields.includes('page_title'),
                showPageDescriptionLoader: selectedFields.includes('page_description'),
                showCategoryDescriptionLoader: selectedFields.includes('category_description'),
                success: function (response) {
                    if (response.success) {
                        if (selectedFields.includes('page_title')) {
                            if (!rewrite || (rewrite && textfields.mgPageTitle() !== '')) {
                                textfields.pageTitle(response.generated_texts.page_title);
                                textfields.originalPageTitle(response.generated_texts.page_title);
                            }
                        }
                        if (selectedFields.includes('page_description')) {
                            if (!rewrite || (rewrite && textfields.mgPageDescription() !== '')) {
                                textfields.pageDescription(response.generated_texts.page_description);
                                textfields.originalPageDescription(response.generated_texts.page_description);
                            }
                        }
                        if (selectedFields.includes('category_description')) {
                            if (!rewrite || (rewrite && textfields.mgCategoryDescription() !== '')) {
                                textfields.categoryDescription(response.generated_texts.category_description);
                                textfields.originalCategoryDescription(response.generated_texts.category_description);
                            }
                        }
                    } else {
                        errorMessagesModel.messages.push(response.message);
                    }
                }
            });
        },

        /**
         * Save user settings for highlighted pronouns.
         *
         * @param {boolean} highlighted
         * @returns {void}
         */
        saveHighlightPronouns: function (highlighted) {
            $.ajax({
                url: self.highlightPronounsUrl,
                type: 'POST',
                data: {
                    highlighted: highlighted,
                    entity_type: self.entityType
                },
                dataType: 'json',
                showWriteTextAILoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response.message);
                    }
                }
            });
        },

        /**
         * 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 = '';
            }

            $.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);
                    }
                }
            });
        },

        /**
         * Initialize AJAX retry handler for _generate function only
         */
        initAjaxRetryHandler: function() {
            // Listen for admin-idle.js events
            $(document).on('wtai:user-return', function() {
                console.log('WriteText.ai: User returned, checking for interrupted generation');
                self.checkAndRetryGenerate();
            });
            
            // Also use Page Visibility API as backup
            document.addEventListener('visibilitychange', function() {
                if (!document.hidden) {
                    console.log('WriteText.ai: Page became visible');
                    setTimeout(function() {
                        self.checkAndRetryGenerate();
                    }, 500);
                }
            });
            
            // Handle focus event for additional reliability on tablets
            window.addEventListener('focus', function() {
                setTimeout(function() {
                    self.checkAndRetryGenerate();
                }, 500);
            });
        },
        
        /**
         * Check for interrupted generate and upload requests and retry
         */
        checkAndRetryGenerate: function() {
            // Check if we have pending retry data
            if (self2.pendingRetryData) {
                console.log('WriteText.ai: Retrying interrupted request');
                var retryData = self2.pendingRetryData;
                self2.pendingRetryData = null;
                
                if (retryData.type === 'category_upload') {
                    // Check if upload is still needed
                    if (imageUploadProgressbarModel && imageUploadProgressbarModel.visible()) {
                        console.log('WriteText.ai: Retrying category upload');
                        self.uploadImages(retryData.rewrite, retryData.keywordAnalysis);
                    } else {
                        console.log('WriteText.ai: Category upload no longer active, skipping retry');
                        imageUploadProgressbarModel.visible(false);
                        keywordAnalysisData.customProgressText($t('Initializing...'));
                        keywordAnalysisData.isUploading(false);
                    }
                } else {
                    self._generate(false, retryData.keyword_analysis ?? false);
                }
            }
            
            // Check if generate request is stuck
            if (self2.activeGenerateRequest) {
                var now = Date.now();
                var duration = now - self2.activeGenerateRequest.startTime;
                
                // If request has been running for more than 60 seconds, retry
                if (duration > 60000) {
                    console.log('WriteText.ai: Generate request appears stuck, retrying');
                    
                    // Abort if possible
                    if (self2.activeGenerateRequest.jqXHR && self2.activeGenerateRequest.jqXHR.abort) {
                        self2.activeGenerateRequest.jqXHR.abort();
                    }
                    
                    // Store for retry
                    self2.pendingRetryData = {
                        type: 'generate',
                        url: self2.activeGenerateRequest.url,
                        data: self2.activeGenerateRequest.data
                    };
                    
                    self2.activeGenerateRequest = null;
                    
                    // Retry
                    self.checkAndRetryGenerate();
                }
            }
            
            // Check if upload request is stuck
            if (self2.activeUploadRequest) {
                var now = Date.now();
                var duration = now - self2.activeUploadRequest.startTime;
                
                // If request has been running for more than 60 seconds, retry
                if (duration > 60000) {
                    console.log('WriteText.ai: Category upload request appears stuck, retrying');
                    
                    // Abort if possible
                    if (self2.activeUploadRequest.jqXHR && self2.activeUploadRequest.jqXHR.abort) {
                        self2.activeUploadRequest.jqXHR.abort();
                    }
                    
                    // Store for retry
                    self2.pendingRetryData = {
                        type: 'category_upload',
                        rewrite: self2.activeUploadRequest.rewrite,
                        keywordAnalysis: self2.activeUploadRequest.keywordAnalysis
                    };
                    
                    self2.activeUploadRequest = null;
                    
                    // Retry
                    self.checkAndRetryGenerate();
                }
            }
        },

        /**
         * Save user preferences
         *
         * @param {string} field
         * @param {string} selected
         * @param {string} entityType
         *
         * @returns {void}
         */
        savePreferences: function (field, selected, entityType = '', scope = '') {
            var value = selected;
            
            if (value.length <= 0) {
                value = '';
            }
            
            $.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);
                    }
                }
            });
        },

        /**
         * Reset settings.
         *
         * @param {string} type
         * @returns {void}
         */
        reset: function (type) {
            if (type === 'tones') {
                self.tonesSelected(self.defaultTones);
                self.stylesSelected(self.defaultStyle);
                self.saveTonesAndStyles();
            }

            if (type === 'audience') {
                self.audienceSelected([...self.defaultAudiences]);
            }
        }
    });
});
