/*
 * Licensed to The OpenNMS Group, Inc (TOG) under one or more
 * contributor license agreements.  See the LICENSE.md file
 * distributed with this work for additional information
 * regarding copyright ownership.
 *
 * TOG licenses this file to You under the GNU Affero General
 * Public License Version 3 (the "License") or (at your option)
 * any later version.  You may not use this file except in
 * compliance with the License.  You may obtain a copy of the
 * License at:
 *
 *      https://www.gnu.org/licenses/agpl-3.0.txt
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied.  See the License for the specific
 * language governing permissions and limitations under the
 * License.
 */
import bootbox from 'bootbox';

require('../services/Requisitions');

import Util from 'lib/util';
const QuickNode = require('../model/QuickNode');
const escape = require('lodash.escape');

/**
* @author Alejandro Galue <agalue@opennms.org>
* @copyright 2014-2025 The OpenNMS Group, Inc.
*/

(function() {
  'use strict';

  const quickAddPanelBasicView = require('../../views/quick-add-panel-basic.html');
  const quickAddPanelSnmpView = require('../../views/quick-add-panel-snmp.html');
  const quickAddPanelCategoriesView = require('../../views/quick-add-panel-categories.html');
  const quickAddPanelHelpView = require('../../views/quick-add-panel-help.html');

  angular.module('onms-requisitions')

  .config(['$locationProvider', function($locationProvider) {
    $locationProvider.hashPrefix('');
  }])

  /**
  * @ngdoc controller
  * @name QuickAddNodeController
  * @module onms-requisitions
  *
  * @requires $scope Angular local scope
  * @requires foreignSources The list of available requisitions (a.k.a. foreign source)
  * @requires RequisitionsService The requisitions service
  * @requires growl The growl plugin for instant notifications
  *
  * @description The controller for manage the modal dialog for quick add a node to an existing requisition.
  */
  .controller('QuickAddNodeController', ['$scope', 'foreignSources', 'RequisitionsService', 'growl', '$sanitize', function($scope, foreignSources, RequisitionsService, growl, $sanitize) {
    $scope.quickAddPanelBasicView = quickAddPanelBasicView;
    $scope.quickAddPanelSnmpView = quickAddPanelSnmpView;
    $scope.quickAddPanelCategoriesView = quickAddPanelCategoriesView;
    $scope.quickAddPanelHelpView = quickAddPanelHelpView;

    /**
    * @description The available foreign sources
    *
    * @ngdoc property
    * @name QuickAddNodeController#foreignSources
    * @propertyOf QuickAddNodeController
    * @returns {array} List of available foreign sources
    */
    $scope.foreignSources = [];

    /**
    * @description The available configured categories
    *
    * @ngdoc property
    * @name QuickAddNodeController#availableCategories
    * @propertyOf QuickAddNodeController
    * @returns {array} The categories
    */
    $scope.availableCategories = [];

    /**
    * @description The available access methods
    *
    * @ngdoc property
    * @name QuickAddNodeController#availableAccessMethods
    * @propertyOf QuickAddNodeController
    * @returns {array} The access methods
    */
    $scope.availableAccessMethods = [ 'RSH', 'SSH', 'Telnet' ];

    /**
    * @description The saving flag (true when the node is being saved)
    *
    * @ngdoc property
    * @name QuickAddNodeController#isSaving
    * @propertyOf QuickAddNodeController
    * @returns {boolean} true when the node is being saved
    */
    $scope.isSaving = false;

    /**
    * @description The source object that contains all the required information for the new node
    *
    * @ngdoc property
    * @name QuickAddNodeController#node
    * @propertyOf QuickAddNodeController
    * @returns {object} The source object
    */
    $scope.node = new QuickNode();

    /**
    * @description Generates a foreign Id
    *
    * @name QuickAddNodeController:generateForeignId
    * @ngdoc method
    * @methodOf QuickAddNodeController
    * @param {object} the form object associated with the foreignId
    */
    $scope.generateForeignId = function(formObj) {
      $scope.node.foreignId = String(new Date().getTime());
      formObj.$invalid = false;
    };

    /**
    * @description Provision the current node
    *
    * @name QuickAddNodeController:provision
    * @ngdoc method
    * @methodOf QuickAddNodeController
    */
    $scope.provision = function() {
      $scope.isSaving = true;
      growl.info('The node ' + escape($scope.node.nodeLabel) + ' is being added to requisition ' + escape($scope.node.foreignSource) + '. Please wait...');
      const successMessage = 'The node ' + escape($scope.node.nodeLabel) + ' has been added to requisition ' + escape($scope.node.foreignSource);

      RequisitionsService.quickAddNode($scope.node).then(
        function() { // success
          $scope.reset();
          bootbox.dialog({
            message: successMessage,
            title: 'Success',
            buttons: {
              main: {
                label: 'Ok',
                className: 'btn-secondary'
              }
            }
          });
        },
        $scope.errorHandler
      );
    };

    /**
    * @description Resets the current node
    *
    * @name QuickAddNodeController:reset
    * @ngdoc method
    * @methodOf QuickAddNodeController
    */
    $scope.reset = function() {
      $scope.node = new QuickNode(); // Resetting the object.
      $scope.isSaving = false;
    };

   /**
    * @description Get the unused available categories
    *
    * @name QuickAddNodeController:getAvailableCategories
    * @ngdoc method
    * @methodOf QuickAddNodeController
    * @returns {array} the unused available categories
    */
    $scope.getAvailableCategories = function() {
      const categories = [];
      angular.forEach($scope.availableCategories, function(category) {
        let found = false;
        angular.forEach($scope.node.categories, function(c) {
          if (c.name === category) {
            found = true;
          }
        });
        if (!found) {
          categories.push(category);
        }
      });
      return categories;
    };

    /**
    * @description Removes a category from the local node
    *
    * @name QuickAddNodeController:removeCategory
    * @ngdoc method
    * @methodOf QuickAddNodeController
    * @param {integer} index The index of the category to be removed
    */
    $scope.removeCategory = function(index) {
      $scope.node.categories.splice(index, 1);
      this.quickAddNodeForm.$dirty = true;
    };

    /**
    * @description Adds a new category to the local node
    *
    * @name QuickAddNodeController:addCategory
    * @ngdoc method
    * @methodOf QuickAddNodeController
    */
    $scope.addCategory = function() {
      $scope.node.addNewCategory();
      this.quickAddNodeForm.$dirty = true;
    };

    /**
    * @description Checks if the form is valid or not
    *
    * @name QuickAddNodeController:isInvalid
    * @ngdoc method
    * @methodOf QuickAddNodeController
    * @returns {boolean} true if the form is invalid.
    */
    $scope.isInvalid = function() {
      if (!this.quickAddNodeForm ||
        !this.quickAddNodeForm.foreignSource ||
        !this.quickAddNodeForm.ipAddress ||
        !this.quickAddNodeForm.nodeLabel) {
        return true;
      }
      return this.quickAddNodeForm.foreignSource.$invalid ||
        this.quickAddNodeForm.ipAddress.$invalid ||
        this.quickAddNodeForm.nodeLabel.$invalid;
    };

    /**
    * @description Shows an error to the user
    *
    * @name QuickAddNodeController:errorHandler
    * @ngdoc method
    * @methodOf QuickAddNodeController
    * @param {string} message The error message
    */
    $scope.errorHandler = function(message) {
      growl.error(message, {ttl: 10000});
    };

    /**
    * @description Adds a new requisition
    *
    * @name QuickAddNodeController:addRequisition
    * @ngdoc method
    * @methodOf QuickAddNodeController
    */
    $scope.addRequisition = function() {
      bootbox.prompt('A requisition is required, please enter the name for a new requisition', function(foreignSource) {
        if (foreignSource && RequisitionsService.isExcludedRequisitionName(foreignSource)) {
          const errMessage = 'You cannot add a node to this requisition.';
          $scope.errorHandler(errMessage);
          return;
        }

        if (foreignSource) {
            if (foreignSource.match(/[/\\?:&*'"]/)) {
                bootbox.alert('Cannot add the requisition ' + escape(foreignSource) + ' because the following characters are invalid:<br/>:, /, \\, ?, &, *, \', "');
                return;
            }
            
            RequisitionsService.addRequisition(foreignSource).then(
            function() { // success
              RequisitionsService.synchronizeRequisition(foreignSource, false).then(
                function() {
                  growl.success('The requisition ' + escape(foreignSource) + ' has been created and synchronized.');
                  $scope.foreignSources.push(foreignSource);
                },
                $scope.errorHandler
              );
            },
            $scope.errorHandler
          );
        } else {
          window.location.href = Util.getBaseHref() + 'admin/index.jsp'; // TODO Is this the best way ?
        }
      });
    };

    // Initialize categories
    RequisitionsService.getAvailableCategories().then(
      function(categories) { // success
        $scope.availableCategories = categories;
      },
      $scope.errorHandler
    );

    // Initialize requisitions
    if (!foreignSources) {
      RequisitionsService.getRequisitionNames().then(
        function(requisitions) { // success
          const filteredRequisitions = (requisitions || []).filter(function(r) {
            return Boolean(r) && !RequisitionsService.isExcludedRequisitionName(r);
          });
          $scope.foreignSources = filteredRequisitions;

          // If there is NO requisitions, the user has to create a new one
          if ($scope.foreignSources.length === 0) {
            $scope.addRequisition();
          }
        },
        $scope.errorHandler
      );
    } else {
      $scope.foreignSources = foreignSources;
    }
  }]);
}());
