import { anthropicShellCommandValidationPractice } from "./anthropic.js";
import { deepmindShellCommandValidationPractice } from "./deepmind.js";
import { openaiShellCommandValidationPractice } from "./openai.js";
import { buildShellPracticeAuditMetadata, createShellBaseToolDefinition, injectRuntimeInvocationMetadata, jsonSchema, } from "../../_shared/baseToolAdapter.js";
import { validateShellCommandSafety, } from "./core.js";
import { shellCommandValidationDependencyDeclarations, } from "./dependencies.js";
export * from "./core.js";
export const shellCommandValidationProviderPractices = [
    anthropicShellCommandValidationPractice,
    openaiShellCommandValidationPractice,
    deepmindShellCommandValidationPractice,
];
export const shellCommandValidationBestPracticeDescriptor = {
    toolId: "shell.commandValidation",
    bestPractice: "runtime-governed-shell-command-validation",
    sourcePriority: ["cli", "agent-sdk", "api-sdk", "praxis-native"],
    providerOrder: ["anthropic", "openai", "deepmind"],
    dependencies: shellCommandValidationDependencyDeclarations,
};
function orderedPractices(preferredProvider) {
    if (preferredProvider === undefined) {
        return shellCommandValidationProviderPractices;
    }
    return [
        ...shellCommandValidationProviderPractices.filter((practice) => practice.providerName === preferredProvider),
        ...shellCommandValidationProviderPractices.filter((practice) => practice.providerName !== preferredProvider),
    ];
}
export function selectShellCommandValidationPractice(dependencies = {}) {
    for (const practice of orderedPractices(dependencies.preferredProvider)) {
        const provider = practice.createProvider(dependencies);
        if (provider !== undefined) {
            return { providerName: practice.providerName, practice, provider };
        }
    }
    return {
        providerName: "praxis-native",
        practice: {
            providerName: "praxis-native",
            source: { kind: "praxis-native", label: "Praxis dry-run fallback" },
            directCliSupport: false,
            sideEffectPolicy: "runtime-governed",
            notes: ["No injected or host shell command validation provider is currently available; dry-run remains available."],
            createProvider: () => undefined,
        },
    };
}
function buildPracticeAuditMetadata(selection) {
    return buildShellPracticeAuditMetadata({
        providerName: selection.providerName,
        sourceLabel: selection.practice.source.label,
        sourceKind: selection.practice.source.kind,
        sourcePath: selection.practice.source.path,
        directCliSupport: selection.practice.directCliSupport,
        sideEffectPolicy: selection.practice.sideEffectPolicy,
        notes: selection.practice.notes,
    });
}
function isRecord(value) {
    return typeof value === "object" && value !== null;
}
function contextFrom(value) {
    return isRecord(value) ? value : undefined;
}
function metadataFrom(value) {
    return isRecord(value) ? value : {};
}
function hasAffirmativeGuard(context) {
    const guard = isRecord(context?.guard) ? context?.guard : undefined;
    if (guard?.allowed === false || guard?.accepted === false) {
        return false;
    }
    return guard?.allowed === true || guard?.accepted === true;
}
const commandValidationVerdicts = new Set(["allowed", "requires-approval", "blocked"]);
function normalizedStringList(value, fieldName) {
    if (value === undefined) {
        return undefined;
    }
    if (!Array.isArray(value)) {
        throw new Error(`shell.commandValidation provider returned invalid ${fieldName}`);
    }
    const values = [];
    for (const item of value) {
        if (typeof item !== "string") {
            throw new Error(`shell.commandValidation provider returned invalid ${fieldName}`);
        }
        values.push(item);
    }
    return values;
}
function providerCommandValidationPatch(value) {
    if (!isRecord(value)) {
        throw new Error("shell.commandValidation provider returned an invalid output envelope");
    }
    const patch = {};
    if (value.verdict !== undefined) {
        if (typeof value.verdict !== "string" || !commandValidationVerdicts.has(value.verdict)) {
            throw new Error("shell.commandValidation provider returned invalid verdict");
        }
        patch.verdict = value.verdict;
    }
    const reasons = normalizedStringList(value.reasons, "reasons");
    if (reasons !== undefined) {
        patch.reasons = reasons;
    }
    if (value.requiresTapApproval !== undefined) {
        if (typeof value.requiresTapApproval !== "boolean") {
            throw new Error("shell.commandValidation provider returned invalid requiresTapApproval");
        }
        patch.requiresTapApproval = value.requiresTapApproval;
    }
    return patch;
}
function providerRejectedMessage(error, fallback) {
    if (isRecord(error) && error.publicSafe === true && typeof error.message === "string" && error.message.trim().length > 0) {
        return error.message;
    }
    return fallback;
}
function runtimeFailure(code, message, boundary, request) {
    return {
        ok: false,
        toolId: "shell.commandValidation",
        error: {
            code,
            message,
            boundary,
            publicSafe: true,
            safeForRuntimeInspection: true,
            internalDetailExposed: false,
        },
        audit: [
            {
                type: "agentCore.basicTool.shell.commandValidation.rejected",
                toolId: "shell.commandValidation",
                invocationId: request.context?.invocationId ?? "shell.commandValidation:runtime",
                dryRun: request.context?.dryRun !== false,
                commandPreview: request.command,
                metadata: { ...metadataFrom(request.context?.auditMetadata), code, boundary },
            },
        ],
        events: ["basicTool.shell.commandValidation.rejected"],
    };
}
export async function executeShellCommandValidation(request = {}) {
    const selection = selectShellCommandValidationPractice({
        executor: request.executor,
        provider: request.provider,
        preferredProvider: request.preferredProvider,
    });
    const requestContext = contextFrom(request.context);
    const auditMetadata = {
        ...metadataFrom(requestContext?.auditMetadata),
        ...buildPracticeAuditMetadata(selection),
    };
    const planned = validateShellCommandSafety({
        ...request,
        context: {
            ...requestContext,
            dryRun: true,
            auditMetadata,
        },
    });
    if (!planned.ok || requestContext?.dryRun !== false) {
        return planned;
    }
    if (!hasAffirmativeGuard(requestContext)) {
        return runtimeFailure("GOVERNANCE_REJECTED", "shell.commandValidation requires an affirmative runtime guard before real provider dispatch", "governance", request);
    }
    if (selection.provider === undefined) {
        return runtimeFailure("PROVIDER_UNAVAILABLE", "shell.commandValidation requires a runtime shell guard provider for real dispatch", "provider", request);
    }
    try {
        const providerRequest = {
            command: planned.output.command,
            workingDirectory: planned.output.workingDirectory,
            shell: planned.output.shell,
            policy: isRecord(request.policy) ? request.policy : undefined,
            context: { ...requestContext, auditMetadata },
        };
        const providerOutput = await selection.provider(providerRequest, { ...requestContext, auditMetadata });
        const providerPatch = providerCommandValidationPatch(providerOutput);
        return {
            ok: true,
            toolId: "shell.commandValidation",
            output: {
                ...planned.output,
                ...providerPatch,
                dryRun: false,
                providerCalled: true,
                executionBlocked: true,
                finalApprovalGranted: false,
                runtimeGuardRequired: true,
            },
            audit: [
                {
                    type: "agentCore.basicTool.shell.commandValidation.provider",
                    toolId: "shell.commandValidation",
                    invocationId: requestContext?.invocationId ?? "shell.commandValidation:runtime",
                    dryRun: false,
                    commandPreview: planned.output.command,
                    metadata: auditMetadata,
                },
            ],
            events: ["basicTool.shell.commandValidation.providerCalled"],
        };
    }
    catch (error) {
        return runtimeFailure("PROVIDER_REJECTED", providerRejectedMessage(error, "shell.commandValidation provider rejected the request"), "provider", request);
    }
}
export function buildShellCommandValidationBestPractice(request = {}) {
    const selection = selectShellCommandValidationPractice({
        executor: request.executor,
        provider: request.provider,
        preferredProvider: request.preferredProvider,
    });
    const requestContext = contextFrom(request.context);
    return validateShellCommandSafety({
        ...request,
        context: {
            ...requestContext,
            auditMetadata: {
                ...metadataFrom(requestContext?.auditMetadata),
                ...buildPracticeAuditMetadata(selection),
            },
        },
    });
}
export const shellCommandValidationBaseToolDefinition = createShellBaseToolDefinition({
    toolId: "shell.commandValidation",
    title: "Shell Command Validation",
    description: "Classify shell command safety before any governed shell execution request.",
    summary: "Use shell.commandValidation to classify command risk without spawning a process.",
    storageGroup: "executionGuard",
    riskLevel: "risky",
    permissionHints: ["shell:validate"],
    dependencies: shellCommandValidationDependencyDeclarations,
    inputSchema: jsonSchema("shell.commandValidation.input", { type: "object", additionalProperties: true }),
    outputSchema: jsonSchema("shell.commandValidation.output", { type: "object", additionalProperties: true }),
});
function adaptResult(result) {
    if (!result.ok) {
        return {
            ok: false,
            toolId: result.toolId,
            error: { code: result.error.code, message: result.error.message, publicSafe: true },
            events: result.events,
        };
    }
    return { ok: true, toolId: result.toolId, output: result.output, events: result.events, metadata: { audit: result.audit } };
}
export const shellCommandValidationHandler = {
    definition: shellCommandValidationBaseToolDefinition,
    async invoke(request) {
        const input = isRecord(request.input) ? request.input : {};
        const inputContext = contextFrom(input.context);
        return adaptResult(await executeShellCommandValidation({
            ...input,
            executor: request.executor,
            context: {
                ...inputContext,
                runtimeId: inputContext?.runtimeId ?? request.runtimeId,
                invocationId: inputContext?.invocationId ?? request.toolCallId,
                auditMetadata: injectRuntimeInvocationMetadata({
                    ...(request.metadata ?? {}),
                }, inputContext?.auditMetadata, request),
            },
        }));
    },
};
