import crypto from 'crypto'
import * as base64UrlSafe from './base64urlsafe.mjs'
import defaults from '../defaults.mjs'

export default function encode(orgHeader, orgBody, privateKeyPassword = null, disableAutofill = false) {
  if (
    typeof orgHeader !== 'object' ||
    typeof orgBody !== 'object'
  ) {
    throw new Error('both header and body should be of type object')
  }

  let header = defaults(orgHeader)
  let body = defaults(orgBody)

  if (!header.alg) {
    header.alg = 'HS256'
  }
  if (!header.typ) {
    header.typ = 'JWT'
  }

  let hmacAlgo = null
  switch (header.alg) {
    case 'HS256':
      hmacAlgo = 'sha256'
      break
    case 'HS384':
      hmacAlgo = 'sha384'
      break
    case 'HS512':
      hmacAlgo = 'sha512'
      break
    default:
      throw new Error(
        'Only alg HS256, HS384 and HS512 are supported'
      )
  }

  if (!body.iat && !disableAutofill) {
    body.iat = Math.floor(Date.now() / 1000)
  }
  if (!body.exp && !disableAutofill) {
    body.exp = body.iat + 300
  }

  // Base64 encode header and body
  let headerBase64 = base64UrlSafe.encode(Buffer.from(JSON.stringify(header)))
  let bodyBase64 = base64UrlSafe.encode(Buffer.from(JSON.stringify(body)))
  let headerBodyBase64 = headerBase64 + '.' + bodyBase64

  const hmac = crypto.createHmac(hmacAlgo, privateKeyPassword)
  hmac.update(headerBodyBase64)
  let signatureBuffer = hmac.digest()

  // Construct final JWT
  let signatureBase64 = base64UrlSafe.encode(signatureBuffer)
  return headerBodyBase64 + '.' + signatureBase64
}