import { NO_WAIT, toSendOptions } from '@aztec/aztec.js/contracts';
import { waitForTx } from '@aztec/aztec.js/node';
import { SimulationError } from '@aztec/stdlib/errors';
import { Tx } from '@aztec/stdlib/tx';
import { inspect } from 'util';
export class ProvenTx extends Tx {
    node;
    offchainEffects;
    stats;
    constructor(node, tx, offchainEffects, stats){
        super(tx.getTxHash(), tx.data, tx.chonkProof, tx.contractClassLogFields, tx.publicFunctionCalldata), this.node = node, this.offchainEffects = offchainEffects, this.stats = stats;
    }
    async send(options) {
        const txHash = this.getTxHash();
        await this.node.sendTx(this).catch((err)=>{
            throw this.contextualizeError(err, inspect(this));
        });
        if (options?.wait === NO_WAIT) {
            return txHash;
        }
        const waitOpts = typeof options?.wait === 'object' ? options.wait : undefined;
        return await waitForTx(this.node, txHash, waitOpts);
    }
    contextualizeError(err, ...context) {
        let contextStr = '';
        if (context.length > 0) {
            contextStr = `\nContext:\n${context.join('\n')}`;
        }
        if (err instanceof SimulationError) {
            err.setAztecContext(contextStr);
        }
        return err;
    }
}
export async function proveInteraction(wallet, interaction, options) {
    const execPayload = await interaction.request(options);
    return wallet.proveTx(execPayload, toSendOptions(options));
}
/**
 * Mutable wrapper around an AztecNode that forwards all calls to the current target.
 * Allows swapping the underlying node at runtime via updateTargetNode, which is useful
 * for tests that need to redirect a wallet from one node to another without recreating it.
 */ // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class AztecNodeProxy {
    target;
    constructor(target){
        this.target = target;
        return new Proxy(this, {
            get: (obj, prop, receiver)=>{
                // Own properties and methods (updateTargetNode, target) are served directly.
                if (Reflect.has(obj, prop)) {
                    return Reflect.get(obj, prop, receiver);
                }
                // Everything else is forwarded to the current target node.
                const val = obj.target[prop];
                return typeof val === 'function' ? val.bind(obj.target) : val;
            }
        });
    }
    /**
   * Updates the underlying node that this reference points to.
   * @param node - The new node to forward calls to.
   */ updateTargetNode(node) {
        this.target = node;
    }
}
