import { later, cancel } from '@ember/runloop';
import { computed, get, set } from '@ember/object';
import Grafana from 'shared/mixins/grafana';
import { alias, gt, not } from '@ember/object/computed';
import Resource from '@rancher/ember-api-store/models/resource';
import { sortableNumericSuffix } from 'shared/utils/util';
import { formatSi } from 'shared/utils/parse-unit';
import { reference, hasMany } from '@rancher/ember-api-store/utils/denormalize';
import StateCounts from 'ui/mixins/state-counts';
import EndpointPorts from 'ui/mixins/endpoint-ports';
import { inject as service } from '@ember/service';
import DisplayImage from 'shared/mixins/display-image';
import C from 'shared/utils/constants';

const WORKLOAD_CONFIG_FIELDS = ['cronJobConfig', 'daemonSetConfig', 'deploymentConfig', 'jobConfig', 'replicaSetConfig', 'replicationControllerConfig', 'statefulSetConfig']

var Workload = Resource.extend(Grafana, DisplayImage, StateCounts, EndpointPorts, {
  intl:          service(),
  growl:         service(),
  modalService:  service('modal'),
  scope:         service(),
  router:        service(),
  clusterStore: service(),

  pods:         hasMany('id', 'pod', 'workloadId'),

  scaleTimer:       null,

  // @TODO-2.0 cleanup all these...
  hasPorts:            true,
  canUpgrade:          true,
  canHaveLabels:       true,
  realButNotLb:        true,
  canHaveLinks:        true,
  canChangeNetworking: true,
  canChangeSecurity:   true,
  canHaveSecrets:      true,
  canHaveEnvironment:  true,
  canHaveHealthCheck:  true,
  isBalancer:          false,
  canBalanceTo:         true,

  grafanaResourceId:    alias('name'),

  namespace:    reference('namespaceId', 'namespace', 'clusterStore'),
  canClone:  not('hasSidekicks'),

  hasSidekicks: gt('containers.length', 1),

  launchConfig: alias('containers.firstObject'),

  canScaleUp: alias('canScale'),

  init() {
    this._super(...arguments);
    this.defineStateCounts('pods', 'podStates', 'podCountSort');
  },

  restarts: computed('pods.@each.restarts', function() {
    let out = 0;

    (get(this, 'pods') || []).forEach((pod) => {
      out += get(pod, 'restarts');
    });

    return out;
  }),

  lcType: computed('type', function() {
    return (get(this, 'type') || '').toLowerCase();
  }),

  canEdit: computed('links.update', 'lcType', function() {
    const lcType = get(this, 'lcType');

    return !!get(this, 'links.update') && ( lcType !== 'job' );
  }),

  availableActions: function() {
    const a = get(this, 'actionLinks') || {};

    const podForShell = get(this, 'podForShell');

    const isPaused = get(this, 'isPaused');
    const canEdit = get(this, 'canEdit');

    let choices = [
      {
        label:    'action.redeploy',
        icon:     'icon icon-refresh',
        action:   'redeploy',
        enabled:  canEdit,
        bulkable: true,
      },
      {
        label:   'action.addSidekick',
        icon:    'icon icon-plus-circle',
        action:  'addSidekick',
      },
      {
        label:   'action.rollback',
        icon:    'icon icon-history',
        action:  'rollback',
        enabled: !!a.rollback,
      },
      { divider: true },
      {
        label:     'action.execute',
        icon:      'icon icon-terminal',
        action:    'shell',
        enabled:   !!podForShell,
        altAction: 'popoutShell'
      },
      //      { label: 'action.logs',           icon: 'icon icon-file',             action: 'logs',           enabled: !!a.logs, altAction: 'popoutLogs' },
      { divider: true },
      {
        label:    'action.pause',
        icon:     'icon icon-pause',
        action:   'pause',
        enabled:  !!a.pause && !isPaused,
        bulkable: true
      },
      {
        label:    'action.resume',
        icon:     'icon icon-play',
        action:   'resume',
        enabled:  !!a.pause && isPaused,
        bulkable: true
      },
    ];

    return choices;
  }.property('actionLinks.{activate,deactivate,pause,restart,rollback,garbagecollect}', 'links.{update,remove}',
    'podForShell', 'isPaused', 'canEdit'
  ),

  displayType: function() {
    let type = this.get('type');

    return get(this, 'intl').t(`servicePage.serviceType.${ type }`);
  }.property('type'),

  sortName: function() {
    return sortableNumericSuffix(get(this, 'displayName'));
  }.property('displayName'),

  combinedState: function() {
    var service = get(this, 'state');
    var health = get(this, 'healthState');

    if ( service === 'active' && health ) {
      // Return the health state for active services
      return health;
    }

    // Return the service for anything else
    return service;
  }.property('state', 'healthState'),

  isGlobalScale: function() {
    let lcType = get(this, 'lcType');

    return lcType === 'daemonset';
  }.property('lcType'),

  canScaleDown: function() {
    return get(this, 'canScale') && get(this, 'scale') > 0;
  }.property('canScale', 'scale'),

  displayScale: function() {
    if ( get(this, 'isGlobalScale') ) {
      return get(this, 'intl').t('servicePage.multistat.daemonSetScale');
    } else {
      return get(this, 'scale');
    }
  }.property('scale', 'isGlobalScale', 'lcType'),

  canScale: computed('lcType', function() {
    let lcType = get(this, 'lcType');

    return lcType !== 'cronjob' && lcType !== 'daemonset' && lcType !== 'job';
  }),

  activeIcon: function() {
    return activeIcon(this);
  }.property('lcType'),

  memoryReservationBlurb: computed('launchConfig.memoryReservation', function() {
    if ( get(this, 'launchConfig.memoryReservation') ) {
      return formatSi(get(this, 'launchConfig.memoryReservation'), 1024, 'iB', 'B');
    }
  }),

  podForShell: computed('pods.@each.canShell', function() {
    return get(this, 'pods').findBy('canShell', true);
  }),

  secondaryLaunchConfigs: computed('containers.[]', function() {
    return (get(this, 'containers') || []).slice(1);
  }),

  isCreatedByRancher: computed('workloadAnnotations', function() {
    const workloadAnnotations = get(this, 'workloadAnnotations') || {};

    return !!workloadAnnotations[C.LABEL.CREATOR_ID];
  }),

  currentScale: computed('pods.@each.state', 'scale', function() {
    const { pods = [] } = this

    return pods.filter((p) => p.state === 'running').length
  }),

  actions: {
    activate() {
      return this.doAction('activate');
    },

    deactivate() {
      return this.doAction('deactivate');
    },

    pause() {
      return this.doAction('pause');
    },

    resume() {
      return this.doAction('resume');
    },

    restart() {
      return this.doAction('restart', { rollingRestartStrategy: {} });
    },

    rollback() {
      get(this, 'modalService').toggleModal('modal-rollback-service', { originalModel: this });
    },

    garbageCollect() {
      return this.doAction('garbagecollect');
    },

    // Start and stop are only here to mimic the same actions that exist on a container
    // the reason being bulkActions, to forgo writing distinct logic for containers vs
    // services lets just mimic the actions here.
    start() {
      return this.doAction('activate');
    },

    stop() {
      return this.doAction('deactivate');
    },

    promptStop() {
      get(this, 'modalService').toggleModal('modal-container-stop', { model: [this] });
    },

    scaleUp() {
      set(this, 'scale', get(this, 'scale') + 1);
      this.saveScale();
    },

    scaleDown() {
      let scale = get(this, 'scale');

      scale -= 1;
      scale = Math.max(scale, 0);
      set(this, 'scale', scale);
      this.saveScale();
    },

    edit(upgradeImage = 'false') {
      var route = 'containers.run';

      if ( get(this, 'lcType') === 'loadbalancerservice' ) {
        route = 'balancers.run';
      }

      get(this, 'router').transitionTo(route, {
        queryParams: {
          workloadId:   get(this, 'id'),
          upgrade:      true,
          upgradeImage,
          namespaceId:  get(this, 'namespaceId'),
        }
      });
    },

    clone() {
      get(this, 'router').transitionTo('containers.run', { queryParams: { workloadId: get(this, 'id'), } });
    },

    redeploy() {
      this.updateTimestamp();
      this.save();
    },

    addSidekick() {
      get(this, 'router').transitionTo('containers.run', {
        queryParams: {
          workloadId:  get(this, 'id'),
          addSidekick: true,
        }
      });
    },

    shell() {
      get(this, 'modalService').toggleModal('modal-shell', { model: get(this, 'podForShell'), });
    },

    popoutShell() {
      const projectId = get(this, 'scope.currentProject.id');
      const podId = get(this, 'podForShell.id');
      const route = get(this, 'router').urlFor('authenticated.project.console', projectId);

      const system = get(this, 'podForShell.node.info.os.operatingSystem') || ''
      let windows = false;

      if (system.startsWith('Windows')) {
        windows = true;
      }

      later(() => {
        const opt = 'toolbars=0,width=900,height=700,left=200,top=200';

        window.open(`//${ window.location.host }${ route }?podId=${ podId }&windows=${ windows }&isPopup=true`, '_blank', opt);
      });
    },
  },

  updateTimestamp() {
    let obj = get(this, 'annotations');

    if ( !obj ) {
      obj = {};
      set(this, 'annotations', obj);
    }

    obj[C.LABEL.TIMESTAMP] = (new Date()).toISOString().replace(/\.\d+Z$/, 'Z');
  },

  saveScale() {
    if ( get(this, 'scaleTimer') ) {
      cancel(get(this, 'scaleTimer'));
    }

    var timer = later(this, function() {
      this.save({ data: { scale: get(this, 'scale') } }).catch((err) => {
        get(this, 'growl').fromError('Error updating scale', err);
      });
    }, 500);

    set(this, 'scaleTimer', timer);
  },

  clearConfigsExcept(keep) {
    const keys = this.allKeys().filter((x) => WORKLOAD_CONFIG_FIELDS.indexOf(x) > -1);

    for ( let key, i = 0 ; i < keys.length ; i++ ) {
      key = keys[i];
      if ( key !== keep && get(this, key) ) {
        set(this, key, null);
      }
    }
  },

});

export function activeIcon(workload) {
  var out = 'icon icon-services';

  switch ( workload.get('lcType') ) {
  case 'pod':                 out = 'icon icon-container'; break;
  case 'cronjob':             out = 'icon icon-backup';    break;
  case 'job':                 out = 'icon icon-file';      break;
  case 'daemonset':           out = 'icon icon-globe';     break;
  case 'statefulset':         out = 'icon icon-database';  break;
  }

  return out;
}

Workload.reopenClass({
  stateMap: {
    'active':             {
      icon:  activeIcon,
      color: 'text-success'
    },
  },

  mangleIn(data) {
    if ( data ) {
      const publicEndpoints = get(data, 'publicEndpoints') || [];
      const containers = get(data, 'containers') || [];

      publicEndpoints.forEach((endpoint) => {
        endpoint.type = 'publicEndpoint';
      });
      containers.forEach((container) => {
        container.type = 'container';
      });
    }

    return data;
  }
});

export default Workload;
