'use strict';

let projectsMainController = BaseController.extend({
    init: function ($scope, projectsService) {
        this._super($scope);
        common.globalSpinner.show();
        // get project and redirect to project's page
        // if no project found then redirect to create project page
        projectsService.list(1).then(response => {
            let urlToRedirect = '';
            if (response.data.data && Array.isArray(response.data.data) && response.data.data.length > 0) {
                const projectID = response.data.data[0].id;
                urlToRedirect = `/build/project/${projectID}`;
                window.sessionStorage.setItem('projectID', projectID);
            } else  {
                urlToRedirect = '/build/project/create';
            }
            window.location.href = urlToRedirect;
        })
    },

    defineScope: function () {
        this.$scope.instance = "projectsMainController";
    }
});

projectsMainController.$inject = ['$scope', 'projectsService'];

let projectsController = BaseController.extend({
    init: function ($scope, projectsService, $routeParams, sshKeyService, $modal, modulesService, masterfilesVersionService) {
        this._super($scope);
        this.$modal = $modal;
        this.modulesService = modulesService;
        this.masterfilesVersionService = masterfilesVersionService;

        if ($routeParams.hasOwnProperty('id')) {
            $scope.projectId = $routeParams.id;
            projectsService.get($scope.projectId).then(response => {
                const data = response.data;
                $scope.project = {
                    ...data,
                    repositoryUrl: data.repository_url,
                    authenticationType: data.authentication_type,
                    sshKeyId: data.ssh_key_id,
                };
                $scope.loadedProject = angular.copy($scope.project);
                // API returns password value as `set` or `not set`
                $scope.passwordPlaceholder = `Password is ${data.password}`;
                $scope.project.password = null;

                // API returns ssh key value as `set` or `not set`
                $scope.sshKeyPlaceholder = `Ssh private key is ${data.ssh_private_key}`;
                $scope.project.sshPrivateKey = null;
            }).catch(() => {
                notify.success('Project not found.');
            });
        }

        this.projectsService = projectsService;
        this.sshKeyService = sshKeyService;
        $scope.project = {authenticationType: 'password'};
        $scope.repositoryUrlPattern = '^(?:git|ssh|https?|git@(.*)):(\/\/)?(.*)';

        projectsService.list(1).then(response => {
            $scope.projectsExist = response.data.data.length > 0;
        });

        this.modulesService.refreshList().catch(error => notify.error('Error occurred while modules list refreshing. ' . error.data));
    },

    defineScope: function () {
        this.$scope.instance = "projectsController";
        this.$scope.save = this.save.bind(this);
        this.$scope.update = this.update.bind(this);
        this.$scope.delete = this.delete.bind(this);
        this.$scope.generateSshKey = this.generateSshKey.bind(this);
        this.$scope.deleteSshKey = this.deleteSshKey.bind(this);
    },

    defineListeners: function () {
        let self = this;

        const autoFillProjectName = function () {
            // skip project name auto filling if there are no repository or branch or user already changed the name
            if (
                !self.$scope.project.repositoryUrl ||
                !self.$scope.project.branch ||
                self.$scope.projectForm.name.$dirty // skip project name auto filling if the name was set by user
            ) return;
            const repositoryName = self.$scope.project.repositoryUrl ?
                self.$scope.project.repositoryUrl
                    .substring((self.$scope.project.repositoryUrl.lastIndexOf('/') + 1)) // get last url part
                    .replace('.git', '') : // remove .git
                '';
            self.$scope.project.name = `${self.$scope.project.username ? self.$scope.project.username + '/' : ''}${repositoryName}@${self.$scope.project.branch}`;
        };
        self.$scope.$watchCollection('[project.repositoryUrl, project.branch, project.username]', autoFillProjectName);
        self.$scope.$watch('project.ssh_key_id', function (id) {
            if (id != undefined) {
                self.sshKeyService.get(id).then(response => {
                    self.$scope.publicKey = response.data.public_key;
                    self.$scope.sshKeyId = response.data.id;
                })
            }
        });
    },

    save: async function (local = false) {
        this.$scope.saveBtnDisabled = true;

        let masterfiles;
        let promise;
        if (local) {
            try {
                masterfiles = await this.masterfilesVersionService.getVersion();
                promise = this.projectsService.createLocal({ masterfiles });
            } catch (e) {
                notify.error('Masterfiles module version is required.')
                return;
            }
        } else {
            promise = this.projectsService.create(this.$scope.project);
        }

        common.globalSpinner.show();

        promise.then(
            response => {
                this.hideSpinner();
                notify.success('Project successfully created.');
                this.modulesService.refreshList().catch(error => notify.error('Error occurred while modules list refreshing. ' . error.data));
                sessionStorage.setItem(PROJECT_CREATED_KEY, response.data.id);
                setTimeout(() => window.location.href = `/build/project/${response.data.id}`, 1000);
            },
            error => {
                this.hideSpinner();
                displayError(error, this.$scope);
            }
        );
    },
    delete: async function (id) {
        let self = this;
        const projectSynchronizedWithVcs = (await this.projectsService.isProjectSynchronizedWithVcs(id)).isSynchronised;

        this.$modal.open({
            templateUrl: 'removeProject.html',
            backdrop: 'static',
            keyboard: true,
            windowClass: 'delete-project',
            controller: function ($scope, $modalInstance) {
                $scope.name = self.$scope.project.name;
                $scope.projectSynchronizedWithVcs = projectSynchronizedWithVcs;
                $scope.data = {stopDeploying: false};
                $scope.close = function () {
                    $modalInstance.close('cancel');
                };
                $scope.delete = async function () {
                    common.globalSpinner.show();
                    try {
                        if ($scope.data.stopDeploying) {
                            await self.projectsService.stopDeploying();
                        }
                        await self.projectsService.delete(id);

                        common.globalSpinner.hide();
                        $scope.close();
                        notify.success('Project successfully deleted.');
                        setTimeout(() => window.location.href = `/build`, 1000);
                    } catch (error) {
                        common.globalSpinner.hide();
                        displayError(error, this.$scope);
                    }
                };
            }
        });
    },
    generateSshKey: function () {
        let self = this;
        common.globalSpinner.show();
        this.sshKeyService.generate().then((result) => {
            common.globalSpinner.hide();
            this.$scope.project.sshKeyId = result.data.id;
            this.$scope.publicKey = result.data.public_key;

            this.$modal.open({
                templateUrl: 'copySsh.html',
                backdrop: 'static',
                keyboard: true,
                windowClass: 'copy-ssh-dialog',
                controller: function ($scope, $modalInstance) {
                    $scope.publicKey = self.$scope.publicKey;
                    $scope.close = function () {
                        $modalInstance.close('cancel');
                    };
                }
            });

        }, err => {
            notify.error(err.data);
            common.globalSpinner.hide();
        })
    },
    deleteSshKey: function (id) {
        let self = this;
        this.$modal.open({
            templateUrl: 'removeSshKey.html',
            backdrop: 'static',
            keyboard: true,
            windowClass: 'remove-ssh-dialog',
            controller: function ($scope, $modalInstance) {
                $scope.publicKey = self.$scope.publicKey;
                $scope.close = function () {
                    $modalInstance.close('cancel');
                };
                $scope.delete = function () {
                    common.globalSpinner.show();
                    self.sshKeyService.delete(id).then(() => {
                        self.$scope.project.sshKeyId = null;
                        self.$scope.publicKey = null;
                        common.globalSpinner.hide();
                        $modalInstance.close('cancel');
                    })
                };
            }
        });

    },
    hideSpinner: function () {
        common.globalSpinner.hide();
        this.$scope.updateBtnDisabled = false;
        this.$scope.saveBtnDisabled = false;
    },
    update: function () {
        common.globalSpinner.show();
        this.$scope.updateBtnDisabled = true;

        this.projectsService.update(this.$scope.projectId, this.$scope.project).then(
            response => {
                this.hideSpinner();
                notify.success('Project successfully updated.');
                setTimeout(() => window.location.href = `/build/project/${response.data.id}`, 1000);
            },
            error => {
                this.hideSpinner();
                displayError(error, this.$scope);
            }
        );
    }
});

