import path from "node:path";
import { fileURLToPath } from "node:url";
const lspSharedRoot = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(lspSharedRoot, "../../../../../../");
export function architectureRelativePath(absolutePath) {
    return path.relative(repoRoot, absolutePath).split(path.sep).join("/");
}
export function lspToolSkillDocPath(toolId) {
    return path
        .join(repoRoot, "src", "storagePool", "baseToolStorage", "codeBase", "lsp", toolId, `${toolId}.md`)
        .split(path.sep)
        .join("/");
}
export function lspToolSourcePath(toolId) {
    return path
        .join(repoRoot, "src", "agentCore", "agent_executionEngine", "basic_toolLayer", "baseTools", "codeBase", "lsp", `${toolId}.ts`)
        .split(path.sep)
        .join("/");
}
export function lspToolStoragePracticePath(toolId) {
    return path
        .join(repoRoot, "src", "storagePool", "baseToolStorage", "codeBase", "lsp", toolId, "bestPractice.ts")
        .split(path.sep)
        .join("/");
}
export function jsonSchema(name, schema) {
    return {
        kind: "json-schema",
        name,
        schema,
    };
}
export function normalizeLspDependencyDeclarations(dependencyIds, descriptions = {}) {
    return dependencyIds.map((dependencyId) => ({
        dependencyId,
        kind: dependencyId.includes("workspace.read")
            ? "permission"
            : dependencyId.includes("stdioJsonRpc")
                ? "runtime"
                : dependencyId.includes("lsp.server")
                    ? "runtime"
                    : dependencyId.includes("workspace.edit")
                        ? "permission"
                        : "runtime",
        required: true,
        description: descriptions[dependencyId] ?? dependencyId,
    }));
}
export const lspCommonSchemaFragments = {
    lspPosition: {
        type: "object",
        additionalProperties: false,
        required: ["line", "character"],
        properties: {
            line: { type: "integer", minimum: 0 },
            character: { type: "integer", minimum: 0 },
        },
    },
    lspRange: {
        type: "object",
        additionalProperties: false,
        required: ["start", "end"],
        properties: {
            start: {
                type: "object",
                additionalProperties: false,
                required: ["line", "character"],
                properties: {
                    line: { type: "integer", minimum: 0 },
                    character: { type: "integer", minimum: 0 },
                },
            },
            end: {
                type: "object",
                additionalProperties: false,
                required: ["line", "character"],
                properties: {
                    line: { type: "integer", minimum: 0 },
                    character: { type: "integer", minimum: 0 },
                },
            },
        },
    },
    invocationContext: {
        type: "object",
        additionalProperties: true,
        properties: {
            invocationId: { type: "string" },
            workspaceRoot: { type: "string" },
            dryRun: { type: "boolean" },
            preferredProvider: { type: "string", enum: ["anthropic", "openai", "deepmind", "praxis-native"] },
        },
    },
};
export function createLspBaseToolDefinition(options) {
    return {
        toolId: options.toolId,
        source: "builtin",
        family: "code",
        group: "lsp",
        title: options.title,
        description: options.description,
        toolSkill: {
            docPath: lspToolSkillDocPath(options.toolId),
            summary: options.summary,
            riskLevel: options.riskLevel ?? "normal",
        },
        inputSchema: options.inputSchema ?? jsonSchema(`${options.toolId}.input`, { type: "object", additionalProperties: true }),
        outputSchema: options.outputSchema ?? jsonSchema(`${options.toolId}.output`, { type: "object", additionalProperties: true }),
        riskLevel: options.riskLevel ?? "normal",
        permissionHints: [...options.permissionHints],
        dependencies: options.dependencies,
        storagePolicy: options.storagePolicy ?? {
            storesMaterial: true,
            storesResult: true,
            storesAudit: true,
            reusable: true,
        },
        sourcePath: lspToolSourcePath(options.toolId),
        metadata: {
            storagePracticePath: lspToolStoragePracticePath(options.toolId),
            ...(options.metadata ?? {}),
        },
    };
}
function normalizePracticeSource(practice) {
    if (typeof practice.source === "string") {
        return {
            sourceLabel: practice.source,
            sourceKind: undefined,
            sourcePath: undefined,
        };
    }
    return {
        sourceLabel: practice.source.label,
        sourceKind: practice.source.kind,
        sourcePath: practice.source.path,
    };
}
export function orderLspPractices(practices, preferredProvider) {
    if (preferredProvider === undefined) {
        return practices;
    }
    return [
        ...practices.filter((practice) => practice.providerName === preferredProvider),
        ...practices.filter((practice) => practice.providerName !== preferredProvider),
    ];
}
export function selectLspPractice(practices, preferredProvider) {
    const selected = orderLspPractices(practices, preferredProvider)[0];
    if (selected === undefined) {
        return {
            providerName: "praxis-native",
            sourceLabel: "Praxis native runtime fallback",
            sourceKind: "praxis-native",
            directCliSupport: false,
            sideEffectPolicy: "read-only",
            notes: ["No provider practice metadata was registered for this LSP tool."],
        };
    }
    return {
        providerName: selected.providerName,
        ...normalizePracticeSource(selected),
        directCliSupport: selected.directCliSupport,
        sideEffectPolicy: selected.sideEffectPolicy,
        notes: selected.notes ?? [],
    };
}
export function buildPracticeAuditMetadata(selection) {
    return {
        selectedPractice: selection.providerName,
        selectedPracticeSource: selection.sourceLabel,
        selectedPracticeSourceKind: selection.sourceKind,
        selectedPracticeSourcePath: selection.sourcePath,
        directCliSupport: selection.directCliSupport,
        sideEffectPolicy: selection.sideEffectPolicy,
    };
}
export function adaptLspToolResultToInvokeResult(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 function createLspCoreHandler(definition, invokeCore) {
    return {
        definition,
        async invoke(request) {
            return adaptLspToolResultToInvokeResult(await invokeCore(request));
        },
    };
}
export function injectInvocationAudit(metadata, auditMetadata, request) {
    return {
        ...(auditMetadata ?? {}),
        runtimeId: request.runtimeId,
        sessionId: request.sessionId,
        toolCallId: request.toolCallId,
        ...(metadata ?? {}),
    };
}
export function normalizeDocumentUriToFilePath(documentUri, workspaceRoot) {
    const trimmed = documentUri.trim();
    if (trimmed.startsWith("file://")) {
        return fileURLToPath(trimmed);
    }
    if (path.isAbsolute(trimmed)) {
        return trimmed;
    }
    return path.resolve(workspaceRoot?.trim() || process.cwd(), trimmed);
}
export function attachAuditMetadata(audit, metadata) {
    return (audit ?? []).map((event) => ({
        ...event,
        metadata: {
            ...(event.metadata ?? {}),
            ...metadata,
        },
    }));
}
export function baseToolInvokeSuccess(toolId, output, events, metadata) {
    return {
        ok: true,
        toolId,
        output,
        events,
        metadata,
    };
}
export function baseToolInvokeFailure(toolId, code, message, events) {
    return {
        ok: false,
        toolId,
        error: {
            code,
            message,
            publicSafe: true,
        },
        events,
    };
}
export function preferAnthropicExecutor(executor, hasMethod, practices, preferredProvider) {
    if (executor !== undefined && hasMethod(executor)) {
        const anthropic = practices.find((practice) => practice.providerName === "anthropic");
        if (anthropic !== undefined && (preferredProvider === undefined || preferredProvider === anthropic.providerName)) {
            return {
                providerName: anthropic.providerName,
                ...normalizePracticeSource(anthropic),
                directCliSupport: anthropic.directCliSupport,
                sideEffectPolicy: anthropic.sideEffectPolicy,
                notes: anthropic.notes ?? [],
            };
        }
    }
    return selectLspPractice(practices, preferredProvider);
}
