import crypto from 'crypto'

export async function encrypt(seed: string, password: string) {
    const salt = crypto.randomBytes(16)
    const iv = crypto.randomBytes(12)

    const key = await new Promise<Buffer>((resolve, reject) => {
        crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => {
            if (err) reject(err)
            else resolve(derivedKey as Buffer)
        })
    })

    const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)
    const ciphertext = Buffer.concat([cipher.update(seed, 'utf8'), cipher.final()])
    const authTag = cipher.getAuthTag()

    const encryptedMnemonic = Buffer.concat([salt, iv, authTag, ciphertext]).toString('hex')

    const keystore = {
        type: 'neptune-wallet',
        encryption: 'aes-256-gcm',
        version: 1,
        wallet: {
            mnemonic: encryptedMnemonic,
        },
    }

    return JSON.stringify(keystore, null, 2)
}

export async function fromEncryptedJson(json: string, password: string) {
    const data = JSON.parse(json)
    const encrypted = Buffer.from(data.wallet.mnemonic, 'hex')

    const salt = encrypted.subarray(0, 16)
    const iv = encrypted.subarray(16, 28)
    const authTag = encrypted.subarray(28, 44)
    const ciphertext = encrypted.subarray(44)

    const key = await new Promise<Buffer>((resolve, reject) => {
        crypto.scrypt(password, salt, 32, { N: 16384, r: 8, p: 1 }, (err, derivedKey) => {
            if (err) reject(err)
            else resolve(derivedKey as Buffer)
        })
    })

    const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)
    decipher.setAuthTag(authTag)

    const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
    return decrypted.toString('utf8')
}
