import { AESCipherSIVNonce96 } from '../../base/cipher/aes';
import { AbstractCryptoConfig, ArgumentsError } from '../base';
import { LocalStorageConfigDumpArgs, LocalStorageConfigLoadArgs } from './args';
import { concatByteArray } from '../../utility';
import { HKDFKeyGeneratorV2 } from '../../base/key/kdf';

export class LocalStorageConfigV2 extends AbstractCryptoConfig<
  LocalStorageConfigLoadArgs,
  LocalStorageConfigDumpArgs
> {
  constructor(never_dump: boolean = false) {
    super(2, never_dump);
  }

  public load(args: LocalStorageConfigLoadArgs): Promise<Uint8Array> {
    if (args.salt.length === 0) {
      throw new ArgumentsError();
    }
    return this.derive_key(args.server_key, args.client_key, args.salt).then((derive_key) => {
      return AESCipherSIVNonce96.decrypt(args.cipher.slice(this.version.byteLength), derive_key);
    });
  }

  public dump(args: LocalStorageConfigDumpArgs): Promise<Uint8Array> {
    if (args.server_key.length < 16 || args.client_key.length < 16 || args.salt.length < 16) {
      throw new ArgumentsError();
    }
    return this.derive_key(args.server_key, args.client_key, args.salt).then((derive_key) => {
      return AESCipherSIVNonce96.encrypt(
        args.plain,
        derive_key,
        undefined,
        undefined,
        this.version
      );
    });
  }

  public derive_key(server_key: Uint8Array, client_key: Uint8Array, salt: Uint8Array) {
    return HKDFKeyGeneratorV2.new_key(
      64,
      concatByteArray(server_key, client_key),
      salt,
      new Uint8Array([])
    );
  }
}
