var apx = apx || {};

apx.crypto = apx.crypto || {};

apx.crypto.genKey = async (uuid) => {
    return await openpgp.generateKey({
        type: "ecc",
        curve: "curve25519",
        userIDs: [
            {
                alias: uuid,
            },
        ],
        passphrase: "",
        format: "armored",
    });
};

apx.crypto.encryptMessage = async (message, publicKey) => {
    publicKey = await openpgp.readKey({
        armoredKey: publicKey,
    });

    return await openpgp.encrypt({
        message: await openpgp.createMessage({
            text: message,
        }),
        encryptionKeys: publicKey,
    });
};

apx.crypto.decryptMessage = async (encryptedMessage, privateKey) => {
    privateKey = await openpgp.readPrivateKey({
        armoredKey: privateKey,
    });

    const message = await openpgp.readMessage({
        armoredMessage: encryptedMessage,
    });

    return await openpgp.decrypt({
        message,
        decryptionKeys: privateKey,
    });
};

apx.crypto.isSignedby = async (
    alias,
    publicKey,
    detachedSignature,
    message
) => {
    const publickey = await openpgp.readKey({ armoredKey: publicKey });
    const msg = await openpgp.createMessage({ text: message });
    const signature = await openpgp.readSignature({
        armoredSignature: atob(detachedSignature), // parse detached signature
    });
    const verificationResult = await openpgp.verify({
        msg, // Message object
        signature,
        verificationKeys: publickey,
    });
    const { verified, keyID } = verificationResult.signatures[0];
    try {
        await verified; // throws on invalid signature
        //console.log("Signed by key id " + keyID.toHex());
        return KeyId.toHex().alias == alias;
    } catch (e) {
        console.log("Signature could not be verified: " + e.message);
        return false;
    }
};

apx.crypto.sign = async (message, privateKey) => {
    privateKey = await openpgp.readPrivateKey(
        {
            armoredKey: privateKey
        }
    );

    return await openpgp.sign(
        {
            message: await openpgp.createMessage(
                {
                    text: message
                }
            ),
            signingKeys: privateKey
        }
    );
};

apx.crypto.verifySignature = async (message, signature, publicKey) => {
    publicKey = await openpgp.readKey(
        {
            armoredKey: publicKey
        }
    );

    const verified = await openpgp.verify(
        {
            message: await openpgp.createMessage(
                {
                    text: message
                }
            ),
            signature: await openpgp.readSignature(
                {
                    armoredSignature: signature
                }
            ),
            verificationKeys: publicKey
        }
    );

    if (await verified.signatures[0].verified) {
        return true;
    } else {
        return false;
    };
};

apx.crypto.genUUID = () => {
    const uuidTemplate = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
    return uuidTemplate.replace(/[xy]/g, (char) => {
        const random = Math.random() * 16 | 0;
        
        let value;

        if (char === "x") {
            value = random;
        } else {
            value = (random & 0x3) | 0x8;
        };

        return value.toString(16);
    });
};