import crypto from 'crypto'
import { BN, toBN } from 'web3-utils'

import { pedersen } from '@/services'

const CUT_LENGTH = 31

export function parseNote(note) {
  const [, currency, amount, netId, hexNote] = note.split('-')

  return {
    ...parseHexNote(hexNote),
    netId,
    amount,
    currency
  }
}

export function parseHexNote(hexNote) {
  const buffNote = Buffer.from(hexNote.slice(2), 'hex')

  const commitment = buffPedersenHash(buffNote)

  const nullifierBuff = buffNote.slice(0, CUT_LENGTH)
  const nullifierHash = BigInt(buffPedersenHash(nullifierBuff))
  const nullifier = BigInt(leInt2Buff(buffNote.slice(0, CUT_LENGTH)))

  const secret = BigInt(leInt2Buff(buffNote.slice(CUT_LENGTH, CUT_LENGTH * 2)))

  return {
    secret,
    nullifier,
    commitment,
    nullifierBuff,
    nullifierHash,
    commitmentHex: toFixedHex(commitment),
    nullifierHex: toFixedHex(nullifierHash)
  }
}

export function leInt2Buff(value) {
  return new BN(value, 16, 'le')
}

export function randomBN(nbytes = 31) {
  return toBN(leInt2Buff(crypto.randomBytes(nbytes)).toString())
}

export function buffPedersenHash(buffer) {
  const [hash] = pedersen.unpackPoint(buffer)
  return pedersen.toStringBuffer(hash)
}

export function toFixedHex(value, length = 32) {
  const isBuffer = value instanceof Buffer

  const str = isBuffer ? value.toString('hex') : BigInt(value).toString(16)
  return '0x' + str.padStart(length * 2, '0')
}

export const isEmptyArray = (arr) => !Array.isArray(arr) || !arr.length

export function packEncryptedMessage(encryptedMessage) {
  const nonceBuf = Buffer.from(encryptedMessage.nonce, 'base64')
  const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, 'base64')
  const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, 'base64')
  const messageBuff = Buffer.concat([
    Buffer.alloc(24 - nonceBuf.length),
    nonceBuf,
    Buffer.alloc(32 - ephemPublicKeyBuf.length),
    ephemPublicKeyBuf,
    ciphertextBuf
  ])
  return '0x' + messageBuff.toString('hex')
}

export function unpackEncryptedMessage(encryptedMessage) {
  if (encryptedMessage.slice(0, 2) === '0x') {
    encryptedMessage = encryptedMessage.slice(2)
  }
  const messageBuff = Buffer.from(encryptedMessage, 'hex')
  const nonceBuf = messageBuff.slice(0, 24)
  const ephemPublicKeyBuf = messageBuff.slice(24, 56)
  const ciphertextBuf = messageBuff.slice(56)
  return {
    version: 'x25519-xsalsa20-poly1305',
    nonce: nonceBuf.toString('base64'),
    ephemPublicKey: ephemPublicKeyBuf.toString('base64'),
    ciphertext: ciphertextBuf.toString('base64')
  }
}

export function checkCommitments(events = []) {
  events.forEach(({ leafIndex }, i) => {
    // TODO reload events, need for if infura provider missing events
    if (leafIndex !== i) {
      console.error(`Missing deposit event for deposit #${i}`)
      throw new Error(window.$nuxt.$t('failedToFetchAllDepositEvents'))
    }
  })
}