/**
 * CLR Bindings Package Resolution
 *
 * Package root resolution, bindings.json discovery, and metadata extraction
 * (namespace, assembly) for CLR bindings packages.
 */
import { existsSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { extractRawDotnetAssemblyName } from "../program/dotnet-binding-payload.js";
/**
 * Resolve package root directory using Node resolution.
 *
 * Uses require.resolve to find the package's package.json,
 * then returns the directory containing it.
 */
export const resolvePkgRoot = (packageName, pkgRootCache, mainRequire) => {
    const cached = pkgRootCache.get(packageName);
    if (cached !== undefined) {
        return cached;
    }
    const resolveViaRequire = (req) => {
        try {
            const pkgJsonPath = req.resolve(`${packageName}/package.json`);
            return dirname(pkgJsonPath);
        }
        catch {
            return null;
        }
    };
    const resolveViaSearchPaths = (paths) => {
        if (!paths)
            return null;
        for (const searchPath of paths) {
            const pkgDir = join(searchPath, packageName);
            if (existsSync(join(pkgDir, "package.json"))) {
                return pkgDir;
            }
        }
        return null;
    };
    const direct = resolveViaRequire(mainRequire);
    if (direct) {
        pkgRootCache.set(packageName, direct);
        return direct;
    }
    const fromPaths = resolveViaSearchPaths(mainRequire.resolve.paths(packageName));
    if (fromPaths) {
        pkgRootCache.set(packageName, fromPaths);
        return fromPaths;
    }
    pkgRootCache.set(packageName, null);
    return null;
};
/**
 * Check if bindings.json exists at the given path (cached)
 */
export const hasBindings = (bindingsPath, bindingsExistsCache) => {
    const cached = bindingsExistsCache.get(bindingsPath);
    if (cached !== undefined) {
        return cached;
    }
    const exists = existsSync(bindingsPath);
    bindingsExistsCache.set(bindingsPath, exists);
    return exists;
};
/**
 * Extract the namespace from a bindings.json file (cached).
 */
export const extractNamespace = (bindingsPath, namespaceCache) => {
    const cached = namespaceCache.get(bindingsPath);
    if (cached !== undefined) {
        return cached ?? undefined;
    }
    try {
        const content = readFileSync(bindingsPath, "utf-8");
        const parsed = JSON.parse(content);
        if (parsed !== null &&
            typeof parsed === "object" &&
            "namespace" in parsed &&
            typeof parsed.namespace === "string") {
            const namespace = parsed.namespace;
            namespaceCache.set(bindingsPath, namespace);
            return namespace;
        }
        namespaceCache.set(bindingsPath, null);
        return undefined;
    }
    catch {
        namespaceCache.set(bindingsPath, null);
        return undefined;
    }
};
/**
 * Extract the assembly name from a bindings.json file (cached).
 * Looks at the first type's assemblyName field.
 */
export const extractAssembly = (bindingsPath, assemblyCache) => {
    const cached = assemblyCache.get(bindingsPath);
    if (cached !== undefined) {
        return cached ?? undefined;
    }
    try {
        const content = readFileSync(bindingsPath, "utf-8");
        const parsed = JSON.parse(content);
        const assembly = extractRawDotnetAssemblyName(parsed);
        if (assembly) {
            assemblyCache.set(bindingsPath, assembly);
            return assembly;
        }
        // No assembly found, cache null
        assemblyCache.set(bindingsPath, null);
        return undefined;
    }
    catch {
        // Failed to read/parse, cache null
        assemblyCache.set(bindingsPath, null);
        return undefined;
    }
};
//# sourceMappingURL=clr-bindings-package-resolution.js.map