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

define([
    'jquery',
    'uiComponent',
    'underscore',
    'ko',
    'mage/translate',
    'WriteTextAI_WriteTextAI/js/model/edit',
    'WriteTextAI_WriteTextAI/js/categories/model/edit',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keywords',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keyword-analysis',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keyword-pipelines',
    'WriteTextAI_WriteTextAI/js/model/edit/product',
    'WriteTextAI_WriteTextAI/js/model/edit/textfields',
    'WriteTextAI_WriteTextAI/js/categories/model/edit/textfields',
    'WriteTextAI_WriteTextAI/js/model/edit/gallery',
    'WriteTextAI_WriteTextAI/js/utils/edit/textfields',
    'WriteTextAI_WriteTextAI/js/model/total-credits',
    'WriteTextAI_WriteTextAI/js/model/edit/error-messages',
    'WriteTextAI_WriteTextAI/js/model/edit/settings',
    'WriteTextAI_WriteTextAI/js/edit/buttons',
    'WriteTextAI_WriteTextAI/js/categories/edit/buttons',
    'WriteTextAI_WriteTextAI/js/utils/edit/generate',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/progress',
    'WriteTextAI_WriteTextAI/js/model/edit/generate/currently-generating',
    'WriteTextAI_WriteTextAI/js/model/grid/notifications',
    'WriteTextAI_WriteTextAI/js/model/signalr',
    'WriteTextAI_WriteTextAI/js/categories/model/signalr',
    'WriteTextAI_WriteTextAI/js/model/edit/audience',
    'WriteTextAI_WriteTextAI/js/model/edit/invalid-image-popup',
    'Magento_Ui/js/modal/confirm',
    'Magento_Ui/js/modal/modal'
], function (
    $,
    Component,
    _,
    ko,
    $t,
    editData,
    categoriesEditData,
    keywordsData,
    keywordAnalysisData,
    keywordPipelinesData,
    product,
    productTextfields,
    categoryTextfields,
    gallery,
    textfieldsUtils,
    totalCredits,
    errorMessagesModel,
    settings,
    productsButtons,
    categoriesButtons,
    generateUtils,
    progress,
    currentlyGeneratingModel,
    notifications,
    signalRModel,
    categoriesSignalRModel,
    audience,
    invalidImagePopupModel,
    confirm
) {
    'use strict';

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

    return Component.extend({
        defaults: {
            newKeyword: '',
            newKeywordLength: 0,
            selectedKeywords: [],
            searchIntents: [
                'transactional',
                'commercial',
                'navigational',
                'informational'
            ],
            searchIntentSelected: [],
            recordId: 0,
            storeId: 0,
            modal: {
                class: 'wtai-edit-modal wtai-edit-keyword-analysis',
                selector: '.wtai-edit-keyword-analysis',
                overlayClass: 'modals-overlay wtai-keyword-overlay',
                overlaySelector: '.wtai-keyword-overlay',
                contentSelector: '.wtai-keyword-analysis',
                editModal: '.wtai-edit-main'
            },
            selectors: {
                calendar: '.wtai-calendar'
            },
            manualKeywordInputError: '',
            autoGenerate: false,
            autoRewrite: false,
            seeCurrentPipelineLoading: 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)
            },
            isKeywordAnalysisAllowed: false
        },
        
        isSelectedKeywordsChange: false,
        isSelectedSearchIntentChange: false,
        isAutoGenerateRewriteChange: false,
        autoGenerateRewriteAfterKo: false,
        isSingleSelectedWarningVisible: false,

        gettingData: null,
        getOptimizationAjax: null,

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

            self = this;

            this.bindModal();
            
            /** Add click-outside handler for heads-up popup */
            this.bindHeadsUpClickOutside();

            /** Add click-outside handler for single item tooltip */
            this.bindSingleItemTooltipClickOutside();

            signalRModel.isConnected.subscribe(function (isConnected) {
                console.log('isConnected', isConnected);
                if (editData.opened() && isConnected &&
                    keywordAnalysisData.optimizing()
                ) {
                    self.getOptimizationStuck();
                }
            }, this);

            /** Categories SignalR connection status */
            categoriesSignalRModel.isConnected.subscribe(function (isConnected) {
                console.log('isConnected', isConnected);
                if (categoriesEditData.opened() && isConnected &&
                    keywordAnalysisData.optimizing()
                ) {
                    self.getOptimizationStuck();
                }
            }, this);

            totalCredits.hasProAccess.subscribe(function (hasProAccess) {
                if (!hasProAccess &&
                    $(self.modal.contentSelector).data('mageModal') &&
                    $(self.modal.contentSelector).data('mageModal').options.isOpen
                ) {
                    $(self.modal.contentSelector).modal('closeModal');
                }
            }, this);

            keywordsData.apiThumbnail.subscribe(function () {
                if (this.hasProAccess() && this.isOptimizationStarted()) {
                    this.updateThumbnail();
                }
            }, this);
            
            keywordsData.searchIntentSelected.subscribe(function (searchIntent) {
                if (!this.isSelectedSearchIntentChange) {
                    self.searchIntentSelected(searchIntent);
                }
            }, this);

            self.searchIntentSelected.subscribe(function (searchIntent) {
                this.isSelectedSearchIntentChange = true;
                keywordsData.searchIntentSelected(searchIntent);
                this.isSelectedSearchIntentChange = false;
            }, this);

            keywordsData.selectedKeywords.subscribe(function (keywords) {
                this.isSelectedKeywordsChange = true;
                this.selectedKeywords(keywords);
                this.isSelectedKeywordsChange = false;
            }, this);

            keywordsData.resetKeywordInput.subscribe(function (value) {
                if (value === true) {
                    this.manualKeywordInputError('');
                    this.newKeyword('');
                }
            }, this);

            self.selectedKeywords.subscribe(function (keywords) {
                if (!this.isSelectedKeywordsChange) {
                    keywordsData.selectedKeywords(keywords);
                    this.saveKeywords();
                }
            }, this);

            categoriesEditData.currentCategory.subscribe(function (category) {
                this.recordId(category.categoryId);
                this.storeId(category.storeId);
            }, this);

            editData.currentProduct.subscribe(function (product) {
                this.recordId(product.productId);
                this.storeId(product.storeId);
            }, this);

            this.autoGenerate.subscribe(function (value) {
                if (!this.isAutoGenerateRewriteChange) {
                    this.savePreferences('auto_generate_after_ko', value, '', 'edit');
                }
                if (this.autoRewrite() !== value
                    && this.enableAutoRewrite()
                    && editData.initialized()) {
                    this.autoRewrite(value);
                }
            }, this);

            this.autoRewrite.subscribe(function (value) {
                if (!this.isAutoGenerateRewriteChange) {
                    this.savePreferences('auto_generate_after_ko', value, '', 'edit');
                }
                if (this.autoGenerate() !== value
                    && this.enableAutoGenerate()
                    && editData.initialized()) {
                    this.autoGenerate(value);
                }
            }, this);

            keywordsData.autoGenerateRewriteAfterKo.subscribe(function (value) {
                this.isAutoGenerateRewriteChange = true;
                this.autoGenerateRewriteAfterKo(value);
                this.autoGenerate(value);
                this.autoRewrite(value);
                this.isAutoGenerateRewriteChange = false;
            }, this);
        },

        /** @inheritdoc */
        initObservable: function () {
            this._super().observe([
                'newKeyword',
                'newKeywordLength',
                'searchIntentSelected',
                'selectedKeywords',
                'recordId',
                'storeId',
                'manualKeywordInputError',
                'autoGenerate',
                'autoRewrite',
                'seeCurrentPipelineLoading',
                'autoGenerateRewriteAfterKo',
                'isAcknowledgedHeadsUp',
                'messageHeadsUp',
                'positionHeadsUp',
                'targetElementHeadsUp',
                'isVisibleHeadsUp',
                'isSingleSelectedWarningVisible'
            ]);

            this.hasProAccess = ko.computed(function () {
                return totalCredits.hasProAccess();
            });

            this.status = ko.computed(function () {
                var status = keywordAnalysisData.statuses().find(function (status) {
                    return Number(status.storeId) === Number(self.storeId()) && String(status.recordId) === String(self.recordId());
                });

                if (status) {
                    return status;
                }

                return {};
            }, this);

            this.enableStartAIpowered = ko.computed(function () {
                var recordId = this.recordId();
                var storeId = this.storeId();
                var entityType = this.entityType;
                var identifier = entityType + '_'+ recordId + '_' + storeId;

                var isBulkGenerating = notifications.statuses().some((status) => {
                    return (status.status === 'Running' || status.status === 'Pending') && (
                            status.queuedIds.indexOf(String(recordId)) !== -1 ||
                            status.runningIds.indexOf(String(recordId)) !== -1
                        );
                }, this);

                if (keywordAnalysisData.refreshingData() || isBulkGenerating) {
                    return false;
                }
                var currentlyGeneratingRecordIdentifiers = currentlyGeneratingModel.recordIdentifiers();
                return !currentlyGeneratingRecordIdentifiers.includes(identifier);
            }, this);

            this.enableAutoGenerate = ko.computed(function () {
                switch (this.entityType) {
                    case 'Product':
                        var canGenerateFields = productTextfields.selectedFields() ? productTextfields.selectedFields().length > 0 : false,
                            canGenerateMedia = gallery.selectedImages() ? gallery.selectedImages().length > 0 : false;

                        return canGenerateFields || canGenerateMedia;
                    case 'Category':
                        return categoryTextfields.selectedFields() ? categoryTextfields.selectedFields().length > 0 : false;
                }
            }, this);

            this.enableAutoRewrite = ko.computed(function () {
                switch (this.entityType) {
                    case 'Product':
                        var selectedFields = productTextfields.selectedFields(),
                            selectedImages = gallery.selectedImages(),
                            images = gallery.images();
                        var canRewriteFields = selectedFields.some((field) => {
                            return (
                                field === 'page_title' &&
                                    productTextfields.mgPageTitle() !== '' ||
                                field === 'page_description' &&
                                    productTextfields.mgPageDescription() !== '' ||
                                field === 'product_description' &&
                                    productTextfields.mgProductDescription() !== '' ||
                                field === 'short_product_description' &&
                                    productTextfields.mgProductShortDescription() !== '' ||
                                self.customOpenGraph &&
                                    field === 'open_graph' &&
                                    productTextfields.mgOpenGraph() !== ''
                            );
                        }),
                        canRewriteMedia = images.some((image) => {
                            return image.alt !== '' && selectedImages.includes(image.id)
                        });

                        return Boolean(canRewriteFields || canRewriteMedia);
                    case 'Category':
                        var mapping = {
                            'page_title': categoryTextfields.mgPageTitle(),
                            'page_description': categoryTextfields.mgPageDescription(),
                            'category_description': categoryTextfields.mgCategoryDescription()
                        };
                        return categoryTextfields.selectedFields.some(field => mapping[field] !== '');
                }
            }, this);

            this.disableSeePipeline = ko.computed(function () {
                if (!this.hasProAccess()) {
                    return true;
                }

                if (!this.enableStartAIpowered()) {
                    return true;
                }

                return (keywordAnalysisData.optimizing() ||
                    keywordAnalysisData.isUploading()) &&
                    !keywordAnalysisData.optimized() &&
                    !keywordAnalysisData.optimizationFailed() &&
                    !keywordAnalysisData.imageUploadFailed();
            }, this);

            this.showAutoGenerate = ko.computed(function () {
                return true;
            });

            this.isOptimizationStarted = ko.computed(function () {
                return (keywordAnalysisData.optimizing() ||
                        keywordAnalysisData.isUploading() ||
                        keywordAnalysisData.optimized()) &&
                    this.status().status !== 'Failed' &&
                    !keywordAnalysisData.optimizationFailed() &&
                    !keywordAnalysisData.imageUploadFailed();
            }, this);

            this.isOptimizationNotStarted = ko.computed(function () {
                return this.status().status === 'Failed' ||
                    (!keywordAnalysisData.optimizing() &&
                        !keywordAnalysisData.isUploading() &&
                        !keywordAnalysisData.optimized()) ||
                    keywordAnalysisData.optimizationFailed() ||
                    keywordAnalysisData.imageUploadFailed();
            }, this);

            this.showPendingText = ko.computed(function () {
                if (keywordAnalysisData.refreshingData()) {
                    return true;
                }
                return this.status().status !== 'Failed' &&
                    (keywordAnalysisData.optimizing() ||
                        keywordAnalysisData.isUploading()
                    ) &&
                    !keywordAnalysisData.optimized() &&
                    !keywordAnalysisData.optimizationFailed() &&
                    !keywordAnalysisData.imageUploadFailed();
            }, this);

            this.dsiableRestart = ko.computed(function () {
                if (keywordAnalysisData.refreshingData()) {
                    return true;
                }

                return this.status().status !== 'Failed' &&
                    (keywordAnalysisData.optimizing() ||
                        keywordAnalysisData.isUploading()
                    ) &&
                    !keywordAnalysisData.optimized() &&
                    !keywordAnalysisData.optimizationFailed() &&
                    !keywordAnalysisData.imageUploadFailed();
            }, this);

            this.showFailedText = ko.computed(function () {
                return keywordAnalysisData.optimizationData().status === 'Failed' ||
                    this.status().status === 'Failed' || (
                    !keywordAnalysisData.optimizing() &&
                    !keywordAnalysisData.isUploading() &&
                    !keywordAnalysisData.optimized() &&
                    keywordAnalysisData.imageUploadFailed()
                );
            }, this);

            this.optimizingKeywords = ko.computed(function () {
                return keywordAnalysisData.optimizationData().allOptimizingKeywords || [];
            }, this);

            this.optimizingIntent = ko.computed(function () {
                if (keywordAnalysisData.optimizing() || keywordAnalysisData.isUploading()) {
                    return this.searchIntentSelected();
                }

                return keywordAnalysisData.optimizationData().intents || [];
            }, this);

            this.keywordsCount = ko.computed(function () {
                var count = this.selectedKeywords()
                    ? this.selectedKeywords().length
                    : 0;

                return '(' + count + '/' + this.rules.maxKeywords + ')';
            }, this);

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

            this.disableInputKeyword = ko.computed(function () {
                return this.selectedKeywords().length >= this.rules.maxKeywords;
            }, this);

            this.maxKeywordsError = ko.computed(function () {
                return $t('You can only add up to %s. Remove a keyword to add a new one.')
                    .replace('%s', this.rules.maxKeywords);
            }, this);
            
            this.isKoRefreshing = ko.computed(function () {
                return keywordAnalysisData.refreshingData();
            }, this);

            this.isKoRunning = ko.computed(function () {
                return keywordAnalysisData.optimizing() &&
                    (this.status().status === 'Running' || this.status().status === 'Completed');
            }, this);

            this.isKoPending = ko.computed(function () {
                var recordId = this.recordId();
                var status = progress.getStatusByRecord(this.storeId(), recordId, this.entityType);
                var statusNormalId = progress.getStatusByRecordNormalId(this.storeId(), recordId, this.entityType);
                var isPending = keywordAnalysisData.optimizing() && status && status.status === 'Pending';
                var isPendingNormalId = keywordAnalysisData.optimizing() && statusNormalId && statusNormalId.status === 'Pending';
                var isOpitziationDataQueued = keywordAnalysisData.optimizationData().status === 'Pending';

                if (isPending || isPendingNormalId || isOpitziationDataQueued) {
                    keywordAnalysisData.customProgressText($t('Queued for keyword analysis'));
                    return true;
                }
                return false;
            }, this);
            
            
            this.autoGenerateAndRewrite = ko.computed({
                read: function () {
                    this.isAutoGenerateRewriteChange = true;
                    if (this.showAutoGenerate() === true && editData.initialized()) {
                        switch (this.entityType) {
                            case 'Product':
                                var selectedTexts = productTextfields.selectedFields();
                                var selectedImages = gallery.selectedImages();
                                if (selectedTexts.length === 0 && selectedImages.length === 0) {
                                    this.autoGenerate(false);
                                    this.autoRewrite(false);
                                } else {
                                    this.autoGenerate(this.autoGenerateRewriteAfterKo());
                                    this.autoRewrite(this.autoGenerateRewriteAfterKo());
                                }
                                break;
                            case 'Category':
                                const categorySelectedTexts = categoryTextfields.selectedFields();
                                if (categorySelectedTexts.length === 0) {
                                    this.autoGenerate(false);
                                    this.autoRewrite(false);
                                } else {
                                    this.autoGenerate(this.autoGenerateRewriteAfterKo());
                                    this.autoRewrite(this.autoGenerateRewriteAfterKo());
                                }
                                break;
                        }
                    }
                    this.isAutoGenerateRewriteChange = false;
                    return;
                }.bind(this)
            }, this);

            return this;
        },

        /**
         * Check if thumbnail changed and upload new thumbnail.
         */
        updateThumbnail: function () {
            var apiThumbnail = keywordsData.apiThumbnail();
            var platformThumbnail = keywordsData.thumbnailId();

            if (apiThumbnail && apiThumbnail !== platformThumbnail) {
                $.ajax({
                    url: this.newThumbnailUrl,
                    type: 'POST',
                    data: {
                        store_id: self.storeId(),
                        image: keywordsData.thumbnail(),
                        image_id: keywordsData.thumbnailId(),
                        type: self.entityType,
                        record_id: self.recordId()
                    },
                    dataType: 'json',
                    showLoader: true,
                    success: function (response) {
                        if (!response.success) {
                            console.log(response);
                        }
                    }
                });
            }
        },

        /**
         * Bind keyword analysis modal.
         */
        bindModal: function () {
            $(this.modal.contentSelector).modal({
                type: 'slide',
                modalClass: this.modal.class,
                title: 'WriteText.ai',
                overlayClass: this.modal.overlayClass,
                innerScroll: true,
                buttons: [{
                    class: 'wtai-link-preview action',
                    attr: {
                        title: $.mage.__('View')
                    },
                    click: function () {
                        self.linkPreview(this);
                    }
                },
                {
                    class: 'wtai-history-log action',
                    attr: {
                        title: $.mage.__('History log')
                    },
                    click: function () {
                        self.openHistoryLog();
                    }
                }],
                outerClickHandler: function () {
                    $(this.modal.contentSelector).modal('closeModal');
                }.bind(this),
                closed: function () {
                    self.getOptimization();
                    $(this.modal.overlaySelector).remove();
                    keywordAnalysisData.historyMode(false);
                    keywordAnalysisData.storeCurrentOptimizationData({});
                    keywordPipelinesData.forceResetEditPipeline(false); /** set to false first to trigger change*/
                    keywordPipelinesData.forceResetEditPipeline(true);
                    keywordPipelinesData.editKeywordRankingVisible(false);
                    keywordPipelinesData.editKeywordRankingVisible.valueHasMutated();
                }.bind(this),
                opened: function () {
                    $(self.selectors.calendar).datepicker("setDate", null);
                    $(this.modal.selector).trigger('contentUpdated');
                }.bind(this)
            });
        },

        /**
         * Get Keyword input note.
         */
        getKeywordInputNote: function () {
            return $t('Enter up to %s keywords. Press <ENTER> or use a comma to separate each keyword.').replace('%s', self.rules.maxKeywords);
        },

        /**
         * Get keyword length.
         */
        getKeywordLength: function () {
            return (
                this.newKeywordLength() +
                '/' +
                this.rules.maxKeywordLength +
                ' ' +
                $t('Char')
            );
        },

        /**
         * Get thumbnail.
         */
        getThumbnail: function (isForUpload = false) {
            if (self.entityType === 'Category'
                && keywordsData.thumbnail() === ''
                && isForUpload === false
            ) {
                return keywordsData.categoryPlaceholderImage();
            }
            return keywordsData.thumbnail();
        },

        /**
         * Open modal.
         */
        openModal: function (refreshOptimization = false) {
            if (!self.hasProAccess()) {
                return;
            }

            if (refreshOptimization) {
                self.seeCurrentPipelineLoading(true);
                $(self.modal.editModal + ' .action-close').prop('disabled', true);
                $.ajax({
                    url: self.getOptimizationUrl,
                    type: 'POST',
                    data: {
                        store_id : self.storeId(),
                        record_id: self.recordId(),
                        entity_type: self.entityType
                    },
                    dataType: 'json',
                    showLoader: false,
                    success: function (response) {
                        keywordAnalysisData.optimizationData({});
                        keywordAnalysisData.optimizationData(response.api_response);
                        keywordAnalysisData.snapshotData(response.api_response.snapshots || {});

                        $(self.modal.contentSelector).modal('openModal');
                    }
                }).always(function () {
                    self.seeCurrentPipelineLoading(false);
                    $(self.modal.editModal + ' .action-close').prop('disabled', false);
                });
            } else {
                $(self.modal.contentSelector).modal('openModal');
            }
        },

        /**
         * Start AI powered keyword analysis
         */
        startAIpoweredKeywordAnallysis: function () {
            /** Build request data right away to fix issue when switching to other products */
            var requestData = {
                record_id: self.recordId(),
                store_id: self.storeId(),
                entity_type: self.entityType,
                url: product.productUrl(),
                name: product.productName(),
                image_id: keywordsData.thumbnailId(),
                /** seed_keywords: self.selectedKeywords(), */
                search_intent_selected: self.searchIntentSelected()
            };

            if (!self.hasProAccess()) {
                return;
            }

            progress.commentHidden(false);
            keywordAnalysisData.customProgressText('');
            keywordsData.showProgress(true);
            keywordsData.noGenerateOnAutoGenerateAfterKo(false);
            signalRModel.toGetGenerated(false);
            categoriesSignalRModel.toGetGenerated(false);

            var statuses = keywordAnalysisData.statuses();
            keywordAnalysisData.statuses(statuses.filter(function (status) {
                return Number(status.storeId) !== Number(self.storeId()) || status.recordId !== self.recordId();
            }));

            keywordAnalysisData.optimizingId(self.recordId());
            keywordAnalysisData.optimizingStoreId(self.storeId());

            if (self.showAutoGenerate() && self.autoGenerate()) {
                keywordAnalysisData.autoGenerateOrRewriteChecked(true);
                signalRModel.toGetGenerated(true);
                categoriesSignalRModel.toGetGenerated(true);
            } else {
                keywordAnalysisData.autoGenerateOrRewriteChecked(false);
            }
            
            if (self.getThumbnail(true)) {
                self.uploadImages(requestData);
            } else {
                self.startAIpoweredRequest(requestData);
            }
        },

        /**
         * Start AI powered request
         *
         * @param {Object} requestData
         * @returns {void}
         */
        startAIpoweredRequest: function (requestData = {}) {
            keywordAnalysisData.customOptFailedText('');
            keywordAnalysisData.optimizationFailed(false);
            keywordAnalysisData.optimizing(true);
            errorMessagesModel.messages([]);

            if (self.showAutoGenerate() && self.autoGenerate()) {
                switch (self.entityType) {
                    case 'Product':
                        productsButtons.prototype.generate(false, true);
                        break;
                    case 'Category':
                        categoriesButtons.prototype.generate(false, true);
                        break;
                }

                return;
            }

            keywordAnalysisData.customProgressText($t('Preparing for keyword analysis...'));
            generateUtils.requestKeywordAnalysis(self.updateOptimizationUrl, self.entityType);
        },

        /**
         * Upload images.
         *
         * @param {Object} requestData
         * @returns {void}
         */
        uploadImages: function (requestData = {}) {
            keywordAnalysisData.imageUploadFailed(false);
            keywordAnalysisData.isUploading(true);
            var uploadText1 = $t('Preparing assets for keyword ideas generation.');
            var uploadText2 = $t('Please keep this page open and avoid reloading, closing, switching tabs, or minimizing until preparation is finished.');
            keywordAnalysisData.customProgressText("<div><span>" + uploadText1 + "</span><span class='wtai-red-highlight'>" + uploadText2 + "</span></div>");
            $.ajax({
                url: this.uploadUrl,
                type: 'POST',
                data: {
                    store_id: self.storeId(),
                    image: keywordsData.thumbnail(),
                    image_id: keywordsData.thumbnailId()
                },
                dataType: 'json',
                success: function (response) {
                    if (response.success || keywordAnalysisData.autoGenerateOrRewriteChecked()) {
                        if (!response.success) {
                            keywordAnalysisData.imageUploadFailedIdentifier(true);
                        }
                        if (!keywordAnalysisData.autoGenerateOrRewriteChecked()) {
                            keywordAnalysisData.customProgressText('');
                            keywordAnalysisData.isUploading(false);
                        }
                        self.startAIpoweredRequest(requestData);
                    } else {
                        keywordAnalysisData.customProgressText('');
                        keywordAnalysisData.imageUploadFailed(true);
                        keywordAnalysisData.customOptFailedText($t('You can proceed with keyword optimization without the invalid image(s) being taken into consideration, or cancel and upload a different image to try again.'));
                        keywordAnalysisData.imageUploadFailedIdentifier(true);
                        if (response.error_messages) {
                            keywordAnalysisData.uploadErrorMessage(response.error_messages);
                        }
                        if (response.message) {
                            keywordAnalysisData.uploadErrorMessage(response.message);
                        }
                        if (!!invalidImagePopupModel.doNotShowAgain() || !!window.wtaiInvalidImagePopupDoNotShowAgain) {
                            keywordsData.showProgress(true);
                            keywordAnalysisData.optimizing(true);
                            keywordAnalysisData.isUploading(false);
                            keywordAnalysisData.optimized(false);
                            keywordAnalysisData.optimizationFailed(false);
                            keywordAnalysisData.imageUploadFailed(false);
                            keywordAnalysisData.customOptFailedText('');
                            keywordAnalysisData.customProgressText($t('Queued for keyword analysis'));
                            self.startAIpoweredRequest(requestData);
                        } else {
                            $('.wtai-keywords-invalid-image-popup').modal('openModal');
                            keywordsData.showProgress(false);
                        }
                    }
                },
                error: function (xhr, status, error) {
                    keywordsData.showProgress(false);
                    errorMessagesModel.messages.push($t('A system error has occurred. Please try again. If the issue persists, please contact our support team at support@writetext.ai.'));
                }
            });
        },

        /**
         * Restart AI powered keyword analysis
         */
        restartAIpoweredKeywordAnallysis: function () {
            confirm({
                content: $t('This will take you back to the screen where'
                    + ' you can add seed keywords and will reset your keyword optimization pipeline,'
                    + ' including deleting any custom pipelines you may have created.'
                    + ' Do you want to continue?'),
            buttons: [{
                text: $t('Cancel'),
                class: 'action-secondary action-dismiss',
                click: function (event) {
                    this.closeModal(event);
                }
                }, {
                    text: $t('Ok'),
                    class: 'action-primary action-accept',
                    click: function (event) {
                        this.closeModal(event, true);
                        if (self.showPendingText()) {
                            return;
                        }
                        self.deleteOptimization();
                    }
                }]
            });
        },

        /**
         * Is intent selected
         *
         * @param {String} intent
         * @return {Boolean}
         */
        isIntentSelected: function (intent) {
            return self.searchIntentSelected().indexOf(intent) !== -1;
        },

        /**
         * Get tooltip text search intent
         *
         * @param {String} intent
         * @return {String}
         */
        getTooltipTextSearchIntent: function (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) {
            if (!self.isKeywordAnalysisAllowed) {
                return;
            }
            if (!self.hasProAccess()) {
                return;
            }
            self.isSingleSelectedWarningVisible(false);

            var searchIntentSelected = self.searchIntentSelected();
            if (searchIntentSelected.length <= 1 &&
                searchIntentSelected.indexOf(intent) !== -1
            ) {
                self.headsupVisibility.transactional(false);
                self.headsupVisibility.commercial(false);
                self.headsupVisibility.navigational(false);
                self.headsupVisibility.informational(false);
                self.isSingleSelectedWarningVisible(true);
                return;
            }

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

            self.searchIntentSelected(searchIntentSelected);

            var searchIntentSelected = '';
            if (self.searchIntentSelected().length !== 0) {
                searchIntentSelected = self.searchIntentSelected().join(',');
            }
            self.savePreferences('search_intent', searchIntentSelected, self.entityType.toLowerCase(), '');
        },

        /**
         * Show educational tooltip for non-transactional intent selection
         *
         * @param {String} intent
         * @return {void}
         */
        showEducationalTooltipForIntent: function (intent) {
            if (!self.isKeywordAnalysisAllowed) {
                return;
            }

            if (!self.hasProAccess()) {
                return;
            }

            if (self.isAcknowledgedHeadsUp()) {
                return;
            }
            var searchIntentSelected = self.searchIntentSelected();
            if (searchIntentSelected.length > 0 && searchIntentSelected.indexOf(intent) !== -1) {
                this.selectIntent(intent);
                return;
            }

            var message = '';
            if (self.entityType === 'Product') {
                message = $t('<p>Heads up! Product pages are typically intended for <strong>transactional</strong> 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.<p>');
            } else {
                message = $t('<p>Heads up! Category pages are generally best suited for <strong>commercial</strong> search intent—users comparing options and researching before making a purchase.</p><p>Using other intent types might not align well unless your category content is specifically designed for that purpose. Be sure it supports your broader SEO and user journey strategy.</p>');
            }

            if (self.entityType === 'Product') {
                /** Only show tooltip for non-transactional intents */
                if (intent === 'transactional') {
                    return;
                }
            } else {
                /** Only show tooltip for non-commercial intents */
                if (intent === 'commercial') {
                    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
                );
            }
        },

        /**
         * Input keyword
         */
        inputKeyword: function (data, event) {
            if (!self.isKeywordAnalysisAllowed) {
                return;
            }
            self.validateInvalidCharacters(data, event);
            if (event.target.value.length > self.rules.maxKeywordLength) {
                event.target.value = event.target.value.slice(0, self.rules.maxKeywordLength);
            }

            self.newKeywordLength(event.target.value.length);

            if (event.key === ',' || event.key === 'Enter') {
                var invalidChars = /[,.!@%^*()={};~`<>?\\|]/g;
                var keywords = self.selectedKeywords();
                var baseKeyword = event.target.value;
                if (baseKeyword.trim() === '' || baseKeyword === ',') {
                    return;
                }

                if (baseKeyword.endsWith(',')) {
                    baseKeyword = baseKeyword.slice(0, -1);
                }
                
                var invalidCharList = [];
                var matchedChars = baseKeyword.match(invalidChars) || [];
                if (matchedChars.length > 0) {
                    matchedChars.forEach(function (char) {
                        if (!invalidCharList.includes(char)) {
                            invalidCharList.push(char);
                        }
                    });
                    if (invalidCharList.length === 1) {
                        self.manualKeywordInputError($t('"%s" is an invalid character.').replace('%s', invalidCharList[0]));
                    } else {
                        self.manualKeywordInputError($t('"%s" are invalid characters.').replace('%s', invalidCharList.join(' ')));
                    }
                    event.target.value = event.target.value.replace(invalidChars, '');

                    return;
                }
                
                const renderedBaseKeyword = $($.parseHTML(baseKeyword.trim())).text().toLowerCase();
                const renderedKeywords = keywords.map(keyword => $($.parseHTML(keyword.trim())).text().toLowerCase());
                
                if (renderedKeywords.indexOf(renderedBaseKeyword) !== -1) {
                    self.manualKeywordInputError($t('The entered keyword already exists.'));
                    event.target.value = baseKeyword;

                    return;
                }

                if (keywords.length >= self.rules.maxKeywords) {
                    self.manualKeywordInputError(self.maxKeywordsError());
                    event.target.value = baseKeyword;
                    
                    return;
                }
                self.addKeyword(baseKeyword.toLowerCase().trim());
                event.target.value = '';
                self.newKeywordLength(0);
            }
        },

        /**
         * On paste
         *
         * @param {*} data
         * @param {*} event
         */
        onPaste: function (data, event) {
            var text = event.originalEvent.clipboardData.getData("text/plain");
            event.currentTarget.value = text;
            self.validateInvalidCharacters(data, event);
        },

        /**
         * Validate invalid characters
         *
         * @param {*} data
         * @param {*} event
         */
        validateInvalidCharacters: function (data, event) {
            var invalidChars = /[,.!@%^*()={};~`<>?\\|]/g;
            var keyword = event.currentTarget.value.toLowerCase().trim();

            var invalidCharList = [];
            var matchedChars = keyword.match(invalidChars) || [];
            if (matchedChars.length > 0) {
                matchedChars.forEach(function (char) {
                    if (!invalidCharList.includes(char)) {
                        invalidCharList.push(char);
                    }
                });
                if (invalidCharList.length === 1) {
                    self.manualKeywordInputError($t('"%s" is an invalid character.').replace('%s', invalidCharList[0]));
                } else {
                    self.manualKeywordInputError($t('"%s" are invalid characters.').replace('%s', invalidCharList.join(' ')));
                }
                event.currentTarget.value = event.currentTarget.value.replace(invalidChars, '');
            } else {
                /** handle paste using ctrl+v */
                if (event.keyCode !== 17) {
                    const isCtrlV = event.keyCode === 86 && (event.ctrlKey || event.metaKey); /** Check for 'Ctrl + V' or 'Cmd + V' */
                    const isVKey = event.key === 'v' || event.key === 'V';
                    if (isCtrlV) {
                        /** Do nothing if paste using 'Ctrl + V' */
                    } else if (isVKey) {
                        /** If 'v' is typed, remove the error and clear text */
                        self.manualKeywordInputError('');
                    } else {
                        /** For any other key, clear the error */
                        self.manualKeywordInputError('');
                    }
                }
            }
        },

        /**
         * Add keyword
         *
         * @param {String} keyword
         * @return {Boolean}
         */
        addKeyword: function (keyword) {
            var keywords = self.selectedKeywords();

            self.manualKeywordInputError('');
            keywords.push(keyword);
            self.selectedKeywords(keywords);
            self.newKeyword('');
        },

        /**
         * Keyword density
         *
         * @param {*} keyword
         * @return {Number}
         */
        keywordDensity: function (keyword) {
            return ko.computed(function () {
                return self.calculateKeywordDensity(keyword);
            });
        },

        /**
         * Calculate the keyword density for a given keyword.
         *
         * @param {string} keyword
         *
         * @returns {string} Formatted keyword density
         */
        calculateKeywordDensity: function (
            keyword
        ) {
            if (!keyword) {
                return ' (0.00%)';
            }

            switch (self.entityType) {
                case 'Product':
                    var productDescription = productTextfields.productDescription() || '',
                        productShortDescription = productTextfields.productShortDescription() || '';

                    if (!productDescription && !productShortDescription) {
                        return ' (0.00%)';
                    }

                    var productDescWordCount = textfieldsUtils.getWordCount(productDescription, false),
                        productShortDescWordCount = textfieldsUtils.getWordCount(productShortDescription, false),
                        keywordWordCount = textfieldsUtils.getWordCount(keyword, false),
                        totalWordCount = productDescWordCount + productShortDescWordCount,
                        productDescKeywordCount = textfieldsUtils.countKeywordOccurences(productDescription, keyword),
                        productShortDescKeywordCount = textfieldsUtils.countKeywordOccurences(productShortDescription, keyword),
                        productDescKeywordOccur = productDescKeywordCount * keywordWordCount,
                        productShortDescKeywordOccur = productShortDescKeywordCount * keywordWordCount,
                        totalKeywordCount = productDescKeywordOccur + productShortDescKeywordOccur;
                    
                    break;
                case 'Category':
                    var categoryDescription = categoryTextfields.categoryDescription();

                    if (!categoryDescription) {
                        return ' (0.00%)';
                    }
        
                    var totalWordCount = textfieldsUtils.getWordCount(categoryDescription, false),
                        keywordWordCount = textfieldsUtils.getWordCount(keyword, false),
                        catDescKeywordCount = textfieldsUtils.countKeywordOccurences(categoryDescription, keyword),
                        totalKeywordCount = catDescKeywordCount * keywordWordCount;
                    
                    break;
                default:
                    return ' (0.00%)';
            }

            var keywordDensity = (totalKeywordCount / totalWordCount) * 100,
                parsedKeywordDensity = parseFloat(keywordDensity, 10).toFixed(2);

            return ' (' + parsedKeywordDensity + '%)';
        },

        /**
         * Remove keyword
         *
         * @param {*} keyword
         * @return {void}
         */
        removeKeyword: function (keyword) {
            if (!self.isKeywordAnalysisAllowed) {
                return;
            }
            self.manualKeywordInputError('');
            var keywords = self.selectedKeywords(),
                index = keywords.indexOf(keyword);

            if (index > -1) {
                keywords.splice(index, 1);
                self.selectedKeywords(keywords);
            }
        },
        
        /**
         * Save user preferences
         *
         * @param {String} field
         * @param {String} selected
         * @param {String} entityType
         * @param {String} scope
         *
         * @return {void}
         */
        savePreferences: function (field, selected, entityType = '', scope = '') {
            var value = selected;
            
            if (value.length <= 0) {
                value = '';
            }
            
            if (field === 'auto_generate_after_ko') {
                if (self.gettingData !== null) {
                    self.gettingData.abort();
                }
            }
            this.gettingData = $.ajax({
                url: self.saveUserSettingsUrl,
                type: 'POST',
                data: {
                    [field]: value,
                    entity_type: entityType,
                    scope: scope
                },
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    } else {
                        if (field === 'auto_generate_after_ko') {
                            this.autoGenerateRewriteAfterKo(value);
                        }
                    }
                }.bind(this),
                error: function (xhr, status, error) {
                    if (status !== 'abort') {
                        console.log(error);
                    }
                }
            });
        },

        /**
         * Save keywords
         */
        saveKeywords: function () {
            var selectedKeywords = self.selectedKeywords();

            $.ajax({
                url: self.saveKeywordsUrl,
                type: 'POST',
                data: {
                    record_id: self.recordId(),
                    store_id: self.storeId(),
                    keywords: selectedKeywords,
                    entity_type: self.entityType
                },
                dataType: 'json',
                showWriteTextAILoader: true,
                showLoader: false,
                success: function (response) {
                    if (!response.success) {
                        console.log(response);
                    }
                }
            });
        },

        /**
         * Delete optimization
         */
        deleteOptimization: function () {
            $.ajax({
                url: self.deleteOptimizationUrl,
                type: 'POST',
                data: {
                    record_id: self.recordId(),
                    store_id: self.storeId(),
                    entity_type: self.entityType
                },
                dataType: 'json',
                showLoader: true,
                success: function (response) {
                    if (response.success) {
                        keywordAnalysisData.optimizing(false);
                        keywordAnalysisData.isUploading(false);
                        keywordAnalysisData.optimized(false);
                        keywordAnalysisData.optimizationFailed(false);
                        keywordAnalysisData.imageUploadFailed(false);
                        keywordAnalysisData.uploadErrorMessage([]);
                    }
                    if (response.error) {
                        errorMessagesModel.messages([response.error]);
                    }
                }
            }).always(function () {
                self.getOptimization();
            });
        },

        /**
         * Get optimization.
         *
         * @param {boolean} showLoader
         * @returns {void}
         */
        getOptimization: function (showLoader = false) {
            $.ajax({
                url: self.getOptimizationUrl,
                type: 'POST',
                data: {
                    store_id : self.storeId(),
                    record_id: self.recordId(),
                    entity_type: self.entityType
                },
                dataType: 'json',
                showLoader: true,
                success: function (response) {
                    keywordAnalysisData.optimizationData(response.api_response);
                    keywordAnalysisData.snapshotData(response.api_response.snapshots || {});
                    
                    var selKeywords = [];
                    if (response.api_response.optimizingKeywords
                        && response.api_response.optimizingKeywords.length > 0) {
                        selKeywords = response.api_response.optimizingKeywords;
                    } else {
                        selKeywords = response.api_response.manualKeywords;
                    }
                }
            });
        },

        /**
         * Get text for restart optimization
         *
         * @returns {string}
         */
        getRestartOptText: function () {
            if (!self.hasProAccess()) {
                return $t('Manually enter keywords');
            }
            return $t('Restart AI-powered keyword analysis');
        },

        /**
         * Open preview.
         *
         * @param {Object} modal
         * @returns {void}
         */
        linkPreview: function (modal) {
            $.each(modal.buttons, function (index, button) {
                if ($(button).is('.wtai-link-preview')) {
                    let link = $(button).data('link');

                    window.open(link, '_blank');
                }
            });
        },
        

        /**
         * Open history log modal.
         */
        openHistoryLog: function () {
            $('.wtai-history-log-modal').modal('openModal');
        },

        /**
         * 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);

            this.isSingleSelectedWarningVisible(false);

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

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

        acknowledgeHeadsUp: function ($intent) {
            /*self.isAcknowledgedHeadsUp(true);
            */
            self.headsupVisibility.transactional(false);
            self.headsupVisibility.commercial(false);
            self.headsupVisibility.navigational(false);
            self.headsupVisibility.informational(false);
            this.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);
                }
            });
        },

        /**
         * Bind click-outside handler for single item tooltip.
         */
        bindSingleItemTooltipClickOutside: 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;
                }

                /** Close single item tooltip */
                self.isSingleSelectedWarningVisible(false);
            });
        },

        /**
         * Get optimization. This is only use for stuck optimization.
         *
         * @returns {void}
         */
        getOptimizationStuck: function () {

            if (self.getOptimizationAjax) {
                self.getOptimizationAjax.abort();
            }

            self.getOptimizationAjax = $.ajax({
                url: self.getOptimizationUrl,
                type: 'POST',
                data: {
                    store_id : self.storeId(),
                    record_id: self.recordId(),
                    entity_type: self.entityType
                },
                dataType: 'json',
                showLoader: false,
                success: function (response) {
                    if (response.api_response.status === 'Completed'
                        || response.api_response.status === 'Failed'
                        || response.api_response.status === 'TimedOut'
                    ) {
                        keywordsData.showProgress(false);
                        keywordAnalysisData.optimizationData(response.api_response);
                        keywordAnalysisData.snapshotData(response.api_response.snapshots || {});
                        
                        if (signalRModel.generating() || categoriesSignalRModel.generating()) {
                            signalRModel.generating(false);
                            categoriesSignalRModel.generating(false);
                            generateUtils.removeIdentifierFromCurrentlyGeneratingRecordIdentifiers(self.entityType);
                        }
                        
                        var koStatuses = keywordAnalysisData.statuses();
                        koStatuses.forEach(function (koStatus, index) {
                            if (Number(koStatus.storeId) === Number(response.api_response.storeId) &&
                                    Number(koStatus.recordId) === Number(response.api_response.recordId)) {
                                koStatuses.splice(index, 1);
                            }
                        });
                        keywordAnalysisData.statuses(koStatuses);
                        keywordAnalysisData.statuses.valueHasMutated();

                        if (response.api_response.status === 'Completed' &&
                            !keywordAnalysisData.autoGenerateOrRewriteChecked()
                        ) {
                            $('.wtai-keyword-analysis').modal('openModal');
                        }

                        signalRModel.triggerHandleUserReturn(true);
                        categoriesSignalRModel.triggerHandleUserReturn(true);
                    } else if (response.api_response.status === 'InProgress') {
                        var koStatuses = keywordAnalysisData.statuses();
                        koStatuses.forEach(function (koStatus) {
                            if (koStatus.requestId === response.api_response.id) {
                                koStatus.status = response.api_response.status;
                                koStatus.statusDisplay = response.api_response.statusMessage;
                                koStatus.completed = response.api_response.completedSteps;
                            }
                        });
                        keywordAnalysisData.statuses(koStatuses);
                        keywordAnalysisData.statuses.valueHasMutated();
                    }
                },
                error: function (xhr, status, error) {
                    if (status !== 'abort') {
                        errorMessagesModel.messages.push(error);
                    }
                }
            });
        }
    });
});
