/*-
 * ~~~~~~licensing~~~~~~
 * entaxy-management-plugin
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
var Entaxy;
(function (Entaxy) {
    Entaxy._module.component('entaxyRoutesTable', {
        template:
        `
          <pf-toolbar class="entaxy-toolbar" config="$ctrl.toolbarConfig"></pf-toolbar>
          <pf-table-view config="$ctrl.tableConfig"
                          columns="$ctrl.tableColumns"
                          action-buttons="$ctrl.tableActionButtons"
                          page-config="$ctrl.pageConfig"
                          items="$ctrl.viewedItems"
                          ng-if="$ctrl.ready">
          </pf-table-view>
        `,
        controller: EntaxyRoutesTableController
    })
    .name;

    function EntaxyRoutesTableController(workspace, $location, $scope, $uibModal, entaxyService,
                                         entaxyAttributesCacheService, entaxyPrivateObjectsCacheService) {
        'ngInject';

        let ctrl = this;
        ctrl.workspace = workspace;

        const STATUS = {
            NEW: 'New',
            TO_REMOVAL: 'To Removal'
        };

        let filterValues = Entaxy.getAllBundleStates();
        filterValues.push(STATUS.NEW);
        filterValues.push(STATUS.TO_REMOVAL);

        ctrl.tableConfig = {
            selectionMatchProp: 'displayName',
            showCheckboxes: false
        };

        ctrl.toolbarConfig = {
            filterConfig: {
                fields: [
                    {
                        id: 'displayName',
                        title: 'Name',
                        placeholder: 'Filter by Name...',
                        filterType: 'text'
                    },
                    {
                        id: 'status',
                        title: 'Status',
                        placeholder: 'Filter by Status...',
                        filterType: 'select',
                        filterValues: filterValues
                    }
                ],
                appliedFilters: [],
                onFilterChange: filterChange
            },
            isTableView: true
        };

        ctrl.tableColumns = [
            { header: 'Name', itemField: 'displayName' },
            { header: 'Status', itemField: 'status' }
        ];

        ctrl.pageConfig = Entaxy.getStandardPageConfig();

        function filterChange(filters) {
            ctrl.viewedItems = Entaxy.applyFilters(ctrl.items, filters, matchesFilter);
            ctrl.toolbarConfig.filterConfig.resultsCount = ctrl.viewedItems.length;
        }

        function matchesFilter(item, filter) {
            let match = true;
            if (filter.id === 'displayName') {
                match = item.displayName.toLowerCase().match(filter.value.toLowerCase()) !== null;
            } else if (filter.id === 'status') {
                match = item.status.match(filter.value) !== null;
            }
            return match;
        }

        ctrl.items = [];
        ctrl.viewedItems = [];

        ctrl.$onInit = function() {

            ctrl.runtimeType = Entaxy.RUNTIME_TYPE.ROUTE;

            populateTable();

            ctrl.itemType = Entaxy.getItemTypeFromRuntimeType(ctrl.runtimeType);

            populateActionButtons();
        }

        function populateActionButtons() {
            let selectedMbean = workspace.getSelectedMBean();
            let ownerMbean = selectedMbean.parent;
            entaxyService.readExtendedData(ownerMbean.objectName)
            .then(result => {
                let extendedData = JSON.parse(result);

                if (!extendedData.applications) {
                    let primaryActions = [ { name: 'Add ' + ctrl.itemType, actionFn: () => ctrl.showModal() } ];

                    ctrl.toolbarConfig.actionsConfig = {
                        primaryActions: primaryActions
                    };

                    ctrl.tableActionButtons = [
                        { name: 'Remove', title: 'Remove ' + ctrl.itemType, actionFn: removeItem },
                        { name: 'Restore', title: 'Restore ' + ctrl.itemType, actionFn: restoreItem }
                    ];
                }

                ctrl.ready = true;
            });
        }

        function populateTable() {
            let selectedMBean = workspace.getSelectedMBean();
            if (selectedMBean && selectedMBean.isFolder) {
                let items = [];
                let children = selectedMBean.children;
                if (children && children.length > 0) {
                    let mbeans = [];
                    children.forEach(child => {
                        if (child.objectName) {
                            let attributes = entaxyAttributesCacheService.getAttributes(child.objectName);
                            if (attributes.RuntimeType === ctrl.runtimeType) {
                                mbeans.push({ mbean: child, attributes: attributes });
                            }
                        }
                    });
                    items = createItemsFromMbeans(mbeans);
                }

                if (entaxyPrivateObjectsCacheService.hasAddedChildren(selectedMBean.objectName)) {
                    items = items.concat(createItemsFromAddedObjectsInfo(selectedMBean.objectName));
                }

                ctrl.items = items;
                filterChange(ctrl.toolbarConfig.filterConfig.appliedFilters);
            }
        }

        function createItemsFromMbeans(mbeans) {
            let items = [];
            mbeans.forEach((mbean) => {
                let displayName = mbean.attributes.DisplayName &&
                mbean.attributes.DisplayName.trim().length > 0 ?
                    mbean.attributes.DisplayName : mbean.attributes.Name;
                let changedObjectInfo = entaxyPrivateObjectsCacheService
                    .getChangedObjectInfo(mbean.attributes.ObjectFullId);
                items.push({
                    id: mbean.attributes.Name,
                    routeId: mbean.attributes.RouteId,
                    displayName: displayName,
                    status: changedObjectInfo && changedObjectInfo.toRemoval ?
                        mbean.attributes.BundleState + ' [' + STATUS.TO_REMOVAL + ']' :
                        mbean.attributes.BundleState,
                    mbeanName: mbean.mbean.objectName,
                    objectFullId: mbean.attributes.ObjectFullId,
                    toRemoval: changedObjectInfo && changedObjectInfo.toRemoval
                });
            });
            return items;
        }

        function createItemsFromAddedObjectsInfo(selectedMBeanMame) {
            let items = [];
            entaxyPrivateObjectsCacheService.getAddedObjectsInfo(selectedMBeanMame).forEach(addedObject => {
                items.push({
                    id: addedObject.ui.id,
                    routeId: addedObject.properties.routeId,
                    displayName: addedObject.properties.displayName ?
                        addedObject.properties.displayName : addedObject.ui.id,
                    status: addedObject.toRemoval ? STATUS.NEW + ' [' + STATUS.TO_REMOVAL + ']' : STATUS.NEW,
                    added: true,
                    toRemoval: addedObject.toRemoval
                });
            });
            return items;
        }

        ctrl.showModal = function() {

            let selectedMbeanName = workspace.getSelectedMBeanName();
            let attributes = entaxyAttributesCacheService.getAttributes(selectedMbeanName);
            let ownerRuntimeType = attributes.ObjectType;
            let ownerFactoryId = attributes.FactoryId;

            let factoryMbean = entaxyService.getFolderByTitle(ownerRuntimeType).get(ownerFactoryId);

            entaxyService.getFields(factoryMbean.objectName).then(result => {
                let fields = JSON.parse(result);
                let routesField = fields.find(field => field.name === 'routes');
                let factoryFilter = routesField && routesField.itemFactory ?
                    routesField.itemFactory.filter : undefined;

                entaxyService.getFactoriesByFilterSearch(factoryFilter, true).then(factories => {

                    let typeInfo = routesField['@TYPEINFO'];
                    let validation = typeInfo ? typeInfo.validation : undefined;

                    let checkUniqueness = validation && validation.rules ?
                            validation.rules.checkChildrenUniqueness : undefined;
                    let checkUniquenessFields = {};
                    if (checkUniqueness) {
                        checkUniqueness.fields.forEach(field => {
                            checkUniquenessFields[field] = [];
                            if (ctrl.items) {
                                ctrl.items.forEach(item => {
                                    if (item[field]) {
                                        checkUniquenessFields[field].push(item[field]);
                                    }
                                });
                            }
                        });
                    }

                    let itemTypes = typeInfo && typeInfo.privateObjectTypes ?
                        typeInfo.privateObjectTypes.map(type => type.displayName).join(' or ') : 'Route';

                    $uibModal.open({
                        component: 'entaxyModal',
                        resolve: {
                            mode: () => Entaxy.MODAL_MODES.ADD,
                            itemType: () => itemTypes,
                            factories: () => factories,
                            returnFormFields: () => true,
                            checkUniquenessParentFields: () => checkUniquenessFields
                        },
                        size: 'xl',
                        backdrop: 'static',
                        windowTopClass: 'modal-top-margin-override'
                    })
                    .result.then(formFields => {
                        // object full id of route-container actually has object full id of its owner
                        let ownerFullId = attributes.ObjectFullId;

                        addItem(formFields, routesField, factories, ownerFullId, typeInfo.useAsIdentifier);
                    },
                    reason => {
                        if (reason) {
                            Entaxy.notificationError(reason);
                        }
                    });
                });
            });
        }

        function addItem(formFields, routesField, factories, ownerFullId, identifierFieldName) {
            let args = entaxyService.getArguments(formFields, factories);

            let objectId = args.fields.find(field => field.name === 'objectId').value;
            let argFields = args.fields.filter(field => field.name !== 'objectId');
            let properties = argFields.reduce((obj, cur) => ({ ...obj, [cur.name] : cur.value }), {});
            if (!identifierFieldName) {
                identifierFieldName = 'routeId';
            }
            let routeType = args.factoryId.attributes['typeinfo.routeType'];

            let itemInfo = {
                objectId: objectId,
                factoryId: args.factoryId.name,
                scope: routesField.itemScope,
                type: routesField.itemType,
                properties: properties,
                ui: {
                    id: properties[identifierFieldName],
                    identifierFieldName: identifierFieldName,
                    formFields: formFields,
                    owner: ownerFullId,
                    routeType: routeType
                }
            };

            let selectedMbean = workspace.getSelectedMBean();
            entaxyPrivateObjectsCacheService.addNew(selectedMbean, itemInfo);

            workspace.loadTree();
            changeLocation(itemInfo.ui.id);
        }

        function changeLocation(itemName) {
            let currentLocation = $location.search();
            $location.search('nid', currentLocation.nid + '-' + itemName);
        }

        $scope.$on(Jmx.TreeEvent.Updated, () => {
            populateTable();
        });

        function removeItem(action, item) {

            if (!item.toRemoval) {
                let selectedMbean = workspace.getSelectedMBean();
                if (item.added) {
                    entaxyPrivateObjectsCacheService.setAddedObjectToRemoval(selectedMbean.objectName, item.id);
                } else {
                    entaxyService.readConfiguration(item.mbeanName).then(config => {
                        entaxyPrivateObjectsCacheService.setObjectToRemoval(item.objectFullId, item.mbeanName, config);
                    });
                }

                workspace.loadTree();

                Entaxy.notificationSuccess('Operation Succeeded');
            } else {
                Entaxy.notificationInfo(ctrl.itemType + ' has been already set to removal');
            }
        }

        function restoreItem (action, item) {
            if (item.toRemoval) {
                if (item.added) {
                    let selectedMbeanName = workspace.getSelectedMBeanName();
                    entaxyPrivateObjectsCacheService.restoreAddedObject(selectedMbeanName, item.id);
                } else {
                    entaxyPrivateObjectsCacheService.restoreObject(item.objectFullId);
                }

                workspace.loadTree();

                Entaxy.notificationSuccess('Operation Succeeded');
            } else {
                Entaxy.notificationInfo(ctrl.itemType + ' has been already restored');
            }
        }

        ctrl.dismissAlert = () => ctrl.alert = null;

    }
    EntaxyRoutesTableController.$inject = ['workspace', '$location', '$scope', '$uibModal', 'entaxyService',
        'entaxyAttributesCacheService', 'entaxyPrivateObjectsCacheService'];

})(Entaxy || (Entaxy = {}));
