import Component from '@ember/component';
import layout from './template';
import { get, set, computed, observer } from '@ember/object';
import { inject as service } from '@ember/service';
import { all as PromiseAll } from 'rsvp';

const headers = [
  {
    name:           'hostnamePrefix',
    sort:           ['hostnamePrefix', 'id'],
    translationKey: 'clusterNew.rke.nodes.hostnamePrefix',
    scope:          'embedded',
  },
  {
    name:           'count',
    sort:           ['quantity', 'displayName.id'],
    translationKey: 'clusterNew.rke.nodes.count',
    width:          100,
  },
  {
    name:           'nodeTemplate',
    sort:           ['nodeTemplate.displayName', 'nodeTemplate.id'],
    translationKey: 'clusterNew.rke.nodes.template',
  },
  {
    name:           'deleteNotReadyAfterSecs',
    sort:           ['deleteNotReadyAfterSecs'],
    translationKey: 'clusterNew.rke.nodes.deleteNotReadyAfterSecs',
    width:          150,
  },
  {
    name:           'etcd',
    sort:           false,
    translationKey: 'clusterNew.rke.role.header.etcd',
    classNames:     ['text-center'],
    width:          100,
  },
  {
    name:           'controlplane',
    sort:           false,
    translationKey: 'clusterNew.rke.role.header.controlplane',
    classNames:     ['text-center'],
    width:          100,
  },
  {
    name:           'worker',
    sort:           false,
    translationKey: 'clusterNew.rke.role.header.worker',
    scope:          'embedded',
    classNames:     ['text-center'],
    width:          100,
  },
  {
    name:           'advanced',
    sort:           false,
    scope:          'embedded',
    translationKey: 'clusterNew.rke.nodes.taints',
    classNames:     ['text-center'],
    width:          100,
  },
  {
    name:       'remove',
    sort:       false,
    classNames: ['text-center'],
    width:      35,
  }
];

