/*-
 * ~~~~~~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.factory('entaxyResourcesService', ['workspace', 'operationsService', '$q', 'jolokia', '$uibModal',
                            'restService',
        function(workspace, operationsService, $q, jolokia, $uibModal, restService) {

            const resourceMbean = getDomainFolder().findDescendant(child =>
                child.objectName && child.objectName.endsWith('category=resource'));

            return {
                getProviders: function () {
                    return getProviders();
                },
                getProviderMbean: function (protocol) {
                    return getProviderMbean(protocol);
                },
                getResource: function (location, useRawReply) {
                    return getResource(location, useRawReply);
                },
                getResourceMetadata: function (location) {
                    return getResourceMetadata(location);
                },
                getResourcesInfo: function (providerMBeanName, path) {
                    return getResourcesInfo(providerMBeanName, path);
                },
                pasteResource: function (providerMBeanName, fromPath, fullToPath) {
                    return pasteResource(providerMBeanName, fromPath, fullToPath);
                },
                removeResource: function (providerMBeanName, path) {
                    return removeResource(providerMBeanName, path);
                },
                downloadResource: function (providerMBeanName, path) {
                    return downloadResource(providerMBeanName, path);
                },
                saveResource: function (providerMBeanName, path, content) {
                    return saveResource(providerMBeanName, path, content);
                },
                uploadFile: function (file, protocol, path) {
                    return uploadFile(file, protocol, path);
                },
                getPath: function (crumbs) {
                    return getPath(crumbs);
                },
                openResourceNameInputModal: function (item, name, rename, replaceSpaces) {
                    return openResourceNameInputModal(item, name, rename, replaceSpaces);
                },
                addFolder: function (items, clientFolders, crumbs) {
                    return addFolder(items, clientFolders, crumbs);
                },
                createFolder: function (name, crumbs) {
                    return createFolder(name, crumbs);
                },
                getClientFoldersToAdd: function (clientFolders, items, crumbs) {
                    return getClientFoldersToAdd(clientFolders, items, crumbs);
                }
            };

            function getProviders() {
                return executeOperationOnResourceMbean('listProviders', []);
            }

            function getDomainFolder() {
                let entaxyJmxDomain = localStorage['entaxyJmxDomain'] || "ru.entaxy.esb";
                return workspace.tree.get(entaxyJmxDomain);
            }

            function getProviderMbean(protocol) {
                return getDomainFolder().findDescendant(child =>
                    child.objectName && child.objectName.endsWith('provider=' + protocol));
            }

            function getResource(location, useRawReply) {
                return $q(function (resolve) {
                    let promise = executeOperationOnResourceMbean('getResource', [location], useRawReply);

                    if (promise) {
                        promise
                        .then((response) => resolve(response))
                        .catch((error) => {
                            Entaxy.notificationError('An error occurred while loading the resource');
                            Entaxy.log.error(error);
                        });
                    } else {
                        Entaxy.notificationError('Resource service is not found');
                    }
                });
            }

            function getResourceMetadata(location) {
                return executeOperationOnResourceMbean('getResourceMetadata', [location]);
            }

            function executeOperationOnResourceMbean(operationName, properties, useRawReply) {
                let resourceObjectName = resourceMbean ? resourceMbean.objectName : undefined;

                if (resourceObjectName) {
                    return useRawReply ?
                        executeOperationWithRawReply(
                            resourceObjectName,
                            { name: operationName },
                            properties
                        ) :
                        operationsService.executeOperation(
                            resourceObjectName,
                            { name: operationName },
                            properties
                        );
                }
            }

            function executeOperationWithRawReply(mbeanName, operation, argValues) {
                return $q((resolve, reject) => {
                    jolokia.execute(mbeanName, operation.name, ...argValues,
                        {
                            success: (response) => {
                                if (response === null || typeof response === 'string') {
                                    resolve(response);
                                } else {
                                    resolve(angular.toJson(response, true));
                                }
                            },
                            error: (response) => reject(response.stacktrace ? response.stacktrace : response.error)
                        });
                });
            }

            function getResourcesInfo(providerMBeanName, path) {
                return $q(function (resolve) {
                    operationsService.executeOperation(providerMBeanName, { name: 'getResourcesInfo' }, [ path ])
                    .then((result) => {
                        let items = JSON.parse(result);
                        items.forEach(item => {
                            if (item.metadata) {
                                Object.keys(item.metadata).forEach(section => {
                                    item.metadata[section] = JSON.parse(item.metadata[section]);

                                    if (item.metadata[section].error && !item.error) {
                                        let error = item.metadata[section].error;
                                        item.error = error.message && error.message.length > 0 ?
                                            error.message : error.exception;
                                    }
                                });
                            }
                        });
                        resolve(items);
                    })
                    .catch((error) => {
                        Entaxy.log.error(error);
                        Entaxy.notificationError('An error occurred while getting resources.');
                    });
                });
            }

            function pasteResource(providerMBeanName, fromPath, fullToPath) {
                return operationsService
                    .executeOperation(providerMBeanName, { name: 'pasteResource' }, [ fromPath, fullToPath ]);
            }

            function removeResource(providerMBeanName, path) {
                return operationsService.executeOperation(providerMBeanName, { name: 'removeResource' }, [ path ]);
            }

            function downloadResource(providerMBeanName, path) {
                return operationsService.executeOperation(providerMBeanName, { name: 'downloadResource' }, [ path ]);
            }

            function saveResource(providerMBeanName, path, content) {
                return operationsService.executeOperation(providerMBeanName, { name: 'saveResource' }, [ path, content ]);
            }

            function uploadFile(file, protocol, path) {
                if (!file) {
                    return;
                }

                let fd = new FormData();
                fd.append('file', file);
                fd.append('protocol', protocol);
                fd.append('path', path);

                return restService.post('/cxf/file-upload/upload/resource', fd);
            }

            function getPath(crumbs) {
                let path = '';
                if (crumbs && crumbs.length > 0) {
                    path = crumbs.join('/');
                }
                return path;
            }

            function openResourceNameInputModal(item, names, rename, replaceSpaces) {
                let type = item.isFolder ? 'Folder' : 'Resource';
                return $uibModal.open({
                    component: 'entaxySimpleResourceNameInputModal',
                    resolve: {
                        title: () => rename ?
                            'Change ' + type.toLowerCase() + ' name' :
                            'Set ' + type.toLowerCase() + ' name',
                        names: () => names,
                        name: () => item.name,
                        type: () => type,
                        replaceSpaces: () => replaceSpaces
                    },
                    size: 'sm-custom',
                    backdrop: 'static',
                    windowTopClass: 'modal-top-margin-center-override'
                }).result;
            }

            function addFolder(items, clientFolders, crumbs) {

                openResourceNameInputModal({ isFolder: true }, items.map((item) => item.name), false, false)
                .then(name => {

                    let newFolder = createFolder(name, crumbs);

                    items.push(newFolder);
                    items = items.sort(Entaxy.compareBy('name')).sort((a, b) => b.isFolder - a.isFolder);
                    clientFolders.push(newFolder);
                });
            }

            function createFolder(name, crumbs) {
                return {
                    name: name,
                    isFolder: true,
                    crumbs: Entaxy.deepCopy(crumbs)
                };
            }

            function getClientFoldersToAdd(clientFolders, items, crumbs) {
                let foldersToAdd = [];

                if (clientFolders.length > 0) {

                    clientFolders = clientFolders.filter((folder) => {
                        let isSaved = true;
                        if (folder.crumbs.length == crumbs.length && (folder.crumbs.length == 0 ||
                            (folder.crumbs.length > 0 && folder.crumbs[folder.crumbs.length - 1] ===
                                crumbs[crumbs.length - 1]))) {

                            items.forEach((item) => {
                                if (item.isFolder && item.name === folder.name) {
                                    isSaved = false;
                                }
                            });

                            if (isSaved) {
                                foldersToAdd.push(folder);
                            }
                        }
                        return isSaved;
                    });
                }

                return foldersToAdd;
            }
        }
    ])
})(Entaxy || (Entaxy = {}));
