import * as CryptoJS from 'crypto-js';
import {gzip} from 'pako/lib/deflate';
import {ECKCDSA} from './ec-kcdsa';
import {Converter} from './converter';
import {EncryptedData} from './typings/encryptedData';

const IV_LENGTH = 16;
const SHARED_KEY_SIZE = 32;

function encrypt(plaintext: Uint8Array, nonce: Uint8Array, sharedKeyOrig: any[]) {

    const sharedKey = sharedKeyOrig.slice(0);

    for (let i = 0; i < SHARED_KEY_SIZE; i++) {
        // tslint:disable:no-bitwise
        sharedKey[i] ^= nonce[i];
    }

    const key = CryptoJS.SHA256(Converter.convertByteArrayToWordArray(sharedKey));
    const data = Converter.convertByteArrayToWordArray(plaintext);
    const encrypted = CryptoJS.AES.encrypt(data, key, {
        iv: CryptoJS.lib.WordArray.random(IV_LENGTH)
    });

    const ivOut = Converter.convertWordArrayToByteArray(encrypted.iv);
    const ciphertextOut = Converter.convertWordArrayToByteArray(encrypted.ciphertext);

    return ivOut.concat(ciphertextOut);
}


/**
 * Encrypts arbitrary data for P2P message/data exchange using asymmetric encryption
 *
 * @see [[decryptData]]
 * @param plaintext Data to be encrypted
 * @param recipientPublicKeyHex The recipients public key in hexadecimal format
 * @param senderPrivateKeyHex The senders private (agreement) key hexadecimal format
 * @return The encrypted Data
 * @module crypto
 */
export function encryptData(
    plaintext: Uint8Array,
    recipientPublicKeyHex: string,
    senderPrivateKeyHex: string): EncryptedData {

    const sharedKey =
        ECKCDSA.sharedkey(
            Converter.convertHexStringToByteArray(senderPrivateKeyHex),
            Converter.convertHexStringToByteArray(recipientPublicKeyHex)
        );

    const compressedData = gzip(plaintext);
    const randomBytes = CryptoJS.lib.WordArray.random(SHARED_KEY_SIZE);
    const nonce = Converter.convertWordArrayToUint8Array(randomBytes);
    const data = Uint8Array.from(encrypt(compressedData, nonce, sharedKey));

    return {
        nonce,
        data
    };
}
