"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidSelectorSizeError = exports.NotFoundError = exports.AmbiguityError = void 0;
exports.format = format;
exports.from = from;
exports.fromAbi = fromAbi;
exports.getSelector = getSelector;
exports.getSignature = getSignature;
exports.getSignatureHash = getSignatureHash;
const abitype = require("abitype");
const Errors = require("./Errors.js");
const Hash = require("./Hash.js");
const Hex = require("./Hex.js");
const internal = require("./internal/abiItem.js");
function format(abiItem) {
    return abitype.formatAbiItem(abiItem);
}
function from(abiItem, options = {}) {
    const { prepare = true } = options;
    const item = (() => {
        if (Array.isArray(abiItem))
            return abitype.parseAbiItem(abiItem);
        if (typeof abiItem === 'string')
            return abitype.parseAbiItem(abiItem);
        return abiItem;
    })();
    return {
        ...item,
        ...(prepare ? { hash: getSignatureHash(item) } : {}),
    };
}
function fromAbi(abi, name, options) {
    const { args = [], prepare = true } = (options ??
        {});
    const isSelector = Hex.validate(name, { strict: false });
    const abiItems = abi.filter((abiItem) => {
        if (isSelector) {
            if (abiItem.type === 'function' || abiItem.type === 'error')
                return getSelector(abiItem) === Hex.slice(name, 0, 4);
            if (abiItem.type === 'event')
                return getSignatureHash(abiItem) === name;
            return false;
        }
        return 'name' in abiItem && abiItem.name === name;
    });
    if (abiItems.length === 0)
        throw new NotFoundError({ name: name });
    if (abiItems.length === 1)
        return {
            ...abiItems[0],
            ...(prepare ? { hash: getSignatureHash(abiItems[0]) } : {}),
        };
    let matchedAbiItem;
    for (const abiItem of abiItems) {
        if (!('inputs' in abiItem))
            continue;
        if (!args || args.length === 0) {
            if (!abiItem.inputs || abiItem.inputs.length === 0)
                return {
                    ...abiItem,
                    ...(prepare ? { hash: getSignatureHash(abiItem) } : {}),
                };
            continue;
        }
        if (!abiItem.inputs)
            continue;
        if (abiItem.inputs.length === 0)
            continue;
        if (abiItem.inputs.length !== args.length)
            continue;
        const matched = args.every((arg, index) => {
            const abiParameter = 'inputs' in abiItem && abiItem.inputs[index];
            if (!abiParameter)
                return false;
            return internal.isArgOfType(arg, abiParameter);
        });
        if (matched) {
            if (matchedAbiItem &&
                'inputs' in matchedAbiItem &&
                matchedAbiItem.inputs) {
                const ambiguousTypes = internal.getAmbiguousTypes(abiItem.inputs, matchedAbiItem.inputs, args);
                if (ambiguousTypes)
                    throw new AmbiguityError({
                        abiItem,
                        type: ambiguousTypes[0],
                    }, {
                        abiItem: matchedAbiItem,
                        type: ambiguousTypes[1],
                    });
            }
            matchedAbiItem = abiItem;
        }
    }
    const abiItem = (() => {
        if (matchedAbiItem)
            return matchedAbiItem;
        const [abiItem, ...overloads] = abiItems;
        return { ...abiItem, overloads };
    })();
    if (!abiItem)
        throw new NotFoundError({ name: name });
    return {
        ...abiItem,
        ...(prepare ? { hash: getSignatureHash(abiItem) } : {}),
    };
}
function getSelector(abiItem) {
    return Hex.slice(getSignatureHash(abiItem), 0, 4);
}
function getSignature(abiItem) {
    const signature = (() => {
        if (typeof abiItem === 'string')
            return abiItem;
        return abitype.formatAbiItem(abiItem);
    })();
    return internal.normalizeSignature(signature);
}
function getSignatureHash(abiItem) {
    if (typeof abiItem !== 'string' && 'hash' in abiItem && abiItem.hash)
        return abiItem.hash;
    return Hash.keccak256(Hex.fromString(getSignature(abiItem)));
}
class AmbiguityError extends Errors.BaseError {
    constructor(x, y) {
        super('Found ambiguous types in overloaded ABI Items.', {
            metaMessages: [
                `\`${x.type}\` in \`${internal.normalizeSignature(abitype.formatAbiItem(x.abiItem))}\`, and`,
                `\`${y.type}\` in \`${internal.normalizeSignature(abitype.formatAbiItem(y.abiItem))}\``,
                '',
                'These types encode differently and cannot be distinguished at runtime.',
                'Remove one of the ambiguous items in the ABI.',
            ],
        });
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'AbiItem.AmbiguityError'
        });
    }
}
exports.AmbiguityError = AmbiguityError;
class NotFoundError extends Errors.BaseError {
    constructor({ name, data, type = 'item', }) {
        const selector = (() => {
            if (name)
                return ` with name "${name}"`;
            if (data)
                return ` with data "${data}"`;
            return '';
        })();
        super(`ABI ${type}${selector} not found.`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'AbiItem.NotFoundError'
        });
    }
}
exports.NotFoundError = NotFoundError;
class InvalidSelectorSizeError extends Errors.BaseError {
    constructor({ data }) {
        super(`Selector size is invalid. Expected 4 bytes. Received ${Hex.size(data)} bytes ("${data}").`);
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 'AbiItem.InvalidSelectorSizeError'
        });
    }
}
exports.InvalidSelectorSizeError = InvalidSelectorSizeError;
//# sourceMappingURL=AbiItem.js.map