import { __awaiter, __generator } from "tslib";
import "@nomiclabs/hardhat-ethers";
import fs from "fs";
import path from "path";
import { ethers } from "hardhat";
import { ContractFactory } from "ethers";
import { getAbi, getBytecode } from "@uma/contracts-node";
function isFactoryOptions(signerOrFactoryOptions) {
    return (typeof signerOrFactoryOptions === "object" &&
        ("signer" in signerOrFactoryOptions || "libraries" in signerOrFactoryOptions));
}
/**
 * Recursively gets all file paths in a directory.
 */
function getAllFilesInPath(dirPath, arrayOfFiles) {
    if (arrayOfFiles === void 0) { arrayOfFiles = []; }
    var files = fs.readdirSync(dirPath);
    files.forEach(function (file) {
        if (fs.statSync(dirPath + "/" + file).isDirectory()) {
            arrayOfFiles = getAllFilesInPath(dirPath + "/" + file, arrayOfFiles);
        }
        else {
            arrayOfFiles.push(path.join(dirPath, "/", file));
        }
    });
    return arrayOfFiles;
}
function isFoundryArtifact(artifact) {
    return typeof artifact.bytecode === "object" && "object" in artifact.bytecode;
}
/**
 * Extracts the bytecode string from an artifact, handling both Foundry and Hardhat formats.
 */
function getBytecodeFromArtifact(artifact) {
    if (isFoundryArtifact(artifact)) {
        return artifact.bytecode.object;
    }
    return artifact.bytecode;
}
/**
 * Finds an artifact JSON file from a given path by contract name.
 * Supports both Hardhat (artifacts/contracts/) and Foundry (out/) artifact structures.
 */
function findArtifactFromPath(contractName, artifactsPath) {
    var allArtifactsPaths = getAllFilesInPath(artifactsPath);
    var desiredArtifactPaths = allArtifactsPaths.filter(function (a) { return a.endsWith("/".concat(contractName, ".json")); });
    if (desiredArtifactPaths.length !== 1) {
        throw new Error("Couldn't find desired artifact or found too many for ".concat(contractName));
    }
    var artifact = JSON.parse(fs.readFileSync(desiredArtifactPaths[0], "utf-8"));
    return {
        abi: artifact.abi,
        bytecode: getBytecodeFromArtifact(artifact),
    };
}
/**
 * Attempts to find an artifact in the @across-protocol/contracts package.
 * Uses the Foundry 'out/' folder for artifacts.
 */
function getAcrossContractsArtifact(contractName) {
    var contractsPackagePath = path.dirname(require.resolve("@across-protocol/contracts/package.json"));
    var artifactsPath = path.join(contractsPackagePath, "out");
    return findArtifactFromPath(contractName, artifactsPath);
}
/**
 * Local implementation of getContractFactory that searches for artifacts in multiple locations:
 * 1. Local hardhat artifacts (for contracts in this repo)
 * 2. @across-protocol/contracts package artifacts
 * 3. UMA contracts-node package
 */
export function getContractFactory(name, signerOrFactoryOptions) {
    return __awaiter(this, void 0, void 0, function () {
        var signer, _1, artifact;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    signer = isFactoryOptions(signerOrFactoryOptions) ? signerOrFactoryOptions.signer : signerOrFactoryOptions;
                    _a.label = 1;
                case 1:
                    _a.trys.push([1, 3, , 4]);
                    return [4 /*yield*/, ethers.getContractFactory(name, signerOrFactoryOptions)];
                case 2: return [2 /*return*/, _a.sent()];
                case 3:
                    _1 = _a.sent();
                    return [3 /*break*/, 4];
                case 4:
                    // 2. Try to get from @across-protocol/contracts package
                    try {
                        artifact = getAcrossContractsArtifact(name);
                        return [2 /*return*/, new ContractFactory(artifact.abi, artifact.bytecode, signer)];
                    }
                    catch (_) {
                        // Continue to other sources
                    }
                    // 3. Try UMA contracts-node package
                    try {
                        if (isFactoryOptions(signerOrFactoryOptions)) {
                            throw new Error("Cannot pass FactoryOptions to a contract imported from UMA");
                        }
                        // eslint-disable-next-line @typescript-eslint/no-explicit-any
                        return [2 /*return*/, new ContractFactory(getAbi(name), getBytecode(name), signerOrFactoryOptions)];
                    }
                    catch (_) {
                        // Continue
                    }
                    throw new Error("Could not find the artifact for ".concat(name, "!"));
            }
        });
    });
}
//# sourceMappingURL=getContractFactory.js.map