'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,
            classicPolicySet: data.classic_policy_set
          };
          $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.error('Project not found.');
        });
    }

    this.projectsService = projectsService;
    this.sshKeyService = sshKeyService;
    $scope.project = { authenticationType: 'password', classicPolicySet: false };
    $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 (
        $scope.project.classic_policy_set === false &&
        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 => {
          const moduleData = this.prepareModuleData({
            projectID: $scope.projectID,
            name: MASTERFILES_MODULE,
            version
          });
          this.addModule(moduleData);
        });
      }
    });

    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;
      });
    }
  };
});
