import { sha256, md5 } from "node-forge";
import { generateRandomKey } from "../utils/utils";
import * as secp256k1 from '@noble/secp256k1';

const worker = new Worker(new URL('./crypto.worker.ts', import.meta.url), { type: 'module' });

export const encodeWithPassword = async (password : string, data : any) : Promise<any> => {
    let task = generateRandomKey(16);
    return new Promise((resolve, _) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'encodeWithPasswordResult' && event.data.task === task) {
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'encodeWithPassword', data: { password, payload: data, task } });
    });
}

export const decodeWithPassword = (password : string, data : any) : Promise<any> => {
    let task = generateRandomKey(16);
    return new Promise((resolve, reject) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'decodeWithPasswordResult' && event.data.task === task) {
                if(event.data.result === null){
                    reject("Decryption failed");
                    return;
                }
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'decodeWithPassword', data: { password, payload: data, task } });
    });
}

export const generateKeyPairFromSeed = async (seed : string) => {
    //generate key pair using secp256k1 includes privatekey from seed
    const privateKey = sha256.create().update(seed).digest().toHex().toString();
    const publicKey = secp256k1.getPublicKey(Buffer.from(privateKey, "hex"), true);
    return {
        privateKey: privateKey,
        publicKey: Buffer.from(publicKey).toString('hex'),
    };

}

export const encrypt = async (data : string, publicKey : string) : Promise<any>  => {
    let task = generateRandomKey(16);
    return new Promise((resolve, _) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'encryptResult' && event.data.task === task) {
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'encrypt', data: { publicKey, payload: data, task } });
    });
}

export const decrypt = async (data : string, privateKey : string) : Promise<any> => {
    let task = generateRandomKey(16);
    return new Promise((resolve, reject) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'decryptResult' && event.data.task === task) {
                if(event.data.result === null){
                    reject("Decryption failed");
                    return;
                }
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'decrypt', data: { privateKey, payload: data, task } });
    });
}

export const chacha20Encrypt = async (data : string) => {
    let task = generateRandomKey(16);
    return new Promise((resolve, _) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'chacha20EncryptResult' && event.data.task === task) {
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'chacha20Encrypt', data: { payload: data, task } });
    });
}

export const chacha20Decrypt = async (ciphertext : string, nonce : string, key : string) => {
    let task = generateRandomKey(16);
    return new Promise((resolve, _) => {
        worker.addEventListener('message', (event: MessageEvent) => {
            if (event.data.action === 'chacha20DecryptResult' && event.data.task === task) {
                resolve(event.data.result);
            }
        });
        worker.postMessage({ action: 'chacha20Decrypt', data: { ciphertext, nonce, key, task } });
    });
}

export const generateMd5 = async (data : string) => {
    const hash = md5.create();
    hash.update(data);
    return hash.digest().toHex();
}

export const generateHashFromPrivateKey = async (privateKey : string) => {
    return sha256.create().update(privateKey + "rosetta").digest().toHex().toString();
}

export const isEncodedWithPassword = (data : string) => {
    try{
        atob(data).split(":");
        return true;
    } catch(e) {
        return false;
    }
}
