'use strict'

var fs = require('fs') var qs = require('querystring') var validate = require('har-validator') var extend = require('extend')

function Har (request) {

this.request = request

}

Har.prototype.reducer = function (obj, pair) {

// new property ?
if (obj[pair.name] === undefined) {
  obj[pair.name] = pair.value
  return obj
}

// existing? convert to array
var arr = [
  obj[pair.name],
  pair.value
]

obj[pair.name] = arr

return obj

}

Har.prototype.prep = function (data) {

// construct utility properties
data.queryObj = {}
data.headersObj = {}
data.postData.jsonObj = false
data.postData.paramsObj = false

// construct query objects
if (data.queryString && data.queryString.length) {
  data.queryObj = data.queryString.reduce(this.reducer, {})
}

// construct headers objects
if (data.headers && data.headers.length) {
  // loweCase header keys
  data.headersObj = data.headers.reduceRight(function (headers, header) {
    headers[header.name] = header.value
    return headers
  }, {})
}

// construct Cookie header
if (data.cookies && data.cookies.length) {
  var cookies = data.cookies.map(function (cookie) {
    return cookie.name + '=' + cookie.value
  })

  if (cookies.length) {
    data.headersObj.cookie = cookies.join('; ')
  }
}

// prep body
function some (arr) {
  return arr.some(function (type) {
    return data.postData.mimeType.indexOf(type) === 0
  })
}

if (some([
  'multipart/mixed',
  'multipart/related',
  'multipart/form-data',
  'multipart/alternative'])) {
  // reset values
  data.postData.mimeType = 'multipart/form-data'
} else if (some([
  'application/x-www-form-urlencoded'])) {
  if (!data.postData.params) {
    data.postData.text = ''
  } else {
    data.postData.paramsObj = data.postData.params.reduce(this.reducer, {})

    // always overwrite
    data.postData.text = qs.stringify(data.postData.paramsObj)
  }
} else if (some([
  'text/json',
  'text/x-json',
  'application/json',
  'application/x-json'])) {
  data.postData.mimeType = 'application/json'

  if (data.postData.text) {
    try {
      data.postData.jsonObj = JSON.parse(data.postData.text)
    } catch (e) {
      this.request.debug(e)

      // force back to text/plain
      data.postData.mimeType = 'text/plain'
    }
  }
}

return data

}

Har.prototype.options = function (options) {

// skip if no har property defined
if (!options.har) {
  return options
}

var har = {}
extend(har, options.har)

// only process the first entry
if (har.log && har.log.entries) {
  har = har.log.entries[0]
}

// add optional properties to make validation successful
har.url = har.url || options.url || options.uri || options.baseUrl || '/'
har.httpVersion = har.httpVersion || 'HTTP/1.1'
har.queryString = har.queryString || []
har.headers = har.headers || []
har.cookies = har.cookies || []
har.postData = har.postData || {}
har.postData.mimeType = har.postData.mimeType || 'application/octet-stream'

har.bodySize = 0
har.headersSize = 0
har.postData.size = 0

if (!validate.request(har)) {
  return options
}

// clean up and get some utility properties
var req = this.prep(har)

// construct new options
if (req.url) {
  options.url = req.url
}

if (req.method) {
  options.method = req.method
}

if (Object.keys(req.queryObj).length) {
  options.qs = req.queryObj
}

if (Object.keys(req.headersObj).length) {
  options.headers = req.headersObj
}

function test (type) {
  return req.postData.mimeType.indexOf(type) === 0
}
if (test('application/x-www-form-urlencoded')) {
  options.form = req.postData.paramsObj
} else if (test('application/json')) {
  if (req.postData.jsonObj) {
    options.body = req.postData.jsonObj
    options.json = true
  }
} else if (test('multipart/form-data')) {
  options.formData = {}

  req.postData.params.forEach(function (param) {
    var attachment = {}

    if (!param.fileName && !param.fileName && !param.contentType) {
      options.formData[param.name] = param.value
      return
    }

    // attempt to read from disk!
    if (param.fileName && !param.value) {
      attachment.value = fs.createReadStream(param.fileName)
    } else if (param.value) {
      attachment.value = param.value
    }

    if (param.fileName) {
      attachment.options = {
        filename: param.fileName,
        contentType: param.contentType ? param.contentType : null
      }
    }

    options.formData[param.name] = attachment
  })
} else {
  if (req.postData.text) {
    options.body = req.postData.text
  }
}

return options

}

exports.Har = Har