'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var multiaddr = require('multiaddr');
var env_js = require('ipfs-utils/src/env.js');
var parseDuration = require('parse-duration');
var debug = require('debug');
var HTTP = require('ipfs-utils/src/http.js');
var mergeOpts = require('merge-options');
var toUrlString = require('ipfs-core-utils/to-url-string');
var getAgent = require('ipfs-core-utils/agent');

function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

var parseDuration__default = /*#__PURE__*/_interopDefaultLegacy(parseDuration);
var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
var HTTP__default = /*#__PURE__*/_interopDefaultLegacy(HTTP);
var mergeOpts__default = /*#__PURE__*/_interopDefaultLegacy(mergeOpts);
var getAgent__default = /*#__PURE__*/_interopDefaultLegacy(getAgent);

const log = debug__default["default"]('ipfs-http-client:lib:error-handler');
const merge = mergeOpts__default["default"].bind({ ignoreUndefined: true });
const DEFAULT_PROTOCOL = env_js.isBrowser || env_js.isWebWorker ? location.protocol : 'http';
const DEFAULT_HOST = env_js.isBrowser || env_js.isWebWorker ? location.hostname : 'localhost';
const DEFAULT_PORT = env_js.isBrowser || env_js.isWebWorker ? location.port : '5001';
const normalizeOptions = (options = {}) => {
  let url;
  let opts = {};
  let agent;
  if (typeof options === 'string' || multiaddr.Multiaddr.isMultiaddr(options)) {
    url = new URL(toUrlString.toUrlString(options));
  } else if (options instanceof URL) {
    url = options;
  } else if (typeof options.url === 'string' || multiaddr.Multiaddr.isMultiaddr(options.url)) {
    url = new URL(toUrlString.toUrlString(options.url));
    opts = options;
  } else if (options.url instanceof URL) {
    url = options.url;
    opts = options;
  } else {
    opts = options || {};
    const protocol = (opts.protocol || DEFAULT_PROTOCOL).replace(':', '');
    const host = (opts.host || DEFAULT_HOST).split(':')[0];
    const port = opts.port || DEFAULT_PORT;
    url = new URL(`${ protocol }://${ host }:${ port }`);
  }
  if (opts.apiPath) {
    url.pathname = opts.apiPath;
  } else if (url.pathname === '/' || url.pathname === undefined) {
    url.pathname = 'api/v0';
  }
  if (env_js.isNode) {
    const Agent = getAgent__default["default"](url);
    agent = opts.agent || new Agent({
      keepAlive: true,
      maxSockets: 6
    });
  }
  return {
    ...opts,
    host: url.host,
    protocol: url.protocol.replace(':', ''),
    port: Number(url.port),
    apiPath: url.pathname,
    url,
    agent
  };
};
const errorHandler = async response => {
  let msg;
  try {
    if ((response.headers.get('Content-Type') || '').startsWith('application/json')) {
      const data = await response.json();
      log(data);
      msg = data.Message || data.message;
    } else {
      msg = await response.text();
    }
  } catch (err) {
    log('Failed to parse error response', err);
    msg = err.message;
  }
  let error = new HTTP__default["default"].HTTPError(response);
  if (msg) {
    if (msg.includes('deadline has elapsed')) {
      error = new HTTP__default["default"].TimeoutError();
    }
    if (msg && msg.includes('context deadline exceeded')) {
      error = new HTTP__default["default"].TimeoutError();
    }
  }
  if (msg && msg.includes('request timed out')) {
    error = new HTTP__default["default"].TimeoutError();
  }
  if (msg) {
    error.message = msg;
  }
  throw error;
};
const KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g;
const kebabCase = str => {
  return str.replace(KEBAB_REGEX, function (match) {
    return '-' + match.toLowerCase();
  });
};
const parseTimeout = value => {
  return typeof value === 'string' ? parseDuration__default["default"](value) : value;
};
class Client extends HTTP__default["default"] {
  constructor(options = {}) {
    const opts = normalizeOptions(options);
    super({
      timeout: parseTimeout(opts.timeout || 0) || undefined,
      headers: opts.headers,
      base: `${ opts.url }`,
      handleError: errorHandler,
      transformSearchParams: search => {
        const out = new URLSearchParams();
        for (const [key, value] of search) {
          if (value !== 'undefined' && value !== 'null' && key !== 'signal') {
            out.append(kebabCase(key), value);
          }
          if (key === 'timeout' && !isNaN(value)) {
            out.append(kebabCase(key), value);
          }
        }
        return out;
      },
      agent: opts.agent
    });
    delete this.get;
    delete this.put;
    delete this.delete;
    delete this.options;
    const fetch = this.fetch;
    this.fetch = (resource, options = {}) => {
      if (typeof resource === 'string' && !resource.startsWith('/')) {
        resource = `${ opts.url }/${ resource }`;
      }
      return fetch.call(this, resource, merge(options, { method: 'POST' }));
    };
  }
}
const HTTPError = HTTP__default["default"].HTTPError;

exports.Client = Client;
exports.HTTPError = HTTPError;
exports.errorHandler = errorHandler;
