import { inject as service } from '@ember/service';
import Adapter, {
  REQUEST_CREATE,
  REQUEST_UPDATE,
  DATACENTER_QUERY_PARAM as API_DATACENTER_KEY,
} from './application';

import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/token';
import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc';
import { OK as HTTP_OK } from 'consul-ui/utils/http/status';
import { PUT as HTTP_PUT } from 'consul-ui/utils/http/method';

import { get } from '@ember/object';

const REQUEST_CLONE = 'cloneRecord';
const REQUEST_SELF = 'querySelf';

export default Adapter.extend({
  store: service('store'),
  cleanQuery: function(_query) {
    const query = this._super(...arguments);
    // TODO: Make sure policy is being passed through
    delete _query.policy;
    // take off the secret for /self
    delete query.secret;
    return query;
  },
  urlForQuery: function(query, modelName) {
    return this.appendURL('acl/tokens', [], this.cleanQuery(query));
  },
  urlForQueryRecord: function(query, modelName) {
    if (typeof query.id === 'undefined') {
      throw new Error('You must specify an id');
    }
    return this.appendURL('acl/token', [query.id], this.cleanQuery(query));
  },
  urlForQuerySelf: function(query, modelName) {
    return this.appendURL('acl/token/self', [], this.cleanQuery(query));
  },
  urlForCreateRecord: function(modelName, snapshot) {
    return this.appendURL('acl/token', [], {
      [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    });
  },
  urlForUpdateRecord: function(id, modelName, snapshot) {
    // If a token has Rules, use the old API
    if (typeof snapshot.attr('Rules') !== 'undefined') {
      return this.appendURL('acl/update', [], {
        [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
      });
    }
    return this.appendURL('acl/token', [snapshot.attr(SLUG_KEY)], {
      [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    });
  },
  urlForDeleteRecord: function(id, modelName, snapshot) {
    return this.appendURL('acl/token', [snapshot.attr(SLUG_KEY)], {
      [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    });
  },
  urlForRequest: function({ type, snapshot, requestType }) {
    switch (requestType) {
      case 'cloneRecord':
        return this.urlForCloneRecord(type.modelName, snapshot);
      case 'querySelf':
        return this.urlForQuerySelf(snapshot, type.modelName);
    }
    return this._super(...arguments);
  },
  urlForCloneRecord: function(modelName, snapshot) {
    return this.appendURL('acl/token', [snapshot.attr(SLUG_KEY), 'clone'], {
      [API_DATACENTER_KEY]: snapshot.attr(DATACENTER_KEY),
    });
  },
  self: function(store, modelClass, snapshot) {
    const params = {
      store: store,
      type: modelClass,
      snapshot: snapshot,
      requestType: 'querySelf',
    };
    // _requestFor is private... but these methods aren't, until they disappear..
    const request = {
      method: this.methodForRequest(params),
      url: this.urlForRequest(params),
      headers: this.headersForRequest(params),
      data: this.dataForRequest(params),
    };
    // TODO: private..
    return this._makeRequest(request);
  },
  clone: function(store, modelClass, id, snapshot) {
    const params = {
      store: store,
      type: modelClass,
      id: id,
      snapshot: snapshot,
      requestType: 'cloneRecord',
    };
    // _requestFor is private... but these methods aren't, until they disappear..
    const request = {
      method: this.methodForRequest(params),
      url: this.urlForRequest(params),
      headers: this.headersForRequest(params),
      data: this.dataForRequest(params),
    };
    // TODO: private..
    return this._makeRequest(request);
  },
  handleSingleResponse: function(url, response, primary, slug) {
    // Sometimes we get `Policies: null`, make null equal an empty array
    if (typeof response.Policies === 'undefined' || response.Policies === null) {
      response.Policies = [];
    }
    // Convert an old style update response to a new style
    if (typeof response['ID'] !== 'undefined') {
      const item = get(this, 'store')
        .peekAll('token')
        .findBy('SecretID', response['ID']);
      if (item) {
        response['SecretID'] = response['ID'];
        response['AccessorID'] = get(item, 'AccessorID');
      }
    }
    return this._super(url, response, primary, slug);
  },
  handleResponse: function(status, headers, payload, requestData) {
    let response = payload;
    if (status === HTTP_OK) {
      const url = this.parseURL(requestData.url);
      switch (true) {
        case response === true:
          response = this.handleBooleanResponse(url, response, PRIMARY_KEY, SLUG_KEY);
          break;
        case Array.isArray(response):
          response = this.handleBatchResponse(url, response, PRIMARY_KEY, SLUG_KEY);
          break;
        default:
          response = this.handleSingleResponse(url, response, PRIMARY_KEY, SLUG_KEY);
      }
    }
    return this._super(status, headers, response, requestData);
  },
  methodForRequest: function(params) {
    switch (params.requestType) {
      case REQUEST_CLONE:
      case REQUEST_CREATE:
        return HTTP_PUT;
    }
    return this._super(...arguments);
  },
  headersForRequest: function(params) {
    switch (params.requestType) {
      case REQUEST_SELF:
        return {
          'X-Consul-Token': params.snapshot.secret,
        };
    }
    return this._super(...arguments);
  },
  dataForRequest: function(params) {
    let data = this._super(...arguments);
    switch (params.requestType) {
      case REQUEST_UPDATE:
        // If a token has Rules, use the old API
        if (typeof data.token['Rules'] !== 'undefined') {
          data.token['ID'] = data.token['SecretID'];
          data.token['Name'] = data.token['Description'];
        }
      // falls through
      case REQUEST_CREATE:
        if (Array.isArray(data.token.Policies)) {
          data.token.Policies = data.token.Policies.filter(function(item) {
            // Just incase, don't save any policies that aren't saved
            return !get(item, 'isNew');
          }).map(function(item) {
            return {
              ID: get(item, 'ID'),
              Name: get(item, 'Name'),
            };
          });
        } else {
          delete data.token.Policies;
        }
        data = data.token;
        break;
      case REQUEST_SELF:
        return {};
      case REQUEST_CLONE:
        data = {};
        break;
    }
    // make sure we never send the SecretID
    if (data && typeof data['SecretID'] !== 'undefined') {
      delete data['SecretID'];
    }
    return data;
  },
});
