var compat = require('./browser')
var crypto = require('crypto')
var fork = require('child_process').fork
var path = require('path')

var MAX_ALLOC = Math.pow(2, 30) - 1 // default in iojs

function asyncPBKDF2 (password, salt, iterations, keylen, digest, callback) {
  if (typeof iterations !== 'number') {
    throw new TypeError('Iterations not a number')
  }

  if (iterations < 0) {
    throw new TypeError('Bad iterations')
  }

  if (typeof keylen !== 'number') {
    throw new TypeError('Key length not a number')
  }

  if (keylen < 0 || keylen > MAX_ALLOC) {
    throw new TypeError('Bad key length')
  }

  if (typeof password === 'string') {
    password = new Buffer(password, 'binary')
  }

  if (typeof salt === 'string') {
    salt = new Buffer(salt, 'binary')
  }

  var child = fork(path.resolve(__dirname, 'async-shim.js'))

  child.on('message', function (result) {
    if (result.type === 'success') {
      callback(null, new Buffer(result.data, 'hex'))
    } else if (result.type === 'fail') {
      callback(new TypeError(result.data))
    }
  })

  child.send({
    password: password.toString('hex'),
    salt: salt.toString('hex'),
    iterations: iterations,
    keylen: keylen,
    digest: digest
  })
}

exports.pbkdf2Sync = function pbkdf2Sync (password, salt, iterations, keylen, digest) {
  digest = digest || 'sha1'

  if (isNode10()) {
    if (digest === 'sha1') {
      return crypto.pbkdf2Sync(password, salt, iterations, keylen)
    } else {
      return compat.pbkdf2Sync(password, salt, iterations, keylen, digest)
    }
  } else {
    return crypto.pbkdf2Sync(password, salt, iterations, keylen, digest)
  }
}

exports.pbkdf2 = function pbkdf2 (password, salt, iterations, keylen, digest, callback) {
  if (typeof digest === 'function') {
    callback = digest
    digest = 'sha1'
  }

  if (isNode10()) {
    if (digest === 'sha1') {
      return crypto.pbkdf2(password, salt, iterations, keylen, callback)
    } else {
      return asyncPBKDF2(password, salt, iterations, keylen, digest, callback)
    }
  } else {
    return crypto.pbkdf2(password, salt, iterations, keylen, digest, callback)
  }
}

var sha1 = '0c60c80f961f0e71f3a9b524af6012062fe037a6e0f0eb94fe8fc46bdc637164'
var isNode10Result

function isNode10 () {
  if (typeof isNode10Result === 'undefined') {
    isNode10Result = crypto.pbkdf2Sync('password', 'salt', 1, 32, 'sha256').toString('hex') === sha1
  }

  return isNode10Result
}
