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

define([
    'jquery',
    'ko',
    'uiComponent',
    'WriteTextAI_WriteTextAI/js/model/signalr',
    'WriteTextAI_WriteTextAI/js/model/grid/notifications',
    'WriteTextAI_WriteTextAI/js/model/grid/transfer',
    'WriteTextAI_WriteTextAI/js/model/edit/keywords/keyword-analysis',
    'WriteTextAI_WriteTextAI/js/model/grid/reference-products',
    'WriteTextAI_WriteTextAI/js/utils/signalr',
    'mage/translate'
], function (
    $,
    ko,
    Component,
    signalRModel,
    notifications,
    transfer,
    keywordAnalysis,
    referenceProducts,
    signalrUtils,
    $t
) {
    'use strict';

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

    return Component.extend({
        defaults: {
            gridName: 'wtai_products_grid_listing.wtai_products_grid_listing_data_source',
            statusCompleted: 'Completed',
            statusTimedout: 'TimedOut',
            statusCancelling: 'Cancelling',
            statusCancelled: 'Cancelled',
            statusRunning: 'Running',
            statusPending: 'Pending',
            statusPreparing: 'Preparing',
            retryLabel: $t('Try Again'),
            opened: false,
            statuses: [],
            user: {},
            tempId: notifications.tempId,
            transferTempId: notifications.transferTempId,
            koTempId: notifications.koTempId,
            cancelBulkTransfer: false,
            isCronRunning: false
        },

        isOpenedChanged: false,

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

            self = this;

            /** 1. Update statuses model */
            notifications.statuses(this.statuses());
            transfer.isCronRunning(this.isCronRunning());

            self.statuses.subscribe(function (statuses) {
                if (statuses.length === 0) {
                    notifications.opened(false);
                }
            });

            /** 2. Listen to statuses model */
            notifications.statuses.subscribe(function (statuses) {
                /** Apply statuses to the view model */
                this.statuses(statuses);
                
                /** Auto-dismiss cancelled statuses after they're added to the view model */
                var cancelledStatuses = this.statuses().filter(function (status) {
                    return status.status === this.statusCancelled && !this.isCancelling(status);
                }, this);
                
                /** Remove cancelled statuses if any found */
                if (cancelledStatuses.length) {
                    cancelledStatuses.forEach(function (status) {
                        this.dismissMessage(status);
                    }, this);
                }
            }, this);

            notifications.opened.subscribe(function (opened) {
                this.isOpenedChanged = true;
                this.opened(opened);
                this.isOpenedChanged = false;
            }, this);

            transfer.cancelBulkTransfer.subscribe(function (cancelBulkTransfer) {
                this.cancelBulkTransfer(cancelBulkTransfer);
            }, this);

            this.opened.subscribe(function (opened) {
                if (!this.isOpenedChanged) {
                    notifications.opened(opened);
                }
            }, this);

            notifications.triggerDismissAll.subscribe(function (triggerDismissAll) {
                if (triggerDismissAll) {
                    this.dismissMessages();
                    notifications.triggerDismissAll(false);
                }
            }, this);

            /** 3. Add transfer statuses to model */
            this.initStatuses();
        },

        /** @inheritdoc */
        initObservable: function () {
            this._super().observe(['opened', 'statuses', 'user', 'cancelBulkTransfer', 'isCronRunning']);

            this.checkingIsSingleRequest = ko.computed(function () {
                return signalRModel.checkingIsSingleRequest();
            }, this);

            this.allDone = ko.computed(
                () =>
                this.statuses().every(status => {
                    if (this.isCancelling(status)) {
                        return false;
                    }
                    return [this.statusCompleted, this.statusCancelled].includes(status.status);
                })
            );

            this.showDismissAll = ko.computed(function () {
                return this.statuses().length > 1 && this.statuses().some((status) => {
                    return status.status === this.statusCompleted;
                }, this);
            }, this);

            this.timedOut = ko.computed(function () {
                return this.statuses().some((status) => {
                    return status.status === this.statusTimedout;
                }, this);
            }, this);

            this.allProductsFailed = ko.computed(function () {
                return this.statuses().length > 0 && this.statuses().every((status) => {
                    var total = Number(status.total || 0);
                    var failed = Number(status.failed || 0);
                    var skippedCount = Array.isArray(status.skippedIds) ? status.skippedIds.length : 0;

                    return (failed === total && failed > 0) || (total > 0 && skippedCount === total);
                }, this);
            }, this);

            this.showGenerateComment = ko.computed(function () {
                if (this.allProductsFailed()) {
                    return false;
                }

                var hasOngoing = this.statuses().some((status) => {
                    return [
                        this.statusPending,
                        this.statusRunning,
                        this.statusPreparing,
                        this.statusCancelled,
                        this.statusTimedout
                    ].includes(status.status);
                }, this);
                /** return false if at least 1 failed status */
                if (!hasOngoing) {
                    return false;
                }
                return this.statuses().length > 0 && this.statuses().every((status) => {
                    return [undefined, 0, 3].includes(status.subType);
                }, this);
            }, this);

            this.showKOComment = ko.computed(function () {
                if (this.allProductsFailed()) {
                    return false;
                }

                var hasOngoing = this.statuses().some((status) => {
                    return [
                        this.statusPending,
                        this.statusRunning,
                        this.statusPreparing,
                        this.statusCancelled,
                        this.statusTimedout
                    ].includes(status.status);
                }, this);
                /** return false if at least 1 failed status */
                if (!hasOngoing) {
                    return false;
                }
                return this.statuses().length > 0 && this.statuses().some((status) => {
                    return [2, 1].includes(status.subType);
                }, this);
            }, this);

            this.isBulkKeywordAnalysis = ko.computed(function () {
                return this.statuses().some((status) => {
                    return status.subType === 2;
                }, this);
            }, this);

            this.showTransferPendingComment = ko.computed(function () {
                if (this.allProductsFailed()) {
                    return false;
                }

                return this.statuses().length > 0 && this.statuses().some((status) => {
                    return status.transfer === true && status.status === 'Pending';
                }, this);
            }, this);

            this.showManualTransferRunningComment = ko.computed(function () {
                if (this.allProductsFailed()) {
                    return false;
                }

                var isTransferRunning = this.statuses().length > 0 && this.statuses().some((status) => {
                    return status.transfer === true && status.status === 'Running';
                }, this);

                if (isTransferRunning && (this.isCronRunning() === false)) {
                    return true;
                }
                return false;

            }, this);

            this.showTabOpenComment = ko.computed(function () {
                return notifications.currentBulkRequestId() === notifications.transferTempId;
            }, this);

            return this;
        },

        /**
         * Initialize statuses.
         */
        initStatuses: function () {
            var transferStatuses = this.transferStatuses;

            for (var i = 0; i < transferStatuses.length; i++) {
                let queueIds = transferStatuses[i].queue_ids ?? [];
                let completedIds = transferStatuses[i].completed_ids ?? [];

                notifications.updateTransferStatus(
                    [...queueIds, ...completedIds],
                    transferStatuses[i].user,
                    queueIds,
                    completedIds,
                    transferStatuses[i].status,
                    transferStatuses[i]
                );
            }
        },

        /**
         * Check if the status is cancelling.
         *
         * @param {Object} status
         * @return {Boolean}
         */
        isCancelling: function (status) {
            return signalrUtils.isCancelling(status);
        },

        /**
         * Get the message.
         *
         * @param {Object} status
         * @return {String}
         */
        getMessage: function (status) {
            var isProductOptimizing = keywordAnalysis.statuses().find(function (data) {
                return Number(data.storeId) === Number(referenceProducts.storeId()) &&
                    status?.queuedIds?.includes(data.recordId) &&
                    data.status === 'Running';
            });

            if (isProductOptimizing) {
                return $t('Keyword analysis currently in progress');
            }

            var isTransfer = status && status.transfer === true;
            var total = Number(status?.total ?? 0);
            var completedIdsCount = status?.completedIds?.length ?? 0;
            var skippedCount = status?.skippedIds?.length ?? 0;
            var failedCount = Number(status?.failed ?? 0);

            if (isTransfer && total > 0 && skippedCount === total && status.status === 'Completed') {
                return $t('Transfer failed because there are no generated texts yet for the products selected.') + '</br> ' +
                    $t('Generate text first before transferring.');
            }

            return status.message || status.status;
        },

        /**
         * Get the failed count.
         *
         * @param {Object} status
         * @return {String}
         */
        getFailedCount: function (status) {
            var failedCount = status.failed;
            
            if (failedCount > 0) {
                return $t('%s failed').replace('%s', failedCount).toLowerCase();
            }

            return "";
        },
        /**
         * Get the skipped count.
         *
         * @param {Object} status
         * @return {String}
         */
        getSkippedCount: function (status) {
            var skippedCount = status.skippedIds?.length ?? 0;
            var failedCount = status.failed || 0;
            
            var processStatus = status.status;

            if (processStatus === 'Running' || processStatus === 'Pending') {
                return "";
            }
            
            if (skippedCount > 0) {
                if (failedCount > 0) {
                    return $t('%s skipped, and ').replace('%s', skippedCount).toLowerCase();
                } else {
                    return $t('%s skipped').replace('%s', skippedCount).toLowerCase();
                }
            }

            return "";
        },

        /**
         * getSummaryMessage
         *
         * @param {Object} status
         * @return {String}
         */
        getSummaryMessage: function (status) {
            var processStatus = status.status,
                totalCount = status.total,
                completedCount = status.completed,
                completedIdsCount = status.completedIds?.length ?? 0,
                failedCount = status.failed;

            var skippedCount = status?.skippedIds?.length ?? 0;

            if (failedCount === totalCount) {
                return "";
            }

            /** Running or Pending */
            if (processStatus === 'Running' || processStatus === 'Pending') {
                if (completedIdsCount > 0) {
                    var processedCount = completedIdsCount;
                } else {
                    var processedCount = completedCount;
                }

                var processedMsg = "";
                processedCount = Math.max(processedCount - failedCount, 0);
                if (failedCount > 0) {
                    processedMsg = $t('%s/%s processed and ')
                    .replace('%s', processedCount)
                    .replace('%s', totalCount);
                } else {
                    processedMsg = $t('%s/%s processed')
                    .replace('%s', processedCount)
                    .replace('%s', totalCount);
                }

                return processedMsg;
            }

            /** Done (Completed/Failed/Other) */
            if (completedIdsCount > 0) {
                let adjustedSuccess = Math.max(completedCount - skippedCount, 0);
      
                if (adjustedSuccess === 0) {
                    return "";
                } else if (failedCount > 0 && skippedCount > 0) {
                    return $t('%s successful,').replace('%s', adjustedSuccess);
                } else if (skippedCount > 0) {
                    return $t('%s successful and').replace('%s', adjustedSuccess);
                } else if (failedCount > 0) {
                    return $t('%s successful and').replace('%s', adjustedSuccess);
                } else {
                    return $t('%s successful').replace('%s', adjustedSuccess);
                }
            }
            return "";
        },

        /**
         * Expand the notification bar.
         */
        seeMore: function () {
            self.opened(true);
        },

        /**
         * Collapse the notification bar.
         */
        seeLess: function () {
            self.opened(false);
        },

        /**
         * Check if the transfer is cancelled.
         */
        isCancelledTransfer: function () {
            return self.cancelBulkTransfer();
        },

        /**
         * Dismiss the notification.
         *
         * @param {Object} item
         * @return {void}
         */
        dismissMessage: function (item) {
            var data = {
                request_id: item.id
            };

            if (item.transfer) {
                data = {
                    transfer_user: item.user,
                    type: 'transfer'
                };
            }

            if (item.subType === 0) {
                data = {
                    request_id: item.id,
                    type: 'generate'
                };
            }

            if (item.subType === 1) {
                data = {
                    request_id: item.id,
                    type: 'full_automation'
                };
            }

            if (item.subType === 2) {
                data = {
                    request_id: item.id,
                    type: 'keyword_analysis'
                };
            }

            this.statuses.remove(item);
        },

        /**
         * Dismiss all notifications.
         */
        dismissMessages: function () {
            var self = this;

            this.statuses.remove(function (item) {
                return item.status === self.statusCompleted;
            });
        },

        /**
         * Cancel the generate.
         *
         * @param {Number} id
         * @return {void}
         */
        cancelBulk: function (id) {
            notifications.updateToAttemptingCancelStatus(id);
            $.ajax({
                url: self.cancelUrl,
                type: 'POST',
                data: {
                    id: id
                },
                dataType: 'json',
                showLoader: true,
                success: function (response) {
                    if (!response.success) {
                        console.log(response.message);
                    }
                }
            });
        },

        /**
         * Cancel the transfer.
         *
         * @param {Number} id
         * @return {void}
         */
        cancelTransfer: function (id) {
            if (transfer.cancelRequest()) {
                transfer.cancelRequest().abort();
            }
            var curUser = self.user();
            $.ajax({
                url: self.transferCancelUrl,
                type: 'POST',
                data: {
                    id: id,
                    user: curUser.email
                },
                dataType: 'json',
                showLoader: true,
                success: function (response) {
                    if (!response.success) {
                        console.log(response.message);
                    }
                    transfer.cancelBulkTransfer(true);
                }
            });
        },

        /**
         * Retry the bulk generate.
         *
         * @param {Number} id
         * @return {void}
         */
        retry: function (id) {
            var url = self.retryUrl;

            $.ajax({
                url: url,
                type: 'POST',
                data: {
                    id: id
                },
                dataType: 'json',
                showLoader: true,
                success: function (response) {
                    if (!response.success) {
                        console.log(response.message);
                    }
                }
            });
        }
    });
});
