'use strict';

var Duplex = require('readable-stream').Duplex;
var _ = require('lodash/core');

module.exports = function(params, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open(params.method, params.url);
  if (params.headers) {
    for (var header in params.headers) {
      xhr.setRequestHeader(header, params.headers[header]);
    }
  }
  xhr.setRequestHeader("Accept", "*/*");
  var response;
  var str = new Duplex();
  str._read = function(size) {
    if (response) {
      str.push(response.body);
    }
  };
  var bufs = [];
  var sent = false;
  str._write = function(chunk, encoding, callback) {
    bufs.push(chunk.toString(encoding === "buffer" ? "binary" : encoding));
    callback();
  };
  str.on('finish', function() {
    if (!sent) {
      xhr.send(bufs.join(''));
      sent = true;
    }
  });
  if (params.body || params.body === "" || !/^(put|post|patch)$/i.test(params.method)) {
    xhr.send(params.body);
    sent = true;
  }
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      var headerNames = getResponseHeaderNames(xhr);
      var headers = {};
      _.forEach(headerNames, function(headerName) {
        if (headerName) {
          headers[headerName] = xhr.getResponseHeader(headerName);
        }
      });
      response = {
        statusCode: xhr.status,
        headers: headers,
        body: xhr.response
      };
      if (!response.statusCode) {
        response.statusCode = 400;
        response.body = "Access Declined";
      }
      if (callback) {
        callback(null, response, response.body);
      }
      str.end();
    }
  };
  return str;
};

function getResponseHeaderNames(xhr) {
  var headerLines = (xhr.getAllResponseHeaders() || "").split(/[\r\n]+/);
  return _.map(headerLines, function(headerLine) {
    return headerLine.split(/\s*:/)[0].toLowerCase();
  });
}
