"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveInputs = resolveInputs;
exports.compile = compile;
exports.tryResolveImport = tryResolveImport;
const solc_1 = __importDefault(require("solc"));
const child_process_1 = require("child_process");
const resolc_1 = require("./resolc");
const path_1 = __importDefault(require("path"));
const fs_1 = require("fs");
function resolveInputs(sources) {
    const input = {
        language: 'Solidity',
        sources,
        settings: {
            outputSelection: {
                '*': {
                    '*': ['evm.bytecode.object'],
                },
            },
        },
    };
    const out = solc_1.default.compile(JSON.stringify(input), {
        import: (path) => {
            return {
                contents: (0, fs_1.readFileSync)(tryResolveImport(path), 'utf8'),
            };
        },
    });
    const output = JSON.parse(out);
    if (output.errors && Object.keys(output.sources).length === 0) {
        throw new Error(output.errors[0].formattedMessage);
    }
    return Object.fromEntries(Object.keys(output.sources).map((fileName) => {
        return [
            fileName,
            sources[fileName] ?? {
                content: (0, fs_1.readFileSync)(tryResolveImport(fileName), 'utf8'),
            },
        ];
    }));
}
async function compile(sources, option = {}) {
    const input = JSON.stringify({
        language: 'Solidity',
        sources: resolveInputs(sources),
        settings: {
            optimizer: { enabled: true, runs: 200 },
            outputSelection: {
                '*': {
                    '*': ['abi'],
                },
            },
        },
    });
    if (option.bin) {
        return compileWithBin(input, option.bin);
    }
    return (0, resolc_1.resolc)(input);
}
/**
 * Resolve an import path to a file path.
 * @param importPath - The import path to resolve.
 */
function tryResolveImport(importPath) {
    // resolve local path
    if ((0, fs_1.existsSync)(importPath)) {
        return path_1.default.resolve(importPath);
    }
    const importRegex = /^(@?[^@/]+(?:\/[^@/]+)?)(?:@([^/]+))?(\/.+)$/;
    const match = importPath.match(importRegex);
    if (!match) {
        throw new Error('Invalid import path format.');
    }
    const basePackage = match[1]; // "foo", "@scope/foo"
    const specifiedVersion = match[2]; // "1.2.3" (optional)
    const relativePath = match[3]; // "/path/to/file.sol"
    let packageJsonPath;
    try {
        packageJsonPath = require.resolve(path_1.default.join(basePackage, 'package.json'));
    }
    catch {
        throw new Error(`Could not resolve package ${basePackage}`);
    }
    // Check if a version was specified and compare with the installed version
    if (specifiedVersion) {
        const installedVersion = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, 'utf-8')).version;
        if (installedVersion !== specifiedVersion) {
            throw new Error(`Version mismatch: Specified ${basePackage}@${specifiedVersion}, but installed version is ${installedVersion}`);
        }
    }
    const packageRoot = path_1.default.dirname(packageJsonPath);
    // Construct full path to the requested file
    const resolvedPath = path_1.default.join(packageRoot, relativePath);
    if ((0, fs_1.existsSync)(resolvedPath)) {
        return resolvedPath;
    }
    else {
        throw new Error(`Resolved path ${resolvedPath} does not exist.`);
    }
}
function compileWithBin(input, bin) {
    return new Promise((resolve, reject) => {
        const process = (0, child_process_1.spawn)(bin, ['--standard-json']);
        let output = '';
        let error = '';
        process.stdin.write(input);
        process.stdin.end();
        process.stdout.on('data', (data) => {
            output += data.toString();
        });
        process.stderr.on('data', (data) => {
            error += data.toString();
        });
        process.on('close', (code) => {
            if (code === 0) {
                try {
                    const result = JSON.parse(output);
                    resolve(result);
                }
                catch {
                    reject(new Error(`Failed to parse output`));
                }
            }
            else {
                reject(new Error(`Process exited with code ${code}: ${error}`));
            }
        });
    });
}
//# sourceMappingURL=index.js.map