import { access, stat } from "node:fs/promises";
import { dirname, join } from "node:path";
import { CONFIG_DIR_NAME } from "../config.js";
import { getGitInstallPath } from "./package-manager-paths.js";
import { addAutoDiscoveredResources, collectProjectLocalResources } from "./package-manager-auto-resources.js";
import { getExistingGitInstallPath, refreshTemporaryGitSource } from "./package-manager-git.js";
import { isOfflineModeEnabled } from "./package-manager-env.js";
import { getExistingNpmInstallPath, installedNpmMatchesConfiguredVersion } from "./package-manager-npm.js";
import { getBaseDirsForScope, resolvePathFromBase } from "./package-manager-paths.js";
import { createAccumulator, addResource, getTargetMap, toResolvedPaths } from "./package-manager-resource-accumulator.js";
import { collectPackageResources, resolveLocalEntries } from "./package-manager-resource-collector.js";
import { resolveExtensionEntries } from "./package-manager-resource-files.js";
import { dedupePackages, getPackageSourceString, parseSource } from "./package-manager-source.js";
import { installParsedSource } from "./package-manager-operations.js";
async function exists(path) {
    try {
        await access(path);
        return true;
    }
    catch {
        return false;
    }
}
export async function resolvePackages(context, onMissing) {
    const accumulator = createAccumulator();
    const globalSettings = context.settingsManager.getGlobalSettings();
    const projectSettings = context.settingsManager.getProjectSettings();
    const allPackages = [];
    for (const pkg of projectSettings.packages ?? []) {
        allPackages.push({ pkg, scope: "project" });
    }
    for (const pkg of globalSettings.packages ?? []) {
        allPackages.push({ pkg, scope: "user" });
    }
    const packageSources = dedupePackages(context, allPackages);
    await resolvePackageSources(context, packageSources, accumulator, onMissing);
    const globalBaseDir = context.agentDir;
    const projectBaseDir = join(context.cwd, CONFIG_DIR_NAME);
    const globalBaseDirs = getBaseDirsForScope(context, "user");
    const projectBaseDirs = getBaseDirsForScope(context, "project");
    for (const resourceType of ["extensions", "skills", "prompts", "themes", "workflows"]) {
        const target = getTargetMap(accumulator, resourceType);
        const globalEntries = (globalSettings[resourceType] ?? []);
        const projectEntries = (projectSettings[resourceType] ?? []);
        for (const baseDir of projectBaseDirs) {
            await resolveLocalEntries(projectEntries, resourceType, target, { source: "local", scope: "project", origin: "top-level", baseDir }, baseDir);
        }
        for (const baseDir of globalBaseDirs) {
            await resolveLocalEntries(globalEntries, resourceType, target, { source: "local", scope: "user", origin: "top-level", baseDir }, baseDir);
        }
    }
    await addAutoDiscoveredResources(context, accumulator, globalSettings, projectSettings, globalBaseDir, projectBaseDir);
    return toResolvedPaths(accumulator);
}
export async function resolveExtensionSources(context, sources, options) {
    const accumulator = createAccumulator();
    const scope = options?.temporary ? "temporary" : options?.local ? "project" : "user";
    const packageSources = sources.map((source) => ({ pkg: source, scope }));
    await resolvePackageSources(context, packageSources, accumulator, undefined, {
        includeProjectLocalResources: options?.includeProjectLocalResources === true,
    });
    return toResolvedPaths(accumulator);
}
async function resolvePackageSources(context, sources, accumulator, onMissing, options) {
    for (const { pkg, scope } of sources) {
        const sourceStr = getPackageSourceString(pkg);
        const filter = typeof pkg === "object" ? pkg : undefined;
        const parsed = parseSource(sourceStr);
        const metadata = { source: sourceStr, scope, origin: "package" };
        if (parsed.type === "local") {
            for (const baseDir of getBaseDirsForScope(context, scope)) {
                await resolveLocalExtensionSource(parsed, accumulator, filter, { ...metadata, baseDir }, baseDir, {
                    includeProjectLocalResources: options?.includeProjectLocalResources === true,
                });
            }
            continue;
        }
        const installMissing = async () => {
            if (isOfflineModeEnabled())
                return false;
            if (!onMissing) {
                if (context.driver)
                    await context.driver.installParsedSource(parsed, scope);
                else
                    await installParsedSource(context, parsed, scope);
                return true;
            }
            const action = await onMissing(sourceStr);
            if (action === "skip")
                return false;
            if (action === "error")
                throw new Error(`Missing source: ${sourceStr}`);
            if (context.driver)
                await context.driver.installParsedSource(parsed, scope);
            else
                await installParsedSource(context, parsed, scope);
            return true;
        };
        if (parsed.type === "npm") {
            let installedPath = getExistingNpmInstallPath(context, parsed, scope);
            const needsInstall = !installedPath || !(await installedNpmMatchesConfiguredVersion(context, parsed, installedPath));
            if (needsInstall) {
                const installed = await installMissing();
                if (!installed)
                    continue;
                installedPath = getExistingNpmInstallPath(context, parsed, scope);
                if (!installedPath || !(await installedNpmMatchesConfiguredVersion(context, parsed, installedPath))) {
                    continue;
                }
            }
            if (!installedPath)
                continue;
            metadata.baseDir = installedPath;
            await collectPackageResources(installedPath, accumulator, filter, metadata);
            continue;
        }
        let installedPath = getExistingGitInstallPath(context, parsed, scope) ?? getGitInstallPath(context, parsed, scope);
        if (!(await exists(installedPath))) {
            const installed = await installMissing();
            if (!installed)
                continue;
        }
        else if (scope === "temporary" && !parsed.pinned && !isOfflineModeEnabled()) {
            if (context.driver)
                await context.driver.refreshTemporaryGitSource(parsed, sourceStr);
            else
                await refreshTemporaryGitSource(context, parsed, sourceStr);
        }
        metadata.baseDir = installedPath;
        await collectPackageResources(installedPath, accumulator, filter, metadata);
    }
}
async function resolveLocalExtensionSource(source, accumulator, filter, metadata, baseDir, options) {
    const resolved = resolvePathFromBase(source.path, baseDir);
    if (!(await exists(resolved)))
        return;
    try {
        const stats = await stat(resolved);
        if (stats.isFile()) {
            addResource(accumulator.extensions, resolved, { ...metadata, baseDir: dirname(resolved) }, true);
            return;
        }
        if (stats.isDirectory()) {
            const packageMetadata = { ...metadata, baseDir: resolved };
            const packageResources = await collectPackageResources(resolved, accumulator, filter, packageMetadata);
            const projectLocalResources = options?.includeProjectLocalResources
                ? await collectProjectLocalResources(resolved, accumulator, filter, packageMetadata)
                : false;
            const extensionEntries = await resolveExtensionEntries(resolved);
            const shouldAddDirectoryFallback = extensionEntries !== null || (options?.includeProjectLocalResources === true && !projectLocalResources);
            if (!packageResources && shouldAddDirectoryFallback) {
                addResource(accumulator.extensions, resolved, packageMetadata, true);
            }
        }
    }
    catch { }
}
//# sourceMappingURL=package-manager-resolver.js.map