import { anthropicShellArgumentAssemblyPractice } from "./anthropic.js";
import { deepmindShellArgumentAssemblyPractice } from "./deepmind.js";
import { openaiShellArgumentAssemblyPractice } from "./openai.js";
import { buildShellPracticeAuditMetadata, createShellBaseToolDefinition, injectRuntimeInvocationMetadata, jsonSchema, selectShellProviderPractice, } from "../../_shared/baseToolAdapter.js";
import { evaluateShellGenerationProviderDispatch, isShellGenerationRecord, shellGenerationDryRunEnabled, } from "../_shared/providerDispatch.js";
import { requireProviderAudit, requireProviderEvents, requireProviderFailureError, requireProviderResultEnvelope, requireRecordField, } from "../_shared/hostExecutorProvider.js";
import { assembleShellArguments, } from "./core.js";
import { normalizeShellArgumentAssemblyOutput, shellArgumentAssemblyDependencyDeclarations, } from "./dependencies.js";
export const shellArgumentAssemblyProviderPractices = [
    anthropicShellArgumentAssemblyPractice,
    openaiShellArgumentAssemblyPractice,
    deepmindShellArgumentAssemblyPractice,
];
export const shellArgumentAssemblyBestPracticeDescriptor = {
    toolId: "shell.argumentAssembly",
    bestPractice: "runtime-governed-shell-argument-assembly",
    sourcePriority: ["cli", "agent-sdk", "api-sdk", "praxis-native"],
    providerOrder: ["anthropic", "openai", "deepmind"],
    dependencies: shellArgumentAssemblyDependencyDeclarations,
};
const praxisNativeShellArgumentAssemblyPractice = {
    providerName: "praxis-native",
    source: {
        kind: "praxis-native",
        label: "Praxis deterministic shell argument assembly core",
    },
    directCliSupport: false,
    sideEffectPolicy: "runtime-governed",
    notes: ["Used for metadata only when no provider-specific practice is selected; dry-run still uses the deterministic core directly."],
    createProvider: ({ provider }) => provider,
};
export function selectShellArgumentAssemblyPractice(dependencies = {}) {
    return selectShellProviderPractice(shellArgumentAssemblyProviderPractices, dependencies, praxisNativeShellArgumentAssemblyPractice);
}
function buildShellArgumentAssemblyPracticeAuditMetadata(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 argumentAssemblyProviderFailure(code, message) {
    return {
        ok: false,
        toolId: "shell.argumentAssembly",
        error: {
            code,
            message,
            boundary: code === "GOVERNANCE_REJECTED" ? "governance" : "contract",
            publicSafe: true,
            internalDetailExposed: false,
        },
        audit: [],
        events: ["basicTool.shell.argumentAssembly.rejected"],
    };
}
const shellArgumentAssemblyProviderErrorCodes = [
    "MISSING_EXECUTABLE",
    "INVALID_ARGUMENT",
    "GOVERNANCE_REJECTED",
    "PROVIDER_UNAVAILABLE",
    "PROVIDER_REJECTED",
    "PERMISSION_DENIED",
    "REAL_EXECUTION_BLOCKED",
];
const shellArgumentAssemblyProviderErrorBoundaries = ["input", "permission", "contract", "governance"];
function normalizeShellArgumentAssemblyProviderResult(result) {
    const envelope = requireProviderResultEnvelope(result, "shell.argumentAssembly");
    const audit = requireProviderAudit(envelope);
    const events = requireProviderEvents(envelope);
    if (!envelope.ok) {
        return {
            ok: false,
            toolId: "shell.argumentAssembly",
            error: requireProviderFailureError(envelope, shellArgumentAssemblyProviderErrorCodes, shellArgumentAssemblyProviderErrorBoundaries),
            audit,
            events,
        };
    }
    return {
        ok: true,
        toolId: "shell.argumentAssembly",
        output: normalizeShellArgumentAssemblyOutput(requireRecordField(envelope, "output")),
        audit,
        events,
    };
}
export async function assembleShellArgumentsBestPractice(request = {}) {
    if (!isShellGenerationRecord(request) || shellGenerationDryRunEnabled(request.context)) {
        return assembleShellArguments(request);
    }
    const dispatch = evaluateShellGenerationProviderDispatch(request.context);
    if (!dispatch.ok) {
        return argumentAssemblyProviderFailure(dispatch.code, dispatch.message);
    }
    const validation = assembleShellArguments({
        ...request,
        context: {
            ...request.context,
            dryRun: true,
        },
    });
    if (!validation.ok) {
        return validation;
    }
    const selection = selectShellArgumentAssemblyPractice({
        executor: request.executor,
        provider: request.provider,
        preferredProvider: request.preferredProvider,
    });
    if (selection.provider === undefined) {
        return argumentAssemblyProviderFailure("PROVIDER_UNAVAILABLE", "shell.argumentAssembly provider-backed generation requires an injected runtime provider");
    }
    try {
        const providerResult = await selection.provider({
            ...request,
            context: {
                ...request.context,
                auditMetadata: {
                    ...(request.context?.auditMetadata ?? {}),
                    ...buildShellArgumentAssemblyPracticeAuditMetadata(selection),
                },
            },
        });
        return normalizeShellArgumentAssemblyProviderResult(providerResult);
    }
    catch {
        return argumentAssemblyProviderFailure("PROVIDER_REJECTED", "shell.argumentAssembly provider rejected the generation request");
    }
}
export const shellArgumentAssemblyBaseToolDefinition = createShellBaseToolDefinition({
    toolId: "shell.argumentAssembly",
    title: "Shell Argument Assembly",
    description: "Assemble shell executable, options, and positional values into an auditable argv envelope.",
    summary: "Use shell.argumentAssembly to build argv material before command generation.",
    storageGroup: "shellGeneration",
    riskLevel: "normal",
    permissionHints: ["shell:generate"],
    dependencies: shellArgumentAssemblyDependencyDeclarations,
    inputSchema: jsonSchema("shell.argumentAssembly.input", {
        type: "object",
        additionalProperties: true,
        required: ["executable"],
    }),
    outputSchema: jsonSchema("shell.argumentAssembly.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 shellArgumentAssemblyHandler = {
    definition: shellArgumentAssemblyBaseToolDefinition,
    async invoke(request) {
        const input = isShellGenerationRecord(request.input) ? request.input : {};
        const inputContext = isShellGenerationRecord(input.context) ? input.context : {};
        const auditMetadata = isShellGenerationRecord(inputContext.auditMetadata) ? inputContext.auditMetadata : undefined;
        const selection = selectShellArgumentAssemblyPractice({
            preferredProvider: input.preferredProvider,
        });
        return adaptResult(await assembleShellArgumentsBestPractice({
            ...input,
            executor: request.executor,
            context: {
                ...inputContext,
                runtimeId: typeof inputContext.runtimeId === "string" ? inputContext.runtimeId : request.runtimeId,
                invocationId: typeof inputContext.invocationId === "string" ? inputContext.invocationId : request.toolCallId,
                auditMetadata: injectRuntimeInvocationMetadata({
                    ...buildShellArgumentAssemblyPracticeAuditMetadata(selection),
                    ...(request.metadata ?? {}),
                }, auditMetadata, request),
            },
        }));
    },
};
