// Native
const {parse} = require('url')
const http = require('http')
const https = require('https')

// Packages
const fetch = require('node-fetch')

/**
 * Returns a `fetch` version with a similar
 * API to the browser's configured with a
 * HTTP2 agent.
 *
 * It encodes `body` automatically as JSON.
 *
 * @param {String} host
 * @return {Function} fetch
 */

module.exports = class Agent {
  constructor(url, {tls = true, debug} = {}) {
    this._url = url
    const parsed = parse(url)
    this._protocol = parsed.protocol
    this._debug = debug
    if (tls) {
      this._initAgent()
    }
  }

  _initAgent() {
    const module = this._protocol === 'https:' ? https : http
    const agent = this._agent = new module.Agent({
      keepAlive: true,
      keepAliveMsecs: 10000,
      maxSockets: 8
    }).on('error', err => this._onError(err, agent))
  }

  _onError(err, agent) {
    if (this._debug) {
      console.log(`> [debug] agent connection error ${err}\n${err.stack}`)
    }
    if (this._agent === agent) {
      this._agent = null
    }
  }

  fetch(path, opts = {}) {
    if (!this._agent) {
      if (this._debug) {
        console.log('> [debug] re-initializing agent')
      }
      this._initAgent()
    }

    const {body} = opts
    if (this._agent) {
      opts.agent = this._agent
    }

    if (body && typeof body === 'object' && typeof body.pipe !== 'function') {
      opts.headers['Content-Type'] = 'application/json'
      opts.body = JSON.stringify(body)
    }

    if (opts.body && typeof body.pipe !== 'function') {
      opts.headers['Content-Length'] = Buffer.byteLength(opts.body)
    }

    return fetch(this._url + path, opts)
  }

  close() {
    if (this._debug) {
      console.log('> [debug] closing agent')
    }

    if (this._agent) {
      this._agent.destroy()
    }
  }
}