/*
 * 文件定位：Agent 执行引擎 / 基础工具原语层 / 工具依赖管理层。
 * 核心目的：承载 dependency Checker 这一能力位点。
 * 能力要求1：需要把文件名表达的能力落实成清晰的类型、输入输出和最小行为。
 * 能力要求2：如果后续发现语义不足，应优先补接口契约，而不是把逻辑散落到相邻文件。
 * 边界：保留 Agent 基础工具原语，不替代 TAP 的高级工具系统。
 * 对接：需要被 runtime.execEngine 拉起，并和 mainLoop、stateEngine、事件暴露、工具调用策略接通。
 * 实现提示：先补稳定类型契约、最小可测行为和清晰错误边界，再接入真实执行逻辑。
 */
import path from "node:path";
import { lookupDependencySource, managedBinDir } from "./dependencySourceRegistry.js";
export const basicToolDependencyCheckerDescriptor = {
    capability: "check-basic-tool-runtime-dependencies",
    layer: "agent_executionEngine.basic_toolLayer.toolDependency.dependencyChecker",
    defaultRefreshPolicy: "use-provided-probes",
    externalProbePerformed: false,
    unsafeSideEffects: false,
};
export function planBasicToolDependencyProbe(dependency, options = {}) {
    const sourceLookup = lookupDependencySource(dependency.id);
    const source = sourceLookup.ok ? sourceLookup.source : undefined;
    const command = source?.executableName ?? dependency.id;
    const alternateCommands = source?.alternateExecutableNames ?? [];
    const binDir = managedBinDir(options);
    const commands = [command, ...alternateCommands];
    return {
        kind: "agentCore.basicTool.dependencyProbePlan",
        dependencyId: dependency.id,
        candidates: [
            ...commands.map((candidate) => ({
                id: `${dependency.id}:managed:${candidate}`,
                command: path.join(binDir, candidate),
                args: source?.versionCommand?.args ?? ["--version"],
                location: "praxis-managed",
            })),
            ...commands.map((candidate) => ({
                id: `${dependency.id}:path:${candidate}`,
                command: candidate,
                args: source?.versionCommand?.args ?? ["--version"],
                location: "path",
            })),
        ],
        externalProbePerformed: false,
        unsafeSideEffects: false,
    };
}
function isBlank(value) {
    return typeof value !== "string" || value.trim().length === 0;
}
function cleanList(values) {
    return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))];
}
function failure(code, message, boundary, report) {
    return {
        ok: false,
        error: { code, message, boundary, publicSafe: true },
        report,
        events: ["agentCore.basicTool.dependencyChecker.rejected"],
    };
}
function validateDependency(dependency) {
    const id = dependency.id?.trim();
    if (isBlank(id)) {
        return failure("INVALID_DEPENDENCY", "basic tool dependency declarations require id", "input");
    }
    return {
        ...dependency,
        id: id ?? "",
        severity: dependency.severity ?? "required",
        scope: dependency.scope?.trim() || undefined,
    };
}
function findProbe(dependency, probes) {
    return probes.find((probe) => probe.id.trim() === dependency.id);
}
function ensureScope(dependency, allowedScopes) {
    const scope = dependency.scope?.trim();
    if (scope === undefined || scope.length === 0) {
        return undefined;
    }
    const allowed = cleanList(allowedScopes);
    if (allowed.length === 0 || allowed.includes(scope)) {
        return undefined;
    }
    return failure("SCOPE_DENIED", `basic tool dependency scope ${scope} is outside runtime governance`, "scope");
}
function buildReport(runtimeId, toolId, statuses, metadata) {
    const missingRequired = statuses
        .filter((status) => status.severity === "required" && !status.available)
        .map((status) => status.id);
    const optionalMissing = statuses
        .filter((status) => status.severity === "optional" && !status.available)
        .map((status) => status.id);
    return {
        kind: "agentCore.basicTool.dependencyReport",
        runtimeId,
        toolId,
        status: missingRequired.length === 0 ? "satisfied" : "degraded",
        dependencies: statuses,
        missingRequired,
        optionalMissing,
        dryRun: true,
        externalProbePerformed: false,
        unsafeSideEffects: false,
        audit: {
            event: "agentCore.basicTool.dependencyChecker.checked",
            metadata,
        },
    };
}
export function checkBasicToolDependencies(request = {}) {
    const runtimeId = request.context?.runtimeId?.trim();
    if (isBlank(runtimeId)) {
        return failure("MISSING_RUNTIME_ID", "basic tool dependency check requires context.runtimeId", "input");
    }
    const toolId = request.context?.toolId?.trim();
    if (isBlank(toolId)) {
        return failure("MISSING_TOOL_ID", "basic tool dependency check requires context.toolId", "input");
    }
    if (request.context?.dryRun === false) {
        return failure("REFRESH_PROBE_BLOCKED", "first-round dependencyChecker only evaluates provided dependency probes", "contract");
    }
    if (request.dependencies === undefined || request.dependencies.length === 0) {
        return failure("MISSING_DEPENDENCIES", "basic tool dependency check requires at least one dependency", "input");
    }
    const probes = request.probes ?? [];
    const statuses = [];
    for (const rawDependency of request.dependencies) {
        const dependency = validateDependency(rawDependency);
        if ("ok" in dependency) {
            return dependency;
        }
        const scopeError = ensureScope(dependency, request.context?.allowedScopes);
        if (scopeError !== undefined) {
            return scopeError;
        }
        const probe = findProbe(dependency, probes);
        const available = probe?.available ?? false;
        statuses.push({
            id: dependency.id,
            kind: dependency.kind,
            severity: dependency.severity ?? "required",
            available,
            version: probe?.version,
            resolvedPath: probe?.resolvedPath,
            versionRange: dependency.versionRange,
            scope: dependency.scope,
            staleProbeAccepted: request.refreshPolicy === "stale-ok",
            detail: probe?.detail,
            metadata: {
                ...(dependency.metadata ?? {}),
                ...(probe?.metadata ?? {}),
            },
        });
    }
    const report = buildReport(runtimeId ?? "", toolId ?? "", statuses, request.context?.metadata ?? {});
    if (report.missingRequired.length > 0) {
        return failure("DEPENDENCY_UNAVAILABLE", `basic tool dependency check failed for ${report.missingRequired[0]}`, "dependency", report);
    }
    return {
        ok: true,
        report,
        events: ["agentCore.basicTool.dependencyChecker.checked"],
    };
}
