"use strict";

import { arrayify, BytesLike, hexlify } from "@ethersproject/bytes";
import { computeHmac, SupportedAlgorithm } from "@ethersproject/sha2";

export function pbkdf2(password: BytesLike, salt: BytesLike, iterations: number, keylen: number, hashAlgorithm: string): string {
    password = arrayify(password);
    salt = arrayify(salt);
    let hLen;
    let l = 1;
    const DK = new Uint8Array(keylen)
    const block1 = new Uint8Array(salt.length + 4)
    block1.set(salt);
    //salt.copy(block1, 0, 0, salt.length)

    let r: number;
    let T: Uint8Array;

    for (let i = 1; i <= l; i++) {
        //block1.writeUInt32BE(i, salt.length)
        block1[salt.length] = (i >> 24) & 0xff;
        block1[salt.length + 1] = (i >> 16) & 0xff;
        block1[salt.length + 2] = (i >> 8) & 0xff;
        block1[salt.length + 3] = i & 0xff;

        //let U = createHmac(password).update(block1).digest();
        let U = arrayify(computeHmac(<SupportedAlgorithm>hashAlgorithm, password, block1));

        if (!hLen) {
            hLen = U.length
            T = new Uint8Array(hLen)
            l = Math.ceil(keylen / hLen)
            r = keylen - (l - 1) * hLen
        }

        //U.copy(T, 0, 0, hLen)
        T.set(U);


        for (let j = 1; j < iterations; j++) {
            //U = createHmac(password).update(U).digest();
            U = arrayify(computeHmac(<SupportedAlgorithm>hashAlgorithm, password, U));
            for (let k = 0; k < hLen; k++) T[k] ^= U[k]
        }


        const destPos = (i - 1) * hLen
        const len = (i === l ? r : hLen)
        //T.copy(DK, destPos, 0, len)
        DK.set(arrayify(T).slice(0, len), destPos);
    }

    return hexlify(DK)
}

