/* eslint-disable no-param-reassign */
import isNil from 'lodash/isNil';
import defaults from 'lodash/defaults';
import { fetch } from './polyfill';
import { checkStatus, normParams, parseObject } from './http-helper';
import middleware from './middleware';

const defaultOptions = {
  headers: {
    Accept: 'application/json',
  },
};

const sortBody = (keys) => {
  const idxToken = keys.indexOf('token');
  let tokens = [];
  let dmPaths = [];
  if (idxToken !== -1) {
    tokens = keys.splice(idxToken, 1);
  }
  const idxDmPath = keys.indexOf('dmPath');
  if (idxDmPath !== -1) {
    dmPaths = keys.splice(idxDmPath, 1);
  }
  return [...tokens, ...dmPaths, ...keys];
};

const orderedStringify = (obj) => {
  const allKeys = [];
  JSON.stringify(obj, (k, v) => { allKeys.push(k); return v; });
  return JSON.stringify(obj, sortBody(allKeys));
};

export default async function post(url, data, params = {}, options = {}, auth = true) {
  if (!data) {
    data = {};
  }
  params = normParams(params);
  const res = await middleware.post.onRequest(url, data, params, options, auth);
  let queryParams = res ? res.params : params;
  queryParams = queryParams.map(([k, v]) => (isNil(v) ? k : `${k}=${encodeURIComponent(v)}`));
  queryParams = queryParams.join('&');
  let realUrl = res ? res.url : url;
  if (queryParams) {
    realUrl = `${url}?${queryParams}`;
  }
  const realOptions = defaults(res ? res.options : options, defaultOptions);
  if (!realOptions.headers) {
    realOptions.headers = {
      Accept: 'application/json',
    };
  }
  realOptions.headers['Content-Type'] = 'application/json';
  realOptions.method = 'POST';
  const body = res ? res.data : data;
  realOptions.body = orderedStringify(body);
  return fetch(realUrl, realOptions)
    .then(checkStatus)
    .then(resp => parseObject(resp, middleware.post.onResponse));
}