text: 'use strict';
  
  import { module } from 'angular';
  import _ from 'lodash';
  
  import {
    CloudProviderRegistry,
    ConfirmationModalService,
    InstanceReader,
    INSTANCE_WRITE_SERVICE,
    InstanceTemplates,
    RecentHistoryService,
  } from '@spinnaker/core';
  import UIROUTER_ANGULARJS from '@uirouter/angularjs';
  import ANGULAR_UI_BOOTSTRAP from 'angular-ui-bootstrap';
  
  export const AZURE_INSTANCE_DETAILS_INSTANCE_DETAILS_CONTROLLER = 'spinnaker.azure.instance.detail.controller';
  export const name = AZURE_INSTANCE_DETAILS_INSTANCE_DETAILS_CONTROLLER; // for backwards compatibility
  module(AZURE_INSTANCE_DETAILS_INSTANCE_DETAILS_CONTROLLER, [
    UIROUTER_ANGULARJS,
    ANGULAR_UI_BOOTSTRAP,
    INSTANCE_WRITE_SERVICE,
  ]).controller('azureInstanceDetailsCtrl', [
    '$scope',
    '$state',
    '$uibModal',
    'instanceWriter',
    'instance',
    'app',
    '$q',
    function ($scope, $state, $uibModal, instanceWriter, instance, app, $q) {
      // needed for standalone instances
      $scope.detailsTemplateUrl = CloudProviderRegistry.getValue('azure', 'instance.detailsTemplateUrl');
  
      $scope.state = {
        loading: true,
        standalone: app.isStandalone,
      };
  
      function extractHealthMetrics(instance, latest) {
        // do not backfill on standalone instances
        if (app.isStandalone) {
          instance.health = latest.health;
        }
  
        instance.health = instance.health || [];
        const displayableMetrics = instance.health.filter(function (metric) {
          return metric.type !== 'Azure' || metric.state !== 'Unknown';
        });
        // backfill details where applicable
        if (latest.health) {
          displayableMetrics.forEach(function (metric) {
            const detailsMatch = latest.health.filter(function (latestHealth) {
              return latestHealth.type === metric.type;
            });
            if (detailsMatch.length) {
              _.defaults(metric, detailsMatch[0]);
            }
          });
        }
        $scope.healthMetrics = displayableMetrics;
      }
  
      function retrieveInstance() {
        const extraData = {};
        let instanceSummary, loadBalancers, account, region, vpcId;
        if (!app.serverGroups) {
          // standalone instance
          instanceSummary = {};
          loadBalancers = [];
          account = instance.account;
          region = instance.region;
        } else {
          app.serverGroups.data.some(function (serverGroup) {
            return serverGroup.instances.some(function (possibleInstance) {
              if (possibleInstance.id === instance.instanceId) {
                instanceSummary = possibleInstance;
                loadBalancers = serverGroup.loadBalancers;
                account = serverGroup.account;
                region = serverGroup.region;
                vpcId = serverGroup.vpcId;
                extraData.serverGroup = serverGroup.name;
                extraData.vpcId = serverGroup.vpcId;
                return true;
              }
            });
          });
          if (!instanceSummary) {
            // perhaps it is in a server group that is part of another app
            app.loadBalancers.data.some(function (loadBalancer) {
              return loadBalancer.instances.some(function (possibleInstance) {
                if (possibleInstance.id === instance.instanceId) {
                  instanceSummary = possibleInstance;
                  loadBalancers = [loadBalancer.name];
                  account = loadBalancer.account;
                  region = loadBalancer.region;
                  vpcId = loadBalancer.vpcId;
                  return true;
                }
              });
            });
            if (!instanceSummary) {
              // perhaps it is in a disabled server group via a load balancer
              app.loadBalancers.data.some(function (loadBalancer) {
                return loadBalancer.serverGroups.some(function (serverGroup) {
                  if (!serverGroup.isDisabled) {
                    return false;
                  }
                  return serverGroup.instances.some(function (possibleInstance) {
                    if (possibleInstance.id === instance.instanceId) {
                      instanceSummary = possibleInstance;
                      loadBalancers = [loadBalancer.name];
                      account = loadBalancer.account;
                      region = loadBalancer.region;
                      vpcId = loadBalancer.vpcId;
                      return true;
                    }
                  });
                });
              });
            }
          }
        }
  
        if (instanceSummary && account && region) {
          extraData.account = account;
          extraData.region = region;
          RecentHistoryService.addExtraDataToLatest('instances', extraData);
          return InstanceReader.getInstanceDetails(account, region, instance.instanceId).then(
            function (details) {
              $scope.state.loading = false;
              extractHealthMetrics(instanceSummary, details);
              $scope.instance = _.defaults(details, instanceSummary);
              $scope.instance.account = account;
              $scope.instance.region = region;
              $scope.instance.vpcId = vpcId;
              $scope.instance.loadBalancers = loadBalancers;
              const discoveryMetric = _.find($scope.healthMetrics, function (metric) {
                return metric.type === 'Discovery';
              });
              if (discoveryMetric && discoveryMetric.vipAddress) {
                const vipList = discoveryMetric.vipAddress;
                $scope.instance.vipAddress = vipList.includes(',') ? vipList.split(',') : [vipList];
              }
              $scope.baseIpAddress = details.publicDnsName || details.privateIpAddress;
            },
            function () {
              // When an instance is first starting up, we may not have the details cached in oort yet, but we still
              // want to let the user see what details we have
              $scope.state.loading = false;
              $state.go('^');
            },
          );
        }
  
        if (!instanceSummary) {
          $scope.instanceIdNotFound = instance.instanceId;
          $scope.state.loading = false;
        }
  
        return $q.when(null);
      }
  
      this.canDeregisterFromLoadBalancer = function () {
        return $scope.instance.health.some(function (health) {
          return health.type === 'LoadBalancer';
        });
      };
  
      this.canRegisterWithLoadBalancer = function () {
        const instance = $scope.instance;
        if (!instance.loadBalancers || !instance.loadBalancers.length) {
          return false;
        }
        const outOfService = instance.health.some(function (health) {
          return health.type === 'LoadBalancer' && health.state === 'OutOfService';
        });
        const hasLoadBalancerHealth = instance.health.some(function (health) {
          return health.type === 'LoadBalancer';
        });
        return outOfService || !hasLoadBalancerHealth;
      };
  
      this.canRegisterWithDiscovery = function () {
        const instance = $scope.instance;
        const discoveryHealth = instance.health.filter(function (health) {
          return health.type === 'Discovery';
        });
        return discoveryHealth.length ? discoveryHealth[0].state === 'OutOfService' : false;
      };
  
      this.terminateInstance = function terminateInstance() {
        const instance = $scope.instance;
  
        const taskMonitor = {
          application: app,
          title: 'Terminating ' + instance.instanceId,
          onTaskComplete: function () {
            if ($state.includes('**.instanceDetails', { instanceId: instance.instanceId })) {
              $state.go('^');
            }
          },
        };
  
        const submitMethod = function () {
          return instanceWriter.terminateInstance(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really terminate ' + instance.instanceId + '?',
          buttonText: 'Terminate ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.terminateInstanceAndShrinkServerGroup = function terminateInstanceAndShrinkServerGroup() {
        const instance = $scope.instance;
  
        const taskMonitor = {
          application: app,
          title: 'Terminating ' + instance.instanceId + ' and shrinking server group',
          onTaskComplete: function () {
            if ($state.includes('**.instanceDetails', { instanceId: instance.instanceId })) {
              $state.go('^');
            }
          },
        };
  
        const submitMethod = function () {
          return instanceWriter.terminateInstanceAndShrinkServerGroup(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really terminate ' + instance.instanceId + ' and shrink ' + instance.serverGroup + '?',
          buttonText: 'Terminate ' + instance.instanceId + ' and shrink ' + instance.serverGroup,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.rebootInstance = function rebootInstance() {
        const instance = $scope.instance;
  
        const taskMonitor = {
          application: app,
          title: 'Rebooting ' + instance.instanceId,
        };
  
        const submitMethod = function () {
          return instanceWriter.rebootInstance(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really reboot ' + instance.instanceId + '?',
          buttonText: 'Reboot ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.registerInstanceWithLoadBalancer = function registerInstanceWithLoadBalancer() {
        const instance = $scope.instance;
        const loadBalancerNames = instance.loadBalancers.join(' and ');
  
        const taskMonitor = {
          application: app,
          title: 'Registering ' + instance.instanceId + ' with ' + loadBalancerNames,
        };
  
        const submitMethod = function () {
          return instanceWriter.registerInstanceWithLoadBalancer(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really register ' + instance.instanceId + ' with ' + loadBalancerNames + '?',
          buttonText: 'Register ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.deregisterInstanceFromLoadBalancer = function deregisterInstanceFromLoadBalancer() {
        const instance = $scope.instance;
        const loadBalancerNames = instance.loadBalancers.join(' and ');
  
        const taskMonitor = {
          application: app,
          title: 'Deregistering ' + instance.instanceId + ' from ' + loadBalancerNames,
        };
  
        const submitMethod = function () {
          return instanceWriter.deregisterInstanceFromLoadBalancer(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really deregister ' + instance.instanceId + ' from ' + loadBalancerNames + '?',
          buttonText: 'Deregister ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.enableInstanceInDiscovery = function enableInstanceInDiscovery() {
        const instance = $scope.instance;
  
        const taskMonitor = {
          application: app,
          title: 'Enabling ' + instance.instanceId + ' in discovery',
        };
  
        const submitMethod = function () {
          return instanceWriter.enableInstanceInDiscovery(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really enable ' + instance.instanceId + ' in discovery?',
          buttonText: 'Enable ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.disableInstanceInDiscovery = function disableInstanceInDiscovery() {
        const instance = $scope.instance;
  
        const taskMonitor = {
          application: app,
          title: 'Disabling ' + instance.instanceId + ' in discovery',
        };
  
        const submitMethod = function () {
          return instanceWriter.disableInstanceInDiscovery(instance, app);
        };
  
        ConfirmationModalService.confirm({
          header: 'Really disable ' + instance.instanceId + ' in discovery?',
          buttonText: 'Disable ' + instance.instanceId,
          account: instance.account,
          taskMonitorConfig: taskMonitor,
          submitMethod: submitMethod,
        });
      };
  
      this.showConsoleOutput = function () {
        $uibModal.open({
          templateUrl: InstanceTemplates.consoleOutputModal,
          controller: 'ConsoleOutputCtrl as ctrl',
          size: 'lg',
          resolve: {
            instance: function () {
              return $scope.instance;
            },
          },
        });
      };
  
      this.hasHealthState = function hasHealthState(healthProviderType, state) {
        const instance = $scope.instance;
        return instance.health.some(function (health) {
          return health.type === healthProviderType && health.state === state;
        });
      };
  
      const initialize = app.isStandalone
        ? retrieveInstance()
        : $q.all([app.serverGroups.ready(), app.loadBalancers.ready()]).then(retrieveInstance);
  
      initialize.then(() => {
        // Two things to look out for here:
        //  1. If the retrieveInstance call completes *after* the user has navigated away from the view, there
        //     is no point in subscribing to the refresh
        //  2. If this is a standalone instance, there is no application that will refresh
        if (!$scope.$$destroyed && !app.isStandalone) {
          app.serverGroups.onRefresh($scope, retrieveInstance);
        }
      });
  
      $scope.account = instance.account;
    },
  ]);
  