import { join, relative } from "node:path";
import { writeGeneratedFile } from "./write-generated-file.js";
import { mergeAppExtensions } from "./merge-app-extensions.js";
export async function writeServiceManifestFile(rootDir, entries, appExtensions, dependencyReport, options = {}) {
    const filePath = join(rootDir, ".vext", "inspect", "services.manifest.json");
    const content = `${JSON.stringify(buildServiceManifestPayload(rootDir, entries, appExtensions, dependencyReport), null, 2)}\n`;
    return writeGeneratedFile(filePath, content, options);
}
export function buildServiceManifestPayload(rootDir, entries, appExtensions, dependencyReport) {
    const mergedAppExtensions = mergeAppExtensions(appExtensions).entries;
    const dependencyEdges = [...dependencyReport.graph.entries()]
        .flatMap(([from, targets]) => [...targets].sort((a, b) => a.localeCompare(b)).map((to) => ({ from, to })))
        .sort((a, b) => {
        const fromCompare = a.from.localeCompare(b.from);
        return fromCompare !== 0 ? fromCompare : a.to.localeCompare(b.to);
    });
    const cycles = dependencyReport.diagnostics
        .map((diagnostic) => diagnostic.relatedKeys)
        .filter((value) => Array.isArray(value) && value.length > 0)
        .map((cycle) => [...cycle])
        .sort((a, b) => a.join(".").localeCompare(b.join(".")));
    const services = entries.map((entry) => ({
        serviceKey: entry.serviceKey,
        keySegments: [...entry.keySegments],
        fileRelativePath: toPortableRelativePath(rootDir, entry.filePath),
        importPath: entry.importPath,
    }));
    return {
        schemaVersion: 1,
        kind: "services-manifest",
        target: "services",
        serviceCount: services.length,
        appExtensionCount: mergedAppExtensions.length,
        summary: {
            topLevelServices: new Set(entries.map((entry) => entry.keySegments[0]).filter(Boolean)).size,
            nestedServices: entries.filter((entry) => entry.keySegments.length > 1).length,
            dependencyEdges: dependencyEdges.length,
            dependencyCycles: cycles.length,
            conflictingAppExtensions: mergedAppExtensions.filter((entry) => entry.conflict).length,
            lowConfidenceAppExtensions: mergedAppExtensions.filter((entry) => entry.confidence !== "high").length,
        },
        services,
        appExtensions: mergedAppExtensions.map((entry) => ({
            propertyKey: entry.propertyKey,
            inferredTypeText: entry.inferredTypeText,
            pluginRelativePaths: entry.pluginFiles.map((filePath) => toPortableRelativePath(rootDir, filePath)),
            sourceKinds: [...entry.sourceKinds],
            confidence: entry.confidence,
            conflict: entry.conflict,
        })),
        dependencies: {
            edges: dependencyEdges,
            cycles,
        },
    };
}
function toPortableRelativePath(rootDir, filePath) {
    return relative(rootDir, filePath).replace(/\\/gu, "/");
}
