import { AbstractCryptoConfig } from '../base';
import { AccountConfigLoadArgs, AccountConfigDumpArgs } from '../account/args';
import { AbstractSelfAccountKeyring } from '../../keyring/account_base';
import { AESCipherSIVNonce96 } from '../../base/cipher/aes';
import { AccountMasterDeriveKeyV1 } from '../common';
import { makeInfoByteArray } from '../../utility';

/**
 * Account-private data encryption: AES-SIV
        KEY: 32B master key -> 64B HKDF by context
        NONCE: 12B random

    Key rotation is not necessary, no account will exhaust the safe usage limits of a key. If there would be
    some special account data that could potentially lead to exhaustion, then that shall be encrypted with a
    different context where time windowing is present.
    NOTE: Small LRU cache on derive_key(). This is used many times, but there's not many different values.
 */
export class AccountConfigV1 extends AbstractCryptoConfig<
  AccountConfigLoadArgs,
  AccountConfigDumpArgs
> {
  public constructor(never_dump: boolean = false) {
    super(1, never_dump);
  }

  public load(args: AccountConfigLoadArgs): Promise<Uint8Array> {
    return this.derive_key(args.self_kr).then((derive_key) => {
      return AESCipherSIVNonce96.decrypt(args.cipher.slice(this.version.byteLength), derive_key);
    });
  }

  public dump(args: AccountConfigDumpArgs): Promise<Uint8Array> {
    return this.derive_key(args.self_kr).then((derive_key) => {
      return AESCipherSIVNonce96.encrypt(
        args.plain,
        derive_key,
        undefined,
        undefined,
        this.version
      );
    });
  }

  public derive_key(self_kr: AbstractSelfAccountKeyring): Promise<Uint8Array> {
    return AccountMasterDeriveKeyV1.derive_key(
      self_kr,
      makeInfoByteArray(['account-', this.version])
    );
  }
}
