import { SelfAccountKeyring } from '../keyring/account_self';
import { AbstractSelfAccountKeyring } from '../keyring/account_base';
import { AbstractPrivateKeyring } from '../keyring/private';
import { account_password_change } from './password';
import { ACCOUNT_ROOT_KEY_CRYPTO_CONTEXT } from '../context/account_key/root/__init__';
import { AccountRootKeyConfigLoadArgs } from '../context/account_key/root/args';
import { Ed25519KeyGenerator } from '../base/key/ec';
import { ACCOUNT_SIGNATURE_CRYPTO_CONTEXT } from '../context/account_signature/__init__';
import { AccountSignatureConfigDumpArgs } from '../context/account_signature/args';
import { base64 } from 'rfc4648';
import { concatByteArray, makeInfoByteArray } from '../utility';

export interface create_account_recovery_confirm_request_type {
  recovery_token: string;
  salt: string;
  master_key: string;
  auth_key: string;
  signature: string;
}

/**
 *
 * @param private_kr_cls
 * @param recovery_token acquired from URL fragment, sent to user as email by recover-prepare
 * @param account_id returned by recover-challenge for use here
 * @param encrypted_signing_secret_ec returned by recover-challenge for use here
 * @param recovery_key provided by the user
 * @param new_password provided by the user
 * @param enforce_normalized_password for testing
 */
export async function create_account_recovery_confirm_request(
  private_kr_cls: typeof AbstractPrivateKeyring,
  recovery_token: string,
  account_id: string,
  encrypted_signing_secret_ec: Uint8Array,
  recovery_key: Uint8Array,
  new_password: string,
  enforce_normalized_password?: boolean
): Promise<create_account_recovery_confirm_request_type> {
  let recovery_kr = new SelfAccountKeyring(
    account_id,
    {},
    { [AbstractSelfAccountKeyring.MASTER]: recovery_key }
  );
  let [client_salt_input, encrypted_master_key, hashed_authentication_key] =
    await account_password_change(
      private_kr_cls,
      recovery_kr,
      new_password,
      enforce_normalized_password
    );

  let ed25519_key = Ed25519KeyGenerator.regenerate_key_pair(
    await ACCOUNT_ROOT_KEY_CRYPTO_CONTEXT.load(
      new AccountRootKeyConfigLoadArgs(
        encrypted_signing_secret_ec,
        recovery_kr,
        SelfAccountKeyring.ED25519
      )
    )
  );

  recovery_kr.update(
    { [SelfAccountKeyring.ED25519]: ed25519_key.publicKey },
    { [SelfAccountKeyring.ED25519]: ed25519_key.secretKey }
  );
  let signature = await ACCOUNT_SIGNATURE_CRYPTO_CONTEXT.dump(
    new AccountSignatureConfigDumpArgs(
      makeInfoByteArray([
        recovery_token,
        client_salt_input,
        encrypted_master_key,
        hashed_authentication_key,
      ]),
      recovery_kr
    )
  );
  return {
    recovery_token: recovery_token,
    salt: base64.stringify(client_salt_input),
    master_key: base64.stringify(encrypted_master_key),
    auth_key: base64.stringify(hashed_authentication_key),
    signature: base64.stringify(signature),
  };
}
