import { AESCipherSIVDeterministic } from '../../../base/cipher/aes';
import { AbstractSelfAccountKeyring } from '../../../keyring/account_base';
import { AbstractCryptoConfig } from '../../base';
import { AccountMasterDeriveKeyV1 } from '../../common';
import { AccountRootKeyConfigDumpArgs, AccountRootKeyConfigLoadArgs } from './args';
import { makeInfoByteArray } from '../../../utility';

/**
 * Account key encryption: AES-SIV
        KEY: 32B from account keyring -> 64B HKDF by context
        NONCE: none

    Used to encrypt various keys of the account. (for public key crypto)
    NOTE: No LRU cache on derive_key(), root keys are only loaded once and they are unique so there's no benefit.
 */
export class AccountRootKeyConfigV1 extends AbstractCryptoConfig<
  AccountRootKeyConfigLoadArgs,
  AccountRootKeyConfigDumpArgs
> {
  constructor(never_dump: boolean = false) {
    super(1, never_dump);
  }

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

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

  public derive_key(self_kr: AbstractSelfAccountKeyring, key_version: string) {
    return AccountMasterDeriveKeyV1.derive_key(
      self_kr,
      makeInfoByteArray(['account-root-key-', this.version, '-', key_version]),
      false
    );
  }
}