export default Component.extend({
  globalStore:  service(),
  modalService: service('modal'),
  intl:         service(),

  layout,
  headers,
  cluster:       null,
  nodeTemplates: null,
  driver:        null, // docker-machine driver

  originalPools: null,
  nodePools:     null,
  errors:        null,

  init() {
    this._super(...arguments);
    const originalPools = (get(this, 'cluster.nodePools') || []).slice();

    set(this, 'originalPools', originalPools);
    set(this, 'nodePools', originalPools.slice().map((p) => p.clone()));

    if ( get(this, 'mode') === 'new' && get(originalPools, 'length') === 0 ) {
      get(this, 'nodePools').pushObject(get(this, 'globalStore').createRecord({
        type:     'nodePool',
        quantity: 1,
      }));
    }

    if (this.registerHook) {
      this.registerHook(this.savePools.bind(this), 'savePools')
    }

    this.setDefaultNodeTemplate();
  },

  didReceiveAttrs() {
    this.validate();
  },

  actions: {
    addPool() {
      let nodePools = get(this, 'nodePools');

      let templateId = null;
      const lastNode = nodePools[nodePools.length - 1];

      if ( lastNode ) {
        templateId = get(lastNode, 'nodeTemplateId');
      }

      nodePools.pushObject(get(this, 'globalStore').createRecord({
        type:           'nodePool',
        nodeTemplateId: templateId
      }));
    },

    removePool(pool) {
      get(this, 'nodePools').removeObject(pool);
    },

    addNodeTemplate(node) {
      get(this, 'modalService').toggleModal('modal-edit-node-template', {
        nodeTemplate: null,
        driver:       get(this, 'driver'),
        onAdd(nodeTemplate) {
          set(node, 'nodeTemplateId', get(nodeTemplate, 'id'));
        },
      });
    },

    configAdvancedOptions(pool) {
      get(this, 'modalService').toggleModal('modal-edit-node-pool', pool);
    },
  },

  setDefaultNodeTemplate: observer('driver', function() {
    const templates = get(this, 'filteredNodeTemplates') || [];

    if ( templates.length === 1 ) {
      (get(this, 'nodePools') || []).forEach((pool) => {
        if ( !get(pool, 'nodeTemplateId') ) {
          set(pool, 'nodeTemplateId', get(templates, 'firstObject.id'));
        }
      });
    }
  }),

  driverChanged: observer('driver', function() {
    const driver = get(this, 'driver');

    get(this, 'nodePools').forEach((pool) => {
      const tpl = get(pool, 'nodeTemplate');

      if ( tpl && get(tpl, 'driver') !== driver ) {
        set(pool, 'nodeTemplateId', null);
      }
    });
  }),

  validate: observer('etcdOk', 'controlPlaneOk', 'workerOk', 'nodePools.@each.{quantity,hostnamePrefix,nodeTemplateId}', 'nodePools.[]', 'driver', function() {
    const intl = get(this, 'intl');
    const driver = get(this, 'driver');

    const errors = [];

    if ( get(this, 'mode') === 'new' && !get(this, 'etcdOk') ) {
      errors.push(intl.t('clusterNew.rke.errors.etcd'));
    }

    if ( !get(this, 'controlPlaneOk') ) {
      errors.push(intl.t('clusterNew.rke.errors.controlPlane'));
    }

    if ( !get(this, 'workerOk') ) {
      errors.push(intl.t('clusterNew.rke.errors.worker'));
    }

    if ( driver === 'digitalocean') {
      const nodePools = get(this, 'nodePools');
      let isError = false;

      nodePools.map((p) => {
        const { hostnamePrefix = '' } = p;

        if (hostnamePrefix.includes('_')) {
          isError = true;
        }
      })

      if (isError) {
        errors.push(intl.t('nodeDriver.digitalocean.errors.hostnamePrefix'));
      }
    }

    get(this, 'nodePools').forEach((pool) => {
      // ClusterId is required but not known yet
      if ( !get(pool, 'clusterId') ) {
        set(pool, 'clusterId', '__later__');
      }
      errors.pushObjects(pool.validationErrors());
    });

    if (this.setNodePoolErrors) {
      this.setNodePoolErrors(errors);
    }
  }),
  showIamWarning: computed('driver', 'nodePools.@each.{nodeTemplateId}', 'cluster.rancherKubernetesEngineConfig.cloudProvider.name', function() {
    const cloudProvider = get(this, 'cluster.rancherKubernetesEngineConfig.cloudProvider.name');
    const driver = get(this, 'driver');

    if ( driver === 'amazonec2' && cloudProvider === 'aws' ) {
      const found = (get(this, 'nodePools') || []).some((pool) => {
        const nodeTemplate = get(pool, 'nodeTemplate');

        return nodeTemplate && !get(nodeTemplate, 'amazonec2Config.iamInstanceProfile');
      });

      return found ? true : false;
    }

    return false;
  }),

  filteredNodeTemplates: computed('driver', 'nodeTemplates.@each.{state,driver}', function() {
    const driver = get(this, 'driver');
    let templates = get(this, 'nodeTemplates').filterBy('state', 'active').filterBy('driver', driver);

    return templates;
  }),

  etcdOk: computed('nodePools.@each.{quantity,etcd}', function() {
    let count = this._nodeCountFor('etcd');

    return count === 1 || count === 3 || count === 5
  }),

  etcdCount: computed('nodePools.@each.{quantity,etcd}', function() {
    return this._nodeCountFor('etcd');
  }),

  controlPlaneOk: computed('nodePools.@each.{quantity,controlPlane}', function() {
    let count = this._nodeCountFor('controlPlane');

    return count >= 1;
  }),

  workerOk: computed('nodePools.@each.{quantity,worker}', function() {
    let count = this._nodeCountFor('worker');

    return count >= 1;
  }),

  savePools() {
    if (this.isDestroyed || this.isDestroying || get(this, 'driver') === 'custom' ) {
      return;
    }

    const nodePools = get(this, 'nodePools');
    const original = get(this, 'originalPools');

    const remove = [];

    original.forEach((pool) => {
      if ( !nodePools.some((p) => p.id === pool.id) ) {
        // Remove
        remove.push(pool);
      }
    });

    const clusterId = get(this, 'cluster.id');

    nodePools.forEach((pool) => {
      set(pool, 'clusterId', clusterId);
    });


    return PromiseAll(nodePools.map((x) => x.save())).then(() => {
      return PromiseAll(remove.map((x) => x.delete())).then(() => {
        return get(this, 'cluster');
      });
    });
  },

  _nodeCountFor(role) {
    let count = 0;

    (get(this, 'nodePools') || []).filterBy(role, true).forEach((pool) => {
      let more = get(pool, 'quantity');

      if ( more ) {
        more = parseInt(more, 10);
      }

      count += more;
    });

    return count;
  },

});
