import { FunctionSelector, FunctionType, decodeFromAbi, encodeArguments, } from '@aztec/foundation/abi';
import { BaseContractInteraction } from './base_contract_interaction.js';
/**
 * This is the class that is returned when calling e.g. `contract.methods.myMethod(arg0, arg1)`.
 * It contains available interactions one can call on a method, including view.
 */
export class ContractFunctionInteraction extends BaseContractInteraction {
    constructor(wallet, contractAddress, functionDao, args) {
        super(wallet);
        this.contractAddress = contractAddress;
        this.functionDao = functionDao;
        this.args = args;
        if (args.some(arg => arg === undefined || arg === null)) {
            throw new Error('All function interaction arguments must be defined and not null. Received: ' + args);
        }
    }
    /**
     * Create a transaction execution request that represents this call, encoded and authenticated by the
     * user's wallet, ready to be simulated.
     * @param opts - An optional object containing additional configuration for the transaction.
     * @returns A Promise that resolves to a transaction instance.
     */
    async create(opts) {
        if (this.functionDao.functionType === FunctionType.UNCONSTRAINED) {
            throw new Error("Can't call `create` on an unconstrained function.");
        }
        const calls = [this.request()];
        const fee = opts?.estimateGas ? await this.getFeeOptionsFromEstimatedGas({ calls, fee: opts?.fee }) : opts?.fee;
        const txRequest = await this.wallet.createTxExecutionRequest({
            calls,
            fee,
            nonce: opts?.nonce,
            cancellable: opts?.cancellable,
        });
        return txRequest;
    }
    /**
     * Returns an execution request that represents this operation. Useful as a building
     * block for constructing batch requests.
     * @returns An execution request wrapped in promise.
     */
    request() {
        const args = encodeArguments(this.functionDao, this.args);
        return {
            name: this.functionDao.name,
            args,
            selector: FunctionSelector.fromNameAndParameters(this.functionDao.name, this.functionDao.parameters),
            type: this.functionDao.functionType,
            to: this.contractAddress,
            isStatic: this.functionDao.isStatic,
            returnTypes: this.functionDao.returnTypes,
        };
    }
    /**
     * Simulate a transaction and get its return values
     * Differs from prove in a few important ways:
     * 1. It returns the values of the function execution
     * 2. It supports `unconstrained`, `private` and `public` functions
     *
     * @param options - An optional object containing additional configuration for the transaction.
     * @returns The result of the transaction as returned by the contract function.
     */
    async simulate(options = {}) {
        if (this.functionDao.functionType == FunctionType.UNCONSTRAINED) {
            return this.wallet.simulateUnconstrained(this.functionDao.name, this.args, this.contractAddress, options?.from);
        }
        const txRequest = await this.create();
        const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from, options?.skipTxValidation);
        // As account entrypoints are private, for private functions we retrieve the return values from the first nested call
        // since we're interested in the first set of values AFTER the account entrypoint
        // For public functions we retrieve the first values directly from the public output.
        const rawReturnValues = this.functionDao.functionType == FunctionType.PRIVATE
            ? simulatedTx.getPrivateReturnValues().nested?.[0].values
            : simulatedTx.getPublicReturnValues()?.[0].values;
        return rawReturnValues ? decodeFromAbi(this.functionDao.returnTypes, rawReturnValues) : [];
    }
    /**
     * Simulate a transaction and profile the gate count for each function in the transaction.
     * @param options - Same options as `simulate`.
     *
     * @returns An object containing the function return value and profile result.
     */
    async simulateWithProfile(options = {}) {
        if (this.functionDao.functionType == FunctionType.UNCONSTRAINED) {
            throw new Error("Can't profile an unconstrained function.");
        }
        const txRequest = await this.create();
        const simulatedTx = await this.wallet.simulateTx(txRequest, true, options?.from, options?.skipTxValidation, true);
        const rawReturnValues = this.functionDao.functionType == FunctionType.PRIVATE
            ? simulatedTx.getPrivateReturnValues().nested?.[0].values
            : simulatedTx.getPublicReturnValues()?.[0].values;
        const rawReturnValuesDecoded = rawReturnValues ? decodeFromAbi(this.functionDao.returnTypes, rawReturnValues) : [];
        return {
            returnValues: rawReturnValuesDecoded,
            gateCounts: simulatedTx.profileResult.gateCounts,
        };
    }
}
//# sourceMappingURL=data:application/json;base64, 