import { GrumpkinAddress } from '@polyaztec/barretenberg/address';
import { AccountTx, ProofData } from '@polyaztec/barretenberg/client_proofs';
import { createDebugLogger } from '@polyaztec/barretenberg/log';
import { HashPath } from '@polyaztec/barretenberg/merkle_tree';
import { OffchainAccountData } from '@polyaztec/barretenberg/offchain_tx_data';
import { TxId } from '@polyaztec/barretenberg/tx_id';
import { WorldStateConstants } from '@polyaztec/barretenberg/world_state';
import { CoreAccountTx } from '../core_tx/index.js';
const debug = createDebugLogger('bb:account_proof');
export class AccountProofCreator {
    constructor(prover, worldState, db) {
        this.prover = prover;
        this.worldState = worldState;
        this.db = db;
    }
    async createProofInput(accountPublicKey, aliasHash, migrate, spendingPublicKey, newAccountPublicKey, newSpendingPublicKey1, newSpendingPublicKey2, spendingKeyExists = true) {
        // Regarding `!migrate` check: see explanation in `getAccountPathAndIndex`
        const create = accountPublicKey.equals(spendingPublicKey) && !migrate;
        const merkleRoot = this.worldState.getRoot();
        const { path: accountPath, index: accountIndex } = await this.getAccountPathAndIndex(accountPublicKey, spendingKeyExists ? spendingPublicKey : accountPublicKey, migrate);
        const tx = new AccountTx(merkleRoot, accountPublicKey, newAccountPublicKey || accountPublicKey, newSpendingPublicKey1 || GrumpkinAddress.ZERO, newSpendingPublicKey2 || GrumpkinAddress.ZERO, aliasHash, create, migrate, accountIndex, accountPath, spendingPublicKey);
        const signingData = await this.prover.computeSigningData(tx);
        return { tx, signingData };
    }
    async createProof({ tx, signature }, txRefNo, timeout) {
        debug('creating proof...');
        const start = new Date().getTime();
        const proof = await this.prover.createAccountProof(tx, signature, timeout);
        debug(`created proof: ${new Date().getTime() - start}ms`);
        debug(`proof size: ${proof.length}`);
        const proofData = new ProofData(proof);
        const txId = new TxId(proofData.txId);
        const { aliasHash, newAccountPublicKey, newSpendingPublicKey1, newSpendingPublicKey2, migrate } = tx;
        const coreTx = new CoreAccountTx(txId, newAccountPublicKey, aliasHash, newSpendingPublicKey1?.x(), newSpendingPublicKey2?.x(), migrate, txRefNo, new Date());
        const offchainTxData = new OffchainAccountData(newAccountPublicKey, aliasHash, newSpendingPublicKey1?.x(), newSpendingPublicKey2?.x(), txRefNo);
        return { tx: coreTx, proofData, offchainTxData, outputNotes: [] };
    }
    async getAccountPathAndIndex(accountPublicKey, spendingPublicKey, migrate) {
        // migrate flag explanation:
        // There is a system-wide assumption (enforced at account creation) that a user's registered spending keys and
        // account keys cannot match, and therefore if a user trys to spend using keys that match, they are performing an
        // "unregistered" action. I.e. they are spending notes which don't require a registered spending key. Unfortunately
        // when importing account registrations from the old system we didn't account for the fact that prior to June 2021
        // users had registrations with no spending keys (only an alias), and such dormant registrations ended up
        // inheriting their account keys as registered spending keys. In order to allow such accounts to migrate their
        // aliases, we have an expectional case in we perform the "registered" action instead of the "unregistered" action.
        if (spendingPublicKey.equals(accountPublicKey) && !migrate) {
            return {
                path: this.worldState.buildZeroHashPath(WorldStateConstants.DATA_TREE_DEPTH),
                index: 0,
            };
        }
        else {
            const spendingKey = await this.db.getSpendingKey(accountPublicKey, spendingPublicKey);
            if (spendingKey === undefined) {
                throw new Error('Unknown spending key.');
            }
            const immutableHashPath = HashPath.fromBuffer(spendingKey.hashPath);
            const path = await this.worldState.buildFullHashPath(spendingKey.treeIndex, immutableHashPath);
            return {
                path,
                index: spendingKey.treeIndex,
            };
        }
    }
}
//# sourceMappingURL=data:application/json;base64, 