/* MIGRATION TO CLEAN PRODUCTION DATA
 *
 * the way the passphrases are stored in login_user_backups is inconsistent.
 * we need to try to detect which word list was used and transform it accordingly
 */

import fs from 'fs'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const sodium = require('sodium-native')

const PHRASE_WORD_COUNT = 24
const WORDS = fs
  .readFileSync('src/config/mnemonic.uncompressed_buffer13116.txt')
  .toString()
  .split(',')

const KeyPairEd25519Create = (passphrase: string[]): Buffer[] => {
  if (!passphrase.length || passphrase.length < PHRASE_WORD_COUNT) {
    throw new Error('passphrase empty or to short')
  }

  const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES)
  sodium.crypto_hash_sha512_init(state)

  for (let i = 0; i < PHRASE_WORD_COUNT; i++) {
    const value = Buffer.alloc(8)
    const wordIndex = WORDS.indexOf(passphrase[i])
    value.writeBigInt64LE(BigInt(wordIndex))
    sodium.crypto_hash_sha512_update(state, value)
  }
  // trailing space is part of the login_server implementation
  const clearPassphrase = passphrase.slice(0, PHRASE_WORD_COUNT).join(' ') + ' '
  sodium.crypto_hash_sha512_update(state, Buffer.from(clearPassphrase))
  const outputHashBuffer = Buffer.alloc(sodium.crypto_hash_sha512_BYTES)
  sodium.crypto_hash_sha512_final(state, outputHashBuffer)

  const pubKey = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES)
  const privKey = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES)

  sodium.crypto_sign_seed_keypair(
    pubKey,
    privKey,
    outputHashBuffer.slice(0, sodium.crypto_sign_SEEDBYTES),
  )

  return [pubKey, privKey]
}

export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
  // Delete data with no reference in login_users table
  // eslint-disable-next-line no-console
  // 663 affected rows
  const userBackups = await queryFn(
    `SELECT passphrase, LOWER(HEX(pubkey)) as pubkey, user_id
     FROM login_user_backups
     LEFT JOIN login_users ON login_user_backups.user_id = login_users.id
     WHERE user_id=1503`,
     // WHERE pubkey is not null`, // todo fix this condition and regenerate
  )
  let i = 0
  // eslint-disable-next-line no-console
  userBackups.forEach(async (userBackup) => {
    const passphrase = userBackup.passphrase.split(' ')
    const keyPair = KeyPairEd25519Create(passphrase)
    if (keyPair[0].toString('hex') !== userBackup.pubkey) {
      i++
      // eslint-disable-next-line no-console
      console.log(
        'Missmatch Pubkey',
        i,
        userBackup.user_id,
        `"${userBackup.passphrase}"`,
        `"${keyPair[0].toString('hex')}`,
        `"${userBackup.pubkey}"`,
      )
    } else {
      // eslint-disable-next-line no-console
      // console.log('SUCCESS: ', `"${keyPair[0].toString('hex')}`, `"${userBackup.pubkey}"`)
    }
  })
}

export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
  return [] // cannot transform things back
}