import _ from 'lodash';
import { Resolver } from 'fastjson_ref_resolver';

/**
 * @global
 * @typedef {Object} RestResponse
 * @template T
 * @property {number} errorCode 错误码，0表示成功
 * @property {T} data 数据
 */

export function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }
  return response.json().then((data) => {
    const error = new Error(data.message ? data.message : response.statusText);
    error.data = data;
    throw error;
  });
}

export function normParams(unnormed) {
  if (_.isPlainObject(unnormed)) {
    return _(unnormed).toPairs().flatMap(([k, v]) => (_.isArray(v) ? v.map(vv => [k, vv]) : [[k, v]])).value();
  } else {
    return unnormed;
  }
}

// eslint-disable-next-line max-len
export function parseObject(response, {
  num2str = false, bool2str = false, nul2str = false, ud2str = false, nil2str = false,
} = {}) {
  if (response.status === 204) { // no-content
    return null;
  } else {
    const contentType = response.headers.get('content-type');
    if (contentType) {
      const needMap = num2str || bool2str || nul2str || ud2str || nil2str;
      const mapStr = (value) => {
        if (num2str && _.isNumber(value)) {
          return value.toString();
        }
        if (bool2str && _.isBoolean(value)) {
          return value.toString();
        }
        if (nul2str && _.isNull(value)) {
          return '';
        }
        if (ud2str && _.isUndefined(value)) {
          return '';
        }
        if (nil2str && _.isNil(value)) {
          return '';
        }
        return value;
      };
      const mapObj = (obj, mapArrFunc) => {
        if (_.isArray(obj)) {
          return mapArrFunc(obj, mapObj);
        }
        if (_.isPlainObject(obj)) {
          return _.mapValues(obj, (val) => {
            const ret = mapStr(val);
            return mapObj(ret, mapArrFunc);
          });
        }
        return obj;
      };
      const mapArr = (arr, mapObjFunc) => {
        if (_.isPlainObject(arr)) {
          return mapObjFunc(arr, mapArr);
        }
        if (_.isArray(arr)) {
          return _.map(arr, (val) => {
            const ret = mapStr(val);
            return mapArr(ret, mapObjFunc);
          });
        }
        return arr;
      };
      const mapValue = _.curry(mapObj)(_, mapArr);
      if (contentType.indexOf('json') !== -1) {
        return response.json()
          .then((json) => {
            if (json.errorCode === 0) {
              let { data } = json;
              if (_.isObjectLike(data)) {
                data = new Resolver(json.data).resolve();
              }
              return needMap ? mapValue(data) : data;
            } else {
              throw new Error(json.message);
            }
          });
      } else if (contentType.indexOf('text') !== -1) {
        return response.text();
      } else {
        throw new Error(`Unsupported response content type: ${contentType}`);
      }
    } else {
      throw new Error('No response content type.');
    }
  }
}
