/**
 * @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/keywords/keyword-analysis',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keyword-pipelines',
    'WriteTextAI_WriteTextAI/js/model/edit',
    'WriteTextAI_WriteTextAI/js/utils/edit/textfields',
    'WriteTextAI_WriteTextAI/js/categories/model/edit',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/trigger-settings',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/pipeline-keyword',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/empty-pipeline',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/edit-pipeline',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/pipeline',
    'WriteTextAI_WriteTextAI/js/edit/keywords/keyword-pipelines/base',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/error-messages',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/triggers',
    "jquery/ui",
    "Magento_Theme/js/sortable",
    "wtaiJqueryUiTouchPunch",
    'mage/dropdown'
], function (
    $,
    Component,
    _,
    ko,
    $t,
    keywordAnalysis,
    keywordPipelines,
    editData,
    textfieldsUtils,
    categoriesEditData,
    triggerSettings,
    pipelineKeyword,
    emptyPipeline,
    editPipeline,
    pipeline,
    base,
    errorMessagesModel,
    triggers
) {
    'use strict';

    /**
     * @var {Component} self
     */
    var self;
    
    return Component.extend({
        defaults: {
            selectors: {
                pipeline: '.wtai-keyword-pipeline',
                editPipeline: '.wtai-pipeline-edit.wtai-keyword-edit-pipeline',
                emptyPipeline: '.wtai-custom-pipeline-empty',
                editPipelineContainer: '.wtai-pipelines.wtai-edit-pipeline-container',
                editPipelineWrapper: '.wtai-edit-pipelines-wrapper'
            },
            tsSelectors: {
                active: '.wtai-trigger-settings.active',
                activeContent: '.wtai-trigger-settings.active .wtai-dropdown-content',
                errorMessage: '.wtai-trigger-settings.active .wtai-error-message',
                dropdownActive: '.wtai-trigger-settings.active .wtai-dropdown-trigger',
                checkedOption: '.wtai-trigger-settings.active .trigger-action-input:checked',
                checkedAction: '.wtai-trigger-settings.active .wtai-auto-text-optimization-input:checked',
                nPositionValue: '.wtai-trigger-settings.active .wtai-input-number[name="trigger_action_n_position"]',
                nDaysValue: '.wtai-trigger-settings.active .wtai-input-number[name="trigger_action_n_days"]',
                allTextFields: '.wtai-trigger-settings.active input[id^="wtaiAllTextFields"',
                checkedTextFields: '.wtai-trigger-settings.active input[name^="text_fields_"]:checked',
                textFieldErrorMessage: '.wtai-trigger-settings.active .wtai-rewrite-fieldset .wtai-error-message',
                allNPosition: '.wtai-trigger-settings .wtai-input-number[name="trigger_action_n_position"]',
                allNDays: '.wtai-trigger-settings .wtai-input-number[name="trigger_action_n_days"]',
                allInputNumber: '.wtai-trigger-settings .wtai-input-number'
            },
            editKeywordPipeline: [],
            editKeywordPipelineVisible: false,
            expectedNumberOfKeywords: 5,
            maxNumberOfKeywordPipeline: 6,
            newKeywordLength: 0,
            newActiveKeywordsInput: {},
            newKeywordRequestCount: 0,
            inputActive: false,
            historyMode: false,
            triggerUpdating: false,
            pipelineDifficulties: ['High', 'MidHigh', 'Mid', 'LowMid', 'Low'],
            storeId: 0,
            recordId: 0,
            showEmptyLoader: false,
            customValidationMessage: "<label class='mage-error'>%s</label>",
            tsActiveTriggerAction: '',
            tsActiveTriggerActionDays: '',
            tsActiveTriggerActionPosition: '',
            tsActiveAutoOptimize: '',
            tsActiveTextFields: [],
            tsContainerClass: 'bottom-right',
            ongoingProcessing: false,
            disableCloseAction: false,
            savingToPool: false
        },
        preventInputBlur: false,

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

            self = this;

            this.editKeywordPipelineVisible.subscribe(function (editKeywordPipelineVisible) {
                keywordPipelines.editKeywordPipelineVisible(editKeywordPipelineVisible);
            });

            keywordAnalysis.historyMode.subscribe(function (historyMode) {
                if (historyMode) {
                    $(self.selectors.editPipeline).sortable("disable");
                    $(self.selectors.emptyPipeline).sortable("disable");
                } else {
                    $(self.selectors.editPipeline).sortable("enable");
                    $(self.selectors.emptyPipeline).sortable("enable");
                }
                self.historyMode(historyMode);
            });

            this.editKeywordPipeline.subscribe(function (editKeywordPipeline) {
                keywordPipelines.editKeywordPipeline(editKeywordPipeline);
            });

            keywordPipelines.forceResetEditPipeline.subscribe(function (forceResetEditPipeline) {
                if (forceResetEditPipeline) {
                    this.closeEditPipeline();
                }
            }, this);

            keywordPipelines.forceNewPipeline.subscribe(function (forceNewPipeline) {
                if (forceNewPipeline) {
                    emptyPipeline.openEmptyCustom(self);
                } else {
                    emptyPipeline.closeEmptyCustom(self);
                }
            }, this);

            keywordPipelines.preventInputBlur.subscribe(function (preventInputBlur) {
                self.preventInputBlur = preventInputBlur;
            }, 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);

            self.tsActiveTriggerAction.subscribe(function (value) {
                if (value) {
                    $(self.tsSelectors.active + ' .trigger-action-input').prop('checked', false);
                    $(self.tsSelectors.active + ' .trigger-action-input[value="' + value + '"]').prop('checked', true);
                }
            }, this);

            self.tsActiveTriggerActionDays.subscribe(function (value) {
                if (value) {
                    $(self.tsSelectors.nDaysValue).val(value);
                }
            }, this);

            self.tsActiveTriggerActionPosition.subscribe(function (value) {
                if (value) {
                    $(self.tsSelectors.nPositionValue).val(value);
                }
            }, this);

            self.tsActiveAutoOptimize.subscribe(function (value) {
                if (value) {
                    $(self.tsSelectors.checkedAction).prop('checked', false);
                    $(self.tsSelectors.active + ' .wtai-auto-text-optimization-input[value="' + value + '"]').prop('checked', true);
                }
            }, this);

            self.tsActiveTextFields.subscribe(function (value) {
                let textMapping = self.textFieldMapping;
                if (value) {
                    if (value.length === Object.keys(textMapping).length) {
                        $(self.tsSelectors.allTextFields).prop('checked', true);
                    } else {
                        $(self.tsSelectors.allTextFields).prop('checked', false);
                    }
                    
                    $(self.tsSelectors.checkedTextFields).prop('checked', false);
                    value.forEach(function (field) {
                        let fieldValue = Object.keys(textMapping).find(key => textMapping[key] === field);
                        $(self.tsSelectors.active + ' input[value="'+fieldValue+'"]').prop('checked', true);
                    });
                }
            }, this);

        },

        /** @inheritdoc */
        initObservable: function () {
            this._super().observe([
                'editKeywordPipeline',
                'editKeywordPipelineVisible',
                'newKeywordLength',
                'newActiveKeywordsInput',
                'newKeywordRequestCount',
                'inputActive',
                'historyMode',
                'triggerUpdating',
                'storeId',
                'recordId',
                'showEmptyLoader',
                'tsActiveTriggerAction',
                'tsActiveTriggerActionDays',
                'tsActiveTriggerActionPosition',
                'tsActiveAutoOptimize',
                'tsActiveTextFields',
                'tsContainerClass',
                'ongoingProcessing',
                'disableCloseAction',
                'savingToPool'
            ]);

            this.pipelines = ko.computed(function () {
                if (!keywordAnalysis.optimizationData()) {
                    return [];
                }
                var pipelineList = keywordAnalysis.optimizationData().pipelines;
                if (pipelineList) {
                    return pipelineList.filter(pipeline => pipeline.autogenerated === true);
                } else {
                    return [];
                }
            }, this);

            this.customPipelines = ko.computed(function () {
                if (!keywordAnalysis.optimizationData()) {
                    return [];
                }
                var pipelineList = keywordAnalysis.optimizationData().pipelines;
                if (pipelineList) {
                    return pipelineList.filter(pipeline => pipeline.autogenerated === false);
                } else {
                    return [];
                }
            }, this);

            this.isCustomKeywordEmptyVisible = ko.computed(function () {
                if (keywordAnalysis.historyMode() === true) {
                    return false;
                }
                if (this.editKeywordPipelineVisible()) {
                    if (this.editKeywordPipeline().id === undefined) {
                        return false;
                    }
                }
                var totalPipeline = this.customPipelines().length + this.pipelines().length;
                if (totalPipeline < this.maxNumberOfKeywordPipeline) {
                    return true;
                }
                return false;
            }, this);

            this.ranges = ko.computed(function () {
                return keywordAnalysis.optimizationData().ranges;
            });

            this.previousAvailable = ko.computed(function () {
                return keywordAnalysis.optimizationData().availableClustersToRestore > 0;
            });

            this.getKeywordLength = ko.computed(function () {
                return (
                    this.newKeywordLength() +
                    '/' +
                    this.rules.maxKeywordLength +
                    ' ' +
                    $t('Char')
                );
            }, this);

            this.triggerSettingsDisabled = ko.computed(function () {
                return this.historyMode() || this.triggerUpdating();
            }, this);

            this.autoArrangeDisabled = ko.computed(function () {
                var emptyPipeline = this.editKeywordPipeline();
                var isCurrentEditKeywordLessOrEqualOne = false;
                if (this.newKeywordRequestCount() > 0) {
                    return true;
                }
                if (keywordAnalysis.optimizationData().pipelines) {
                    var pipeline = keywordAnalysis.optimizationData().pipelines.find(pipeline => pipeline.id === emptyPipeline.id);
                    if (pipeline) {
                        /** Total keywords - keywords that are not editable. Check if it's less or equal to 1 */
                        isCurrentEditKeywordLessOrEqualOne = this.countNotAvailableKeywords(pipeline) <= 1;
                    }
                }
                return this.inputActive() || isCurrentEditKeywordLessOrEqualOne;
            }, this);

            this.saveDisabled = ko.computed(function () {
                var pipelines = keywordAnalysis.optimizationData().pipelines || [];
                var originalPipeline = pipelines.find(pipeline => pipeline.id === this.editKeywordPipeline().id);

                if (this.inputActive()) {
                    return true;
                }

                if (this.newKeywordRequestCount() > 0) {
                    return true;
                }

                if (!originalPipeline) {
                    if (this.editKeywordPipeline().keywords === undefined) {
                        return true;
                    }
                    if (Object.keys(this.editKeywordPipeline().keywords).length === 0) {
                        return true;
                    }
                }
                
                const findDifferences = (obj1, obj2, path = '') => {
                    if (!obj1 || !obj2) {
                        return true;
                    }
                    
                    let hasDifferences = false;
                    
                    Object.keys(obj1).forEach(key => {
                        const currentPath = path ? `${path}.${key}` : key;
                        if (typeof obj1[key] === 'object' && obj1[key] !== null) {
                            var obj1Length = Object.keys(obj1[key]).length;
                            var obj2Length = obj2[key] && typeof obj2[key] === 'object' ? Object.keys(obj2[key]).length : 0;
                            if (obj1Length != obj2Length) {
                                hasDifferences = true;
                            }
                            if (findDifferences(obj1[key], obj2[key], currentPath)) {
                                hasDifferences = true;
                            }
                        } else if (obj1[key] !== obj2[key]) {
                            hasDifferences = true;
                        }
                    });
                    return hasDifferences;
                };
                var hasDifferences = findDifferences(originalPipeline, this.editKeywordPipeline());
                return !hasDifferences;
            }, this);

            this.disableRewriteFields = ko.computed(function () {
                return this.tsActiveTriggerAction() === 'none' || this.tsActiveAutoOptimize() === 'flag';
            }, this);

            this.isEditMaskVisible = ko.computed(function () {
                return this.editKeywordPipelineVisible() || keywordAnalysis.editKeywordRankingVisible();
            }, this);

            this.getPrimaryKeyword = ko.computed(function () {
                if (keywordAnalysis.optimizationData() &&
                    keywordAnalysis.optimizationData().optimizingKeywords &&
                    keywordAnalysis.optimizationData().optimizingKeywords.length > 0) {
                    return keywordAnalysis.optimizationData().optimizingKeywords[0];
                }
                return null;
            }, this);

            this.hidePipelineActions = ko.computed(function () {
                return this.editKeywordPipelineVisible() || keywordAnalysis.editKeywordRankingVisible() || this.historyMode();
            }, this);

            this.disableAction = ko.computed(function () {
                return this.ongoingProcessing() || this.historyMode();
            }, this);

            this.newKeywordRequestCount.subscribe(function (newKeywordRequestCount) {
                if (newKeywordRequestCount >= 1) {
                    $(self.selectors.editPipeline).sortable("disable");
                } else {
                    $(self.selectors.editPipeline).sortable("enable");
                }
            }, this);

            this.hasKeywordRankingBaseOnPosition = ko.computed(function () {
                if (keywordAnalysis.optimizationData() && keywordAnalysis.optimizationData().keywords) {
                    return keywordAnalysis.optimizationData().keywords.some(keyword => keyword.position > 0);
                }
                return false;
            }, this);

            return this;
        },

        /**
         * Initialize keyword edit blur event
         */
        initKeywordEditBlurEvent: function () {
            $(function () {
                /** Force blur on active inputs when mousedown anywhere in document */
                $(document).on('mousedown', function (event) {
                    /** Find active keyword inputs */
                    var activeInputs = $('.wtai-edit-keyword-item.wtai-input-active input.admin__control-text');
                    
                    /** Only blur if we have at least one active and focused input */
                    if (activeInputs.length) {
                        /** Check if any of these inputs is currently focused */
                        var focusedInput = activeInputs.filter(function () {
                            return this === document.activeElement;
                        });
                        
                        /** Don't trigger blur if clicking the input itself */
                        if (focusedInput.length && !$(event.target).is(focusedInput)) {
                            /** Using setTimeout to ensure this executes after other event bindings */
                            setTimeout(function () {
                                focusedInput.blur();
                            }, 0);
                        }
                    }
                });
            });
        },

        /**
         * Initialize sortable.
         */
        initSortable: function () {
            var $parentContainer = $('.wtai-edit-keyword-analysis .modal-content');
            var $pipelinesContent = $('.wtai-keyword-analysis-content .wtai-pipelines-content');

            $(self.selectors.editPipeline).sortable({
                tolerance: 'pointer',
                items: 'li',
                scroll: false,
                containment: '#wtaiKeywordEditPipeline',
                placeholder: 'wtai-placeholder ui-sortable-handle wtai-on-drag-placeholder',
                cancel: '.wtai-placeholder, .wtai-keyword.wtai-previous, .wtai-input-active, .wtai-keyword.wtai-current',
                start: function (event, ui) {
                    keywordPipelines.preventInputBlur(true);
                    $('.wtai-edit-keyword-item.wtai-input-active:not(.wtai-saving-keyword)').find('.admin__control-text').blur();
                    ui.placeholder.html($t('Add keyword from pool'));
                },
                over: function (event, ui) {
                    /*ui.placeholder.removeClass('wtai-not-allowed');*/
                    ui.item.removeClass('wtai-not-allowed');
                },
                out: function (event, ui) {
                    if (ui.helper) {
                        /** force to move the placehoder back the pool */
                        ui.helper.after(ui.placeholder);
                        $('#wtaiKeywordPoolList').sortable('refresh');
                    }
                },
                receive: function (event, ui) {
                    var nextElement = ui.item.next(),
                        prevElement = ui.item.prev(),
                        nextElDifficulty = nextElement.attr('wtai-placeholder-difficulty'),
                        prevElDifficulty = prevElement.attr('wtai-placeholder-difficulty'),
                        targetDifficulty = nextElDifficulty !== undefined ? nextElDifficulty : prevElDifficulty,
                        bothDefined = (nextElDifficulty !== undefined && prevElDifficulty !== undefined),
                        keyword = ui.item.find(".wtai-keyword").text();

                    let editKeywordPipeline = self.editKeywordPipeline();
                    let keywordPool = keywordAnalysis.optimizationData().keywords;
                    var keywordData = keywordPool.find(kw => kw.keyword === keyword) || { keyword: keyword, manual: true };

                    if (targetDifficulty === undefined) {
                        /** make sure to cancel the sortable if not dragging to a placeholder.
                         * This is to make sure that the item is not added to the edit pipeline
                         */
                        ui.sender.sortable("cancel");

                        if (nextElement.attr('data-wtai-difficulty')) {
                            /** if the next element has a data-wtai-difficulty attribute,
                             * it means the item is dragged to an existing keyword
                             * and needs to be added and replace the existing keyword */
                            targetDifficulty = nextElement.attr('data-wtai-difficulty');

                            if (self.isPrevious(targetDifficulty, editKeywordPipeline.currentLevel)) {
                                $(self.selectors.editPipeline).sortable("cancel");
                                ui.sender.sortable("cancel");
                                return;
                            }

                            if (self.isIosSafari && self.isIosSafari()) {
                                if (editKeywordPipeline.keywords && editKeywordPipeline.keywords[targetDifficulty] !== undefined) {
                                    delete editKeywordPipeline.keywords[targetDifficulty];
                                    self.editKeywordPipeline([]);
                                    self.editKeywordPipeline(editKeywordPipeline);
                                }
                            }

                            editKeywordPipeline.keywords[targetDifficulty] = keywordData;
                            self.editKeywordPipeline([]);
                            self.editKeywordPipeline(editKeywordPipeline);
                            ui.item.remove();
                        }
                    } else {
                        /** If targetDifficulty is defined, it means the item is dragged to a placeholder */
                        nextElement.hide();
                        if (self.isIosSafari && self.isIosSafari()) {
                            if (editKeywordPipeline.keywords && editKeywordPipeline.keywords[targetDifficulty] !== undefined) {
                                delete editKeywordPipeline.keywords[targetDifficulty];
                                self.editKeywordPipeline([]);
                                self.editKeywordPipeline(editKeywordPipeline);
                            }
                        }
                        editKeywordPipeline.keywords[targetDifficulty] = keywordData;
                        self.editKeywordPipeline([]);
                        self.editKeywordPipeline(editKeywordPipeline);
                        ui.item.remove();
                    }

                    self.afterDragRefresh();
                },
                stop: function (event, ui) {
                    ui.item.removeClass('wtai-not-allowed');

                    var indexedKeywords = [];
                    $('.ui-sortable-handle:visible').find('.wtai-edit-pipeline-keyword-text').each(function () {
                        if ($(this).data('wtai-placeholder-text') === undefined) {
                            indexedKeywords.push($(this).text());
                        } else {
                            indexedKeywords.push('skipped');
                        }
                    });

                    var keywordsData = {};
                    for (let i = 0; i < indexedKeywords.length; i++) {
                        if (indexedKeywords[i] === 'skipped') {
                            continue;
                        }
                        keywordsData[self.pipelineDifficulties[i]] = Object.values(self.editKeywordPipeline().keywords).find(k => k.keyword === indexedKeywords[i]);
                    }

                    var newEditKeywordPipeline = self.editKeywordPipeline();
                    newEditKeywordPipeline.keywords = keywordsData;
                    self.editKeywordPipeline([]);
                    self.editKeywordPipeline(newEditKeywordPipeline);
                    self.editKeywordPipeline.valueHasMutated();
                    $(self.selectors.editPipeline).sortable("cancel");

                    self.afterDragRefresh();
                },
                sort: function (event, ui) {
                    /** scroll to top if the item is near the top of the container */
                    var parentOffset = $parentContainer.offset();
                    var parentHeight = $parentContainer.outerHeight();
                    var mouseY = event.pageY;
                
                    var scrollTop = $parentContainer.scrollTop();
                    var threshold = 40; /* px from top/bottom where scrolling should kick in */
                    var scrollSpeed = 20; /* px per event */
                
                    /* scroll up */
                    if (mouseY < parentOffset.top + threshold) {
                        $parentContainer.scrollTop(scrollTop - scrollSpeed);
                    }
                    
                    /* scroll down */
                    else if (mouseY > parentOffset.top + parentHeight - threshold) {
                        $parentContainer.scrollTop(scrollTop + scrollSpeed);
                    }
                }
            });
            $(self.selectors.emptyPipeline).sortable({
                tolerance: 'pointer',
                items: 'div',
                cancel: '.wtai-custom-pipeline-empty-initial, .wtai-custom-pipeline-empty-history',
                receive: function (event, ui) {
                    if (!self.editKeywordPipelineVisible() && !keywordAnalysis.editKeywordRankingVisible()) {
                        var text = ui.item.find(".wtai-keyword").text(),
                            newCustom = {
                                "name": "Custom",
                                "autogenerated": false,
                                "keywords": {
                                    "Low": {
                                        "keyword": text
                                    }
                                }
                        };
                        
                        self.editKeywordPipelineVisible(true);
                        self.editKeywordPipeline(newCustom);

                        ui.item.remove();

                        self.afterDragRefresh();
                    }
                }
            });
        },

        isIosSafari: function () {
            var ua = (navigator && navigator.userAgent) ? navigator.userAgent : '';
            var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator && navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
            return isIOS;
        },

        afterDragRefresh: function () {
            
            if (!self.isIosSafari()) {
                return;
            }
            if (self.editKeywordPipeline && self.editKeywordPipeline.valueHasMutated) {
                self.editKeywordPipeline.valueHasMutated();
            }

            try {
                $(self.selectors.editPipeline).sortable('refresh');
            } catch (e) {
            }

            try {
                $('#wtaiKeywordPoolList').sortable('refresh');
            } catch (e) {
            }

            window.requestAnimationFrame(function () {
                window.requestAnimationFrame(function () {
                    var pipelineEl = document.querySelector('#wtaiKeywordEditPipeline');
                    if (pipelineEl) {
                        var previousTransform = pipelineEl.style.transform;
                        pipelineEl.style.transform = 'translateZ(0)';
                        void pipelineEl.offsetHeight;
                        pipelineEl.style.transform = previousTransform;
                    }

                    var poolEl = document.querySelector('#wtaiKeywordPoolList');
                    if (poolEl) {
                        var previousPoolTransform = poolEl.style.transform;
                        poolEl.style.transform = 'translateZ(0)';
                        void poolEl.offsetHeight;
                        poolEl.style.transform = previousPoolTransform;
                    }
                });
            });
        },

        /**
         * @inheritdoc
         */
        openEmptyCustom: function () {
            emptyPipeline.openEmptyCustom(self);
        },

        /**
         * Initialize dropdown dialogs after rendering.
         *
         * @param {number} indexSource
         * @param {Array} pipeline
         * @param {boolean} isCustom
         *
         * @returns {void}
         */
        initDropdownDialogs: function (indexSource, pipeline, isCustom = false) {
            if (pipeline.length === 0) {
                return;
            }

            pipeline.forEach(function (item, index) {
                var keywords = item.keywords;

                if (indexSource !== index) {
                    return;
                }

                if (Object.keys(keywords).length === 0) {
                    return;
                }

                Object.entries(keywords).forEach(function ([key, keyword]) {
                    var prefix = isCustom ? '.wtai-trigger-settings-wrapper.wtai-custom ' : '.wtai-trigger-settings-wrapper.wtai-cluster ';
                    var saveButtonId = prefix + '.wtai-dropdown-btn-action' + item.id + key;
                    var secondaryDropdownId = prefix + '.wtai-actions-content' + item.id + key;
                    
                    $(prefix + '.wtai-dropdown-btn' + item.id + key).dropdown({
                        parent: prefix + '.wtai-dropdown-wrapper' + item.id + key,
                        autoclose: true
                    }).on('click.toggleDropdown', function () {
                        $(self.tsSelectors.errorMessage).html('');
                        $('.wtai-keyword.active-details').removeClass('active-details');
                        if ($(this).hasClass('active')) {
                            $(secondaryDropdownId).hide();
                            $(saveButtonId).removeClass('active');
                            triggerSettings.adjustPositionTriggerSettings(self, $(this));
                            triggerSettings.setActiveTriggerSettingsValue(self, item.id, key);
                        }
                    });
                    
                    $(prefix + '.wtai-dropdown-content' + item.id + key).removeClass('wtai-hide-initially');
                
                    $(saveButtonId).on('click', function () {
                        $(secondaryDropdownId).toggle();
                        $(saveButtonId).toggleClass('active');
                    });
                
                    $(document).on('click', function (e) {
                        if (!$(e.target).closest(saveButtonId).length && !$(e.target).closest(secondaryDropdownId).length) {
                            $(secondaryDropdownId).hide();
                            $(saveButtonId).removeClass('active');
                        }
                    });
                });
            });
        },

        /**
         * Init arrange dropdown.
         */
        initArrangeDropdown: function () {
            $('#wtaiDropdownArrangeBtn').dropdown({
                parent: '.wtai-dropdown-arrange-container.wtai-arrange-top',
                autoclose: true
            });
            $('#wtaiDropdownArrangeBtnBottom').dropdown({
                parent: '.wtai-dropdown-arrange-container.wtai-arrange-bottom',
                autoclose: true
            });
        },

        /**
         * Manually close arrange dropdown.
         */
        closeArrangeDropdown: function () {
            $('#wtaiDropdownArrangeBtn').removeClass('active');
            $('#wtaiDropdownArrangeBtnBottom').removeClass('active');
            $('.wtai-dropdown-arrange-container').removeClass('active');
        },

        /**
         * Init spinner.
         */
        initSpinner: function () {
            $(self.tsSelectors.allInputNumber).spinner({
                numberFormat: 'n',
                min: self.minTriggerActionNPosition,
                max: self.maxTriggerActionNPosition
            });
            $(self.tsSelectors.allNPosition).on('input', function () {
                if ($(this).val() > self.maxTriggerActionNPosition) {
                    $(this).val(self.maxTriggerActionNPosition);
                }
                if ($(this).val() < self.minTriggerActionNPosition) {
                    $(this).val(self.minTriggerActionNPosition);
                }
            });
            $(self.tsSelectors.allNDays).on('input', function () {
                if ($(this).val() > self.maxTriggerActionNDays) {
                    $(this).val(self.maxTriggerActionNDays);
                }
                if ($(this).val() < self.minTriggerActionNDays) {
                    $(this).val(self.minTriggerActionNDays);
                }
            });
        },

        /**
         *
         * @param {*} data
         * @param {*} event
         */
        initCloseDropdown: function (data, event) {
            $('.wtai-keyword-analysis-content').click(function (event) {
                if (!$(event.target).closest('.wtai-keyword.active-details').length) {
                    $('.wtai-keyword.active-details').removeClass('active-details');
                }

                if (!$(event.target).closest('.wtai-has-popup .wtai-serp-popup.active').length) {
                    $('.wtai-has-popup .wtai-serp-popup.active').removeClass('active');
                }
            });
        },

        /**
         * Get optimization.
         *
         * @param {boolean} showLoader
         * @returns {void}
         */
        getOptimization: function () {
            $.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) {
                    keywordAnalysis.optimizationData(response.api_response);
                    keywordAnalysis.snapshotData(response.api_response.snapshots || {});
                    console.log('edit keyword-pipelines getOptimization', response.api_response);
                }
            });
        },

        /**
         * @inheritdoc
         */
        seeMoreData: function (data, event) {
            pipelineKeyword.seeMoreData(self, data, event);
        },

        /**
         * Close more details
         *
         * @param {*} data
         * @param {*} event
         */
        closeMoreData: function (data, event) {
            $(event.currentTarget).removeClass('active-details');
        },

        /**
         * View SERP
         *
         * @param {*} data
         * @param {*} event
         */
        viewSERP: function (data, event) {
            self.adjustPositionSerp($(event.currentTarget));
            $(event.currentTarget).closest('.wtai-keyword-data').find('.wtai-serp-popup').addClass('active');
        },

        /**
         * Close SERP
         *
         * @param {*} data
         * @param {*} event
         */
        closeSERP: function (data, event) {
            $(event.currentTarget).closest('.wtai-keyword-data').find('.wtai-serp-popup').removeClass('active');
        },

        /**
         * Get domain
         *
         * @param {String} domain
         * @returns {String}
         */
        getDomain: function (domain) {
            if (!domain.startsWith('http://') && !domain.startsWith('https://')) {
                domain = 'https://' + domain;
            }
            return domain;
        },
        
        /**
         * Check if domain is current site.
         *
         * @param {string} domain
         *
         * @returns {boolean}
         */
        isMySite: function (domain) {
            return domain === window.location.hostname;
        },

        /**
         * @inheritdoc
         */
        getSerpDateText: function (difficulty, keywords) {
            return base.getSerpDateText(self, difficulty, keywords);
        },

        /**
         * After render clustered
         *
         * @param {number} index
         * @param {boolean} isFromCustom
         *
         * @returns {void}
         */
        afterRenderPipeline: function (index, isFromCustom = false) {
            setTimeout(function () {
                if (isFromCustom) {
                    self.initDropdownDialogs(index, self.customPipelines(), true);
                } else {
                    self.initDropdownDialogs(index, self.pipelines());
                }
                self.initSpinner();
                self.initCloseDropdown();
            }, 1000);
        },

        /**
         * After render common
         */
        afterRenderCommon: function () {
            self.initSortable();
            self.initSpinner();
            self.initArrangeDropdown();
            self.initCloseDropdown();
            self.initKeywordEditBlurEvent();
        },

        /**
         * @inheritdoc
         */
        editPipeline: function (id) {
            return pipeline.editPipeline(self, id);
        },

        /**
         * Close edit keyword pipeline
         */
        closeEditPipeline: function () {
            /** revert edit back to its position before update */
            var editPipelineContents = $(self.selectors.editPipelineContainer);
            if (!editPipelineContents.parent().is(self.selectors.editPipelineWrapper)) {
                editPipelineContents.appendTo($(self.selectors.editPipelineWrapper));
            }
            self.editKeywordPipeline([]);
            self.editKeywordPipelineVisible(false);
            errorMessagesModel.messages([]);
            self.inputActive(false);
        },

        /**
         * @inheritdoc
         */
        isPipelineActiveEdit: function (id) {
            return pipeline.isPipelineActiveEdit(self, id);
        },

        /**
         * @inheritdoc
         */
        saveEditPipeline: function () {
            return editPipeline.saveEditPipeline(self);
        },

        /**
         * Edit keyword
         *
         * @param {*} data
         * @param {*} event
         */
        editKeywordItem: function (data, event, difficulty) {
            base.editkeywordItemInitialProcess(
                self,
                $(event.currentTarget).closest('.wtai-edit-keyword-item'),
                difficulty
            );
        },

        /**
         * @inheritdoc
         */
        addKeywordItemManually: function (data, event, difficulty) {
            return editPipeline.addKeywordItemManually(self, data, event, difficulty);
        },

        /**
         * @inheritdoc
         */
        closeInputKeyword: function (data, event, difficulty) {
            return editPipeline.closeInputKeyword(self, data, event, difficulty);
        },

        /**
         * Remove keyword
         *
         * @param {string} difficulty
         */
        removeKeyword: function (difficulty) {
            var editKeywordPipeline = self.editKeywordPipeline();
            let keywordToDelete = editKeywordPipeline.keywords[difficulty];
            let keywordPool = keywordAnalysis.optimizationData().keywords;
            if (!keywordPool.some(keyword => keyword.keyword === keywordToDelete.keyword)) {
                if (keywordToDelete.keyword !== '' && keywordToDelete.manual !== true) {
                    keywordPool.push(keywordToDelete);
                }
            }
            delete editKeywordPipeline.keywords[difficulty]
            self.editKeywordPipeline([]);
            self.editKeywordPipeline(editKeywordPipeline);
        },

        /**
         * @inheritdoc
         */
        deleteKeywordPipeline: function (pipelineId) {
            return pipeline.deleteKeywordPipeline(self, pipelineId);
        },

        /**
         * @inheritdoc
         */
        isPipelineLocked: function (id) {
            return pipeline.isPipelineLocked(id);
        },

        /**
         * Toggle lock cluster based pipeline
         *
         * @param {number} id
         *
         * @returns {void}
         */
        toggleLockPipeline: function (id, currentValue) {
            if (currentValue) {
                pipeline.unlockPipelineRequest(self, id);
            } else {
                pipeline.lockPipelineRequest(self, id);
            }
        },

        /**
         * @inheritdoc
         */
        restorePreviousPipeline: function () {
            return emptyPipeline.restorePreviousPipelineRequest(self);
        },
        
        /**
         * @inheritdoc
         */
        getDifficulty: function (difficulty, getLabel = false) {
            return editPipeline.getDifficulty(self, difficulty, getLabel);
        },

        /**
         * Check if difficulty is skipped
         *
         * @param {string} difficulty
         * @param {Object} keywords
         *
         * @returns {boolean}
         */
        isSkipped: function (difficulty, keywords) {
            return keywords[difficulty] === undefined;
        },

        /**
         * @inheritdoc
         */
        getCurrentState: function (apiState) {
            return pipelineKeyword.getCurrentState(apiState);
        },

        /**
         * @inheritdoc
         */
        isPreviousNone: function (difficulty, id) {
            return pipelineKeyword.isPreviousNone(self, difficulty, id);
        },

        /**
         * @inheritdoc
         */
        isPreviousSkipped: function (difficulty, keywords) {
            return pipelineKeyword.isPreviousSkipped(self, difficulty, keywords);
        },

        /**
         * @inheritdoc
         */
        areAllKeywordsAboveSkipped: function (difficulty, keywords) {
            return pipelineKeyword.areAllKeywordsAboveSkipped(self, difficulty, keywords);
        },

        /**
         * @inheritdoc
         */
        countSkippedKeywords: function (difficulty, keywords) {
            return pipelineKeyword.countSkippedKeywords(self, difficulty, keywords);
        },
        
        /**
         * @inheritdoc
         */
        isPrevious: function (difficulty, currentLevel) {
            return pipelineKeyword.isPrevious(difficulty, currentLevel);
        },
        
        /**
         * @inheritdoc
         */
        isCurrentAndUneditable: function (difficulty, currentLevel, pipelineId) {
            return editPipeline.isCurrentAndUneditable(self, difficulty, currentLevel, pipelineId);
        },

        /**
         * Check if serp is available
         *
         * @param {string} difficulty
         * @param {Array} keywords
         * @param {string} property
         *
         * @returns {string}
         */
        hasSerp: function (difficulty, keywords) {
            if (keywords[difficulty] === undefined) {
                return '';
            }

            return keywords[difficulty].serpItems.length > 0;
        },

        /**
         * Get keyword
         *
         * @param {string} difficulty
         * @param {Array} keywords
         * @param {string} property
         *
         * @returns {string}
         */
        getKeywordData: function (difficulty, keywords, property) {
            if (keywords[difficulty] === undefined) {
                return '';
            }
            if (property === 'positionDelta' && keywords[difficulty].positionDelta > 0) {
                return '+' + keywords[difficulty].positionDelta;
            }
            if (property === 'searchVolume' && !keywords[difficulty].searchVolume) {
                return 0;
            }

            return keywords[difficulty][property];
        },

        /**
         * Is currently optimizing
         *
         * @param {string} difficulty
         * @param {string} currentLevel
         *
         * @returns {boolean}
         *
         */
        isCurrent: function (difficulty, currentLevel) {
            return difficulty === currentLevel;
        },

        /**
         * @inheritdoc
         */
        isNext: function (difficulty, currentLevel, keywords = []) {
            return pipelineKeyword.isNext(self, difficulty, currentLevel, keywords);
        },

        /**
         * Get keyword to edit
         *
         * @param {string} difficulty
         */
        getKeywordToEdit: function (difficulty) {
            if (self.editKeywordPipeline().keywords === undefined) {
                return '';
            }
            if (self.editKeywordPipeline().keywords[difficulty] === undefined) {
                return '';
            }
            return self.editKeywordPipeline().keywords[difficulty].keyword ?? '';
        },

        /**
         * Get keyword input active
         *
         * @param {string} difficulty
         *
         * @returns {string}
         */
        getKeywordInputActive: function (difficulty) {
            var activeInputKeyword = self.newActiveKeywordsInput();
            return activeInputKeyword[difficulty] ?? self.getKeywordToEdit(difficulty);
        },

        /**
         *
         * Get pipeline name
         *
         * @param {string} name
         * @param {string} isAutogenerated
         */
        getPipelineName: function (name, isAutogenerated) {
            return isAutogenerated ? name : $t('Custom');
        },

        /**
         * @inheritdoc
         */
        updateKeyword: function (data, event, difficulty) {
            return editPipeline.updateKeyword(self, data, event, difficulty);
        },

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

        /**
         * @inheritdoc
         */
        updateKeywordOnBlur: function (data, event, difficulty) {
            return base.updateKeywordOnBlur(self, data, event, difficulty);
        },

        /**
         * Prevent blur
         */
        preventBlur: function () {
            keywordPipelines.preventInputBlur(true);
        },

        /**
         * @inheritdoc
         */
        arrangePipeline: function (arrangeBy, excludeCurrent = false) {
            return editPipeline.arrangePipeline(self, arrangeBy, excludeCurrent);
        },

        /**
         * @inheritdoc
         */
        deletePipelineRequest: function (pipelineId, fromSaveEditPipeline = false) {
            return pipeline.deletePipelineRequest(self, pipelineId, fromSaveEditPipeline);
        },

        /**
         * @inheritdoc
         */
        getTriggerDropdownLabel: function (pipelineId, difficulty) {
            return triggerSettings.getTriggerDropdownLabel(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        isTriggerActionSelected: function (pipelineId, option, difficulty) {
            return triggerSettings.isTriggerActionSelected(self, pipelineId, option, difficulty);
        },

        /**
         * @inheritdoc
         */
        isAutomaticTextOptimizationSelected: function (pipelineId, action, difficulty) {
            return triggerSettings.isAutomaticTextOptimizationSelected(self, pipelineId, action, difficulty);
        },

        /**
         * @inheritdoc
         */
        isAllTextFieldsSelected: function (pipelineId, difficulty) {
            return triggerSettings.isAllTextFieldsSelected(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        getTriggerActionNPosition: function (pipelineId, difficulty) {
            return triggerSettings.getTriggerActionNPosition(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        getTriggerActionNDays: function (pipelineId, difficulty) {
            return triggerSettings.getTriggerActionNDays(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        isTextFieldSelected: function (pipelineId, field, difficulty) {
            return triggerSettings.isTextFieldSelected(self, pipelineId, field, difficulty);
        },

        /**
         * @inheritdoc
         */
        applyTriggerAction: function (pipelineId, difficulty) {
            return triggerSettings.applyTriggerAction(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        applyTriggerActionToPipeline: function (pipelineId, difficulty) {
            return triggerSettings.applyTriggerActionToPipeline(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        applyTriggerActionToAll: function (
            pipelineId,
            difficulty
        ) {
            return triggerSettings.applyTriggerActionToAll(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        applyTriggerActionToSameDifficulty: function (
            pipelineId,
            difficulty
        ) {
            return triggerSettings.applyTriggerActionToSameDifficulty(self, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        selectAllFields: function (data, event, pipelineId, difficulty) {
            return triggerSettings.selectAllFields(self, data, event, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        selectTriggerAction: function () {
            return triggerSettings.selectTriggerAction(self);
        },

        /**
         * Select automatic text optimization
         *
         * @returns {boolean}
         */
        selectAutomaticTextOptimization: function () {
            var countSelected = $(self.tsSelectors.checkedAction).length;
            self.tsActiveAutoOptimize($(self.tsSelectors.checkedAction).val());
            return countSelected > 0;
        },

        /**
         * @inheritdoc
         */
        selectTextField: function (data, event, pipelineId, difficulty) {
            return triggerSettings.selectTextField(self, data, event, pipelineId, difficulty);
        },

        /**
         * @inheritdoc
         */
        applyMultipleTriggerActionRequest: function (
            pipelineId,
            difficulties,
            option,
            value,
            action,
            textTypes,
            includeLocked = false
        ) {
            return triggerSettings.applyMultipleTriggerActionRequest(
                self,
                pipelineId,
                difficulties,
                option,
                value,
                action,
                textTypes,
                includeLocked
            );
        },

        /**
         * Manually close dropdown
         *
         * @param {*} elem
         */
        closeDropdown: function (elem) {
            elem.removeClass('active')
                .parent()
                    .removeClass('active');
        },

        /**
         * @inheritdoc
         */
        adjustPositionSerp: function (activeButton) {
            return pipelineKeyword.adjustPositionSerp(self, activeButton);
        },

        /**
         * @inheritdoc
         */
        ensureNumerical: function (data, event) {
            return textfieldsUtils.ensureNumerical(event.key);
        },

        /**
         * @inheritdoc
         */
        countNotAvailableKeywords: function (originalPipeline) {
            return editPipeline.countNotAvailableKeywords(self, originalPipeline);
        },

        /**
         * Is primary keyword
         *
         * @param {string} keyword
         *
         * @returns {boolean}
         */
        isPrimaryKeyword: function (keyword) {
            return self.getPrimaryKeyword() === keyword;
        },

        /**
         * Get keyword title
         *
         * @param {string} difficulty
         * @param {Array} keywords
         *
         * @returns {string}
         */
        getKeywordTitle: function (difficulty, keywords) {
            var isPrimary = self.getKeywordData(difficulty, keywords, 'keyword') === self.getPrimaryKeyword();
            var isRanking = self.getKeywordData(difficulty, keywords, 'position') > 0;
            
            if (isPrimary && isRanking) {
                return $t('Primary keyword and ranking in the SERP');
            }
            if (isPrimary) {
                return $t('Primary keyword');
            }
            if (isRanking) {
                return $t('Ranking in the SERP');
            }
            return '';
        }
    });
});