import { AESCipherSIVDeterministic } from "../../base/cipher/aes";
import { AbstractSelfAccountKeyring } from "../../keyring/account_base";
import { PeerAccountKeyring } from "../../keyring/account_peer";
import { AbstractRoomKeyring } from "../../keyring/room_base";
import { AbstractCryptoConfig } from "../base";
import { AccountPairDeriveKeyV1 } from "../common";
import { RoomKeyConfigDumpArgs, RoomKeyConfigLoadArgs } from "./args";
import { makeInfoByteArray } from "../../utility"

/**
 * Room key encryption: AES-SIV
        KEY: 32B from curve25519 scalar_mult -> 64B HKDF by context
        NONCE: none

    Encryption of the keys required for room access. These are always distributed by the owner with P2P encryption
    for other peer accounts.
    NOTE: No LRU cache on derive_key(), room keys are only loaded once and they are unique so there's no benefit.
 */
export class RoomKeyConfigV1 extends AbstractCryptoConfig<RoomKeyConfigLoadArgs, RoomKeyConfigDumpArgs>{

    constructor(never_dump: boolean = false){
        super(1, never_dump);
    }

    public load(args: RoomKeyConfigLoadArgs): Promise<Uint8Array>{
        let cipher = args.cipher.slice(this.version.byteLength);
        
        return this.derive_key(args.self_kr, args.peer_kr, args.room_kr, args.key_version).then((derive_key)=>{
            return AESCipherSIVDeterministic.decrypt(
                cipher, derive_key
            )
        })
    }

    public dump(args: RoomKeyConfigDumpArgs): Promise<Uint8Array>{
        return this.derive_key(args.self_kr, args.peer_kr, args.room_kr, args.key_version).then((derive_key)=>{
            return AESCipherSIVDeterministic.encrypt(
                args.room_kr.get_key(args.key_version),
                derive_key,
                undefined,
                this.version
            );
        })
    }

    public derive_key(
        self_kr: AbstractSelfAccountKeyring,
        peer_kr: PeerAccountKeyring,
        room_kr: AbstractRoomKeyring,
        key_version: string): Promise<Uint8Array>{
            return AccountPairDeriveKeyV1.derive_key(
                self_kr,
                peer_kr,
                makeInfoByteArray(['room-key-', this.version, '-', room_kr.id, '-', key_version]),
                false
            )
        }
}