import { EventEmitter } from 'events';
import fs from 'fs';

class Curl extends EventEmitter {
  constructor() {
    super();
    this._options = {};
    this._meta = {};
    this._features = {};
  }

  static getVersion() {
    return 'libcurl/7.54.0 LibreSSL/2.0.20 zlib/1.2.11 nghttp2/1.24.0';
  }

  enable(name) {
    this._features[name] = true;
  }

  setUrl(url) {
    this.setOpt(Curl.option.URL, url);
  }

  setOpt(name, value) {
    if (!name) {
      throw new Error(`Invalid option ${name} ${value}`);
    }

    if (name === Curl.option.CAINFO) {
      // Just ignore this because it's platform-specific
      return;
    }

    if (name === Curl.option.READFUNCTION) {
      let body = '';
      // Only limiting this to prevent infinite loops
      for (let i = 0; i < 1000; i++) {
        const buffer = Buffer.alloc(23);
        const bytes = value(buffer);
        if (bytes === 0) {
          break;
        }
        body += buffer.slice(0, bytes);
      }

      this._meta[`${name}_VALUE`] = body;
    }

    if (name === Curl.option.COOKIELIST) {
      // This can be set multiple times
      this._options[name] = this._options[name] || [];
      this._options[name].push(value);
    } else if (name === Curl.option.READDATA) {
      const { size } = fs.fstatSync(value);
      const buffer = Buffer.alloc(size);
      fs.readSync(value, buffer, 0, size, 0);
      this._options[name] = buffer.toString();
    } else {
      this._options[name] = value;
    }
  }

  getInfo(name) {
    switch (name) {
      case Curl.info.COOKIELIST:
        return [`#HttpOnly_.insomnia.rest\tTRUE\t/url/path\tTRUE\t${Date.now() / 1000}\tfoo\tbar`];
      case Curl.info.EFFECTIVE_URL:
        return this._options[Curl.option.URL];
      case Curl.info.TOTAL_TIME:
        return 700;
      case Curl.info.SIZE_DOWNLOAD:
        return 800;
      default:
        throw new Error(`Invalid info ${name}`);
    }
  }

  perform() {
    process.nextTick(() => {
      const data = Buffer.from(
        JSON.stringify({
          options: this._options,
          meta: this._meta,
          features: this._features,
        }),
      );

      this.emit('data', data);
      this._options.WRITEFUNCTION(data);

      process.nextTick(() => {
        this.emit(
          'end',
          'NOT_USED',
          'NOT_USED',
          [
            'HTTP/1.1 200 OK',
            `Content-Length: ${data.length}`,
            'Content-Type: application/json',
            '',
          ].join('\n'),
        );
      });
    });
  }

  close() {}
}

Curl.info = {
  COOKIELIST: 'COOKIELIST',
  EFFECTIVE_URL: 'EFFECTIVE_URL',
  SIZE_DOWNLOAD: 'SIZE_DOWNLOAD',
  TOTAL_TIME: 'TOTAL_TIME',
  debug: {
    DATA_IN: 'DATA_IN',
    DATA_OUT: 'DATA_OUT',
    SSL_DATA_IN: 'SSL_DATA_IN',
    SSL_DATA_OUT: 'SSL_DATA_OUT',
    TEXT: 'TEXT',
  },
};

Curl.auth = {
  ANY: 'ANY',
};

Curl.netrc = {
  IGNORED: 0,
  OPTIONAL: 1,
  REQUIRED: 2,
};

Curl.feature = {
  NO_HEADER_PARSING: 'NO_HEADER_PARSING',
  NO_DATA_PARSING: 'NO_DATA_PARSING',
};

Curl.option = {
  ACCEPT_ENCODING: 'ACCEPT_ENCODING',
  CAINFO: 'CAINFO',
  COOKIEFILE: 'COOKIEFILE',
  COOKIELIST: 'COOKIELIST',
  CUSTOMREQUEST: 'CUSTOMREQUEST',
  DEBUGFUNCTION: 'DEBUGFUNCTION',
  FOLLOWLOCATION: 'FOLLOWLOCATION',
  HTTPAUTH: 'HTTPAUTH',
  HTTPGET: 'HTTPGET',
  HTTPHEADER: 'HTTPHEADER',
  HTTPPOST: 'HTTPPOST',
  INFILESIZE_LARGE: 'INFILESIZE_LARGE',
  KEYPASSWD: 'KEYPASSWD',
  MAXREDIRS: 'MAXREDIRS',
  NETRC: 'NETRC',
  NOBODY: 'NOBODY',
  NOPROGRESS: 'NOPROGRESS',
  NOPROXY: 'NOPROXY',
  PASSWORD: 'PASSWORD',
  POST: 'POST',
  POSTFIELDS: 'POSTFIELDS',
  PROXY: 'PROXY',
  PROXYAUTH: 'PROXYAUTH',
  READDATA: 'READDATA',
  READFUNCTION: 'READFUNCTION',
  SSLCERT: 'SSLCERT',
  SSLCERTTYPE: 'SSLCERTTYPE',
  SSLKEY: 'SSLKEY',
  SSL_VERIFYHOST: 'SSL_VERIFYHOST',
  SSL_VERIFYPEER: 'SSL_VERIFYPEER',
  TIMEOUT_MS: 'TIMEOUT_MS',
  UNIX_SOCKET_PATH: 'UNIX_SOCKET_PATH',
  UPLOAD: 'UPLOAD',
  URL: 'URL',
  USERAGENT: 'USERAGENT',
  USERNAME: 'USERNAME',
  VERBOSE: 'VERBOSE',
  WRITEFUNCTION: 'WRITEFUNCTION',
  XFERINFOFUNCTION: 'XFERINFOFUNCTION',
};

module.exports = {
  Curl: Curl,
};
