import crypto from 'crypto'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as xxh from 'xxhashjs'

const HEXBASE = 16

const defaultHashOptions = {
  method: 'xxhash32',
  shrink: 8,
  append: false
}

const getxxhash = (content, options) => {
  const hashFunc = options.method === 'xxhash32' ? xxh.h32 : xxh.h64
  const seed = 0

  return hashFunc(seed)
    .update(content)
    .digest()
    .toString(HEXBASE)
}

const getHash = (content, options) => {
  if (options.method && typeof options.method === 'function') {
    return options.method(content)
  }

  if (options.method && options.method.indexOf('xxhash') === 0) {
    return getxxhash(content, options)
  }

  try {
    const hashFunc = crypto.createHash(options.method)

    return hashFunc.update(content).digest('hex')
  } catch (e) {
    return null
  }
}

function hash (content, options) {
  options = options || defaultHashOptions

  let hash = getHash(content, options)

  if (hash == null) {
    // bad hash method fallback to defaults
    // TODO: warning/error reporting?
    hash = getHash(content, defaultHashOptions)
  }

  return options.shrink ? hash.substr(0, options.shrink) : hash
}

export default (file, options?: any) => {
  const content = fs.readFileSync(file)
  const ext = path.extname(file)
  return hash(content, options) + ext
}