projectsController.$inject = ['$scope', 'projectsService', '$routeParams', 'sshKeyService', '$modal', 'modulesService', 'masterfilesversionService'];


let projectsViewController = BaseBuildController.extend({
    init: function ($scope, modulesService, projectsService, $routeParams, $modal, masterfilesversionService) {
        this._super($scope, projectsService, $routeParams, $modal);

        this.modulesService = modulesService;
        this.$modal = $modal;
        this.projectsService = projectsService;

        $scope.project = {};
        $scope.moduleCategories = {security: [], compliance: []}
        $scope.refreshStatus = '';

        $scope.$watch('addedModules', addedModules => {
            /**
             * Ask user to install masterfiles if project newly created and masterfiles module is missing
             */
            if (
                addedModules !== undefined &&
                sessionStorage.getItem(PROJECT_CREATED_KEY) === $scope.projectID.toString() &&
                !Object.values(addedModules).some(module => module.name === MASTERFILES_MODULE)
            ) {
                sessionStorage.removeItem(PROJECT_CREATED_KEY);
                masterfilesversionService.getVersion().then(version => this.addModule($scope.projectID, MASTERFILES_MODULE, version));
            }
        })

        Object.keys($scope.moduleCategories).forEach(category => this.modulesService.getList({
            'tag': category,
            'limit': 4,
            'sortColumn': 'downloads',
            'sortDescending': 'true'
        }).then(result => {
            $scope.moduleCategories[category] = result.data.data.map(item => {
                return item;
            })
        }))
        this.refreshProjectStatus();
        this.modulesService.refreshList().catch(error => notify.error('Error occurred while modules list refreshing. ' . error.data));
    },

    defineScope: function () {
        this.$scope.instance = "projectsViewController";
    },
    defineListeners: function () {
        this._super();
        let self = this;

        this.$scope.$watchCollection('[addedModules, project]', async function () {
            if (self.$scope.addedModules != undefined && self.$scope.project != undefined && self.$scope.project.id != undefined ) {
                const addedModulesNames = self.$scope.addedModules.map(item => item.name);
                self.$scope.showQuickstart = await self._showQuickstart(addedModulesNames, self.$scope.project);
            }
        });
    },
    _showQuickstart: async function (addedModules, project) {
        const moreThanOneModuleAdded = addedModules.length > 1;
        const masterfilesModulePresented = addedModules.includes('masterfiles');
        const projectPushed = project.pushed_at != null;
        const projectSynchronizedWithVcs = (await this.projectsService.isProjectSynchronizedWithVcs(project.id)).isSynchronised;

        return !(moreThanOneModuleAdded && masterfilesModulePresented && projectPushed && projectSynchronizedWithVcs);
    }
});

projectsViewController.$inject = ['$scope', 'modulesService', 'projectsService', '$routeParams', '$modal', 'masterfilesversionService'];

buildApp.directive('buildUrlAuthValidator', function () {
    return {
        require: 'ngModel',
        link: function (scope, elem, attr, ngModel) {
            ngModel.$parsers.unshift((value) => {
                const authenticationType = ngModel.$name == 'authenticationType' ? value : scope.project.authenticationType;
                const repositoryUrl = ngModel.$name == 'repositoryUrl' ? value : scope.project.repositoryUrl;

                if (!repositoryUrl || !authenticationType) return value;

                if (authenticationType == 'private_key') {
                    scope.projectForm.repositoryUrl.$setValidity('sshUrlPasswordAuth', true)
                    scope.projectForm.repositoryUrl.$setValidity('httpUrlSshAuth', (repositoryUrl.search(/^(https?):/i) < 0));
                } else if (authenticationType == 'password') {
                    scope.projectForm.repositoryUrl.$setValidity('httpUrlSshAuth', true)
                    scope.projectForm.repositoryUrl.$setValidity('sshUrlPasswordAuth', (repositoryUrl.search(/^(?:git|ssh|git@(.*)):/i) < 0));
                }

                return value;
            });
        }
    };
});
