import { ID } from "./main.js";

export class Packet {
    static _createBase(name) {
        return {
            type: name,
            id: window.crypto.randomUUID(),
            timestamp: Date.now(),
            author: ID,
        };
    }

    static _sign(data) {
        // compute hash of data
        let hash = CryptoJS.SHA3(JSON.stringify(data));
        let res = 0n;
        for (let word32 of hash.words) {
            // remove any sign
            let bi = BigInt.asUintN(32, BigInt(word32));
            res = (res << 32n) | bi;
        }

        // sign hash
        let sig = window.rsa.privKey.decrypt(res);

        // return new packet
        return {
            sig: "0x" + sig.toString(16),
            payload: data,
        };
    }

    static createAnnounce(rsaKeyPair, paillierKeyPair) {
        return this._sign({
            ...this._createBase("ANNOUNCE"),
            rsaPubKey: rsaKeyPair.pubKey.toJSON(),
            paillierPubKey: paillierKeyPair.pubKey.toJSON(),
        });
    }

    static createDisconnect() {
        return this._sign(this._createBase("DISCONNECT"));
    }

    static createKeepAlive() {
        return this._sign(this._createBase("KEEPALIVE"));
    }

    static createSetReady(nowReady) {
        return this._sign({
            ...this._createBase("ACT"),
            action: "READY",
            ready: nowReady,
        });
    }

    static createRandomCyphertext(sessionId, range, cipherText) {
        return this._sign({
            ...this._createBase("RANDOM"),
            session: sessionId,
            range: range,
            stage: "CIPHERTEXT",
            cipherText: cipherText,
        });
    }

    static createRandomKey(sessionId, key) {
        return this._sign({
            ...this._createBase("RANDOM"),
            session: sessionId,
            stage: "DECRYPT",
            cipherKey: key,
        });
    }

    static createBarrierSignal() {
        return this._sign(this._createBase("BARRIER"));
    }

    static createRegionClaim(region, text) {
        return this._sign({
            ...this._createBase("ACT"),
            region: region,
            cipherText: text,
        });
    }

    static createReinforce(regionCipherTexts, verification) {
        return this._sign({
            ...this._createBase("ACT"),
            regions: regionCipherTexts,
            verification: verification,
        });
    }

    static createAction(action, startRegion, endRegion, amount) {
        return this._sign({
            ...this._createBase("ACT"),
            startRegion: startRegion,
            endRegion: endRegion,
            strength: amount,
            action: action,
        });
    }

    static createDefense(amount) {
        return this._sign({
            ...this._createBase("ACT"),
            action: "DEFENSE",
            amount: amount,
        });
    }

    static createEndTurn() {
        return this._sign({
            ...this._createBase("ACT"),
            action: "END",
        });
    }

    static createProofRequest(region) {
        return this._sign({
            ...this._createBase("PROOF"),
            stage: "REQUEST",
            region: region,
        });
    }

    static createProofConjecture(region, plainText, a) {
        return this._sign({
            ...this._createBase("PROOF"),
            stage: "CONJECTURE",
            plainText: plainText,
            a: a,
            region: region,
        });
    }

    static createProofChallenge(region, challenge) {
        return this._sign({
            ...this._createBase("PROOF"),
            stage: "CHALLENGE",
            challenge: challenge,
            region: region,
        });
    }

    static createProof(region, z) {
        return this._sign({
            ...this._createBase("PROOF"),
            stage: "PROOF",
            z: z,
            region: region,
        });
    }
}
