"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.createArchitectureBaseline = createArchitectureBaseline;
exports.updateArchitectureBaseline = updateArchitectureBaseline;
exports.checkArchitectureBaseline = checkArchitectureBaseline;
const path = __importStar(require("node:path"));
const node_fs_1 = require("node:fs");
const architectureMap_1 = require("./architectureMap");
const architectureBaselineMetadataVersion = 1;
function normalizePath(value) {
    return value.replace(/\\/g, '/');
}
function baselineFilePath(workspaceRoot) {
    return path.join(workspaceRoot, '.archpilot', 'baseline', 'architecture-baseline.json');
}
function driftReportFilePath(workspaceRoot) {
    return path.join(workspaceRoot, '.archpilot', 'reports', 'architecture-drift.json');
}
function sortUnique(values) {
    return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
function sortEdges(edges) {
    return [...edges].sort((left, right) => {
        const sourceCompare = left.source.localeCompare(right.source);
        if (sourceCompare !== 0) {
            return sourceCompare;
        }
        return left.target.localeCompare(right.target);
    });
}
function sortCycles(cycles) {
    return [...cycles]
        .map((cycle) => [...cycle])
        .sort((left, right) => left.join('->').localeCompare(right.join('->')));
}
function toCycleDisplay(cycle) {
    if (cycle.length === 0) {
        return '';
    }
    return `${cycle.join(' -> ')} -> ${cycle[0]}`;
}
function cycleKey(cycle) {
    return cycle.join('->');
}
function edgeKey(edge) {
    return `${edge.source}->${edge.target}`;
}
function buildBaselineSnapshot(map, options) {
    const modules = [...map.modules].sort((left, right) => left.moduleName.localeCompare(right.moduleName));
    const edges = sortEdges([...map.edges]);
    const cycles = sortCycles([...map.cycles]);
    const orphanModules = sortUnique(map.hotspots.orphanModules);
    return {
        metadataVersion: architectureBaselineMetadataVersion,
        projectName: map.projectName,
        createdAtUtc: options?.createdAtUtc ?? new Date().toISOString(),
        modules,
        edges,
        cycles,
        orphanModules,
    };
}
async function writeBaselineFile(workspaceRoot, baseline) {
    const filePath = baselineFilePath(workspaceRoot);
    await node_fs_1.promises.mkdir(path.dirname(filePath), { recursive: true });
    await node_fs_1.promises.writeFile(filePath, `${JSON.stringify(baseline, null, 2)}\n`, { encoding: 'utf8' });
    return filePath;
}
async function readBaselineFile(workspaceRoot) {
    const filePath = baselineFilePath(workspaceRoot);
    let content;
    try {
        content = await node_fs_1.promises.readFile(filePath, { encoding: 'utf8' });
    }
    catch (error) {
        if (error.code === 'ENOENT') {
            return { kind: 'missing', baselinePath: filePath };
        }
        return {
            kind: 'invalid',
            baselinePath: filePath,
            details: error instanceof Error ? error.message : 'Unable to read baseline file.',
        };
    }
    try {
        const parsed = JSON.parse(content);
        if (!parsed ||
            typeof parsed !== 'object' ||
            !Array.isArray(parsed.modules) ||
            !Array.isArray(parsed.edges) ||
            !Array.isArray(parsed.cycles)) {
            return {
                kind: 'invalid',
                baselinePath: filePath,
                details: 'Baseline JSON does not match the expected structure. Regenerate baseline.',
            };
        }
        return {
            kind: 'ok',
            baseline: {
                metadataVersion: architectureBaselineMetadataVersion,
                projectName: parsed.projectName,
                createdAtUtc: parsed.createdAtUtc,
                modules: [...parsed.modules].sort((left, right) => left.moduleName.localeCompare(right.moduleName)),
                edges: sortEdges([...parsed.edges]),
                cycles: sortCycles([...parsed.cycles]),
                orphanModules: sortUnique(parsed.orphanModules ?? []),
            },
            baselinePath: filePath,
        };
    }
    catch {
        return {
            kind: 'invalid',
            baselinePath: filePath,
            details: 'Baseline JSON is invalid.',
        };
    }
}
async function createArchitectureBaseline(workspaceRoot, options) {
    const filePath = baselineFilePath(workspaceRoot);
    if (!options?.force) {
        try {
            await node_fs_1.promises.access(filePath);
            return { created: false, baselinePath: filePath, reason: 'exists' };
        }
        catch {
            // file missing is expected for create.
        }
    }
    const map = await (0, architectureMap_1.generateArchitectureMap)(workspaceRoot);
    const baseline = buildBaselineSnapshot(map);
    const baselinePath = await writeBaselineFile(workspaceRoot, baseline);
    return { created: true, baselinePath, baseline };
}
async function updateArchitectureBaseline(workspaceRoot) {
    const map = await (0, architectureMap_1.generateArchitectureMap)(workspaceRoot);
    const baseline = buildBaselineSnapshot(map);
    const baselinePath = await writeBaselineFile(workspaceRoot, baseline);
    return { baselinePath, baseline };
}
async function checkArchitectureBaseline(workspaceRoot) {
    const baselineLoad = await readBaselineFile(workspaceRoot);
    if (baselineLoad.kind === 'missing') {
        return { kind: 'baseline-missing', baselinePath: baselineLoad.baselinePath };
    }
    if (baselineLoad.kind === 'invalid') {
        return {
            kind: 'baseline-invalid',
            baselinePath: baselineLoad.baselinePath,
            details: baselineLoad.details,
        };
    }
    const currentMap = await (0, architectureMap_1.generateArchitectureMap)(workspaceRoot);
    const currentModules = sortUnique(currentMap.modules.map((moduleEntry) => moduleEntry.moduleName));
    const baselineModules = sortUnique(baselineLoad.baseline.modules.map((moduleEntry) => moduleEntry.moduleName));
    const currentModuleSet = new Set(currentModules);
    const baselineModuleSet = new Set(baselineModules);
    const modulesAdded = currentModules.filter((moduleName) => !baselineModuleSet.has(moduleName));
    const modulesRemoved = baselineModules.filter((moduleName) => !currentModuleSet.has(moduleName));
    const currentEdgeMap = new Map(sortEdges([...currentMap.edges]).map((edge) => [
        edgeKey(edge),
        { source: edge.source, target: edge.target },
    ]));
    const baselineEdgeMap = new Map(sortEdges([...baselineLoad.baseline.edges]).map((edge) => [
        edgeKey(edge),
        { source: edge.source, target: edge.target },
    ]));
    const dependenciesAdded = [...currentEdgeMap.entries()]
        .filter(([key]) => !baselineEdgeMap.has(key))
        .map(([, edge]) => edge)
        .sort((left, right) => {
        const sourceCompare = left.source.localeCompare(right.source);
        if (sourceCompare !== 0) {
            return sourceCompare;
        }
        return left.target.localeCompare(right.target);
    });
    const dependenciesRemoved = [...baselineEdgeMap.entries()]
        .filter(([key]) => !currentEdgeMap.has(key))
        .map(([, edge]) => edge)
        .sort((left, right) => {
        const sourceCompare = left.source.localeCompare(right.source);
        if (sourceCompare !== 0) {
            return sourceCompare;
        }
        return left.target.localeCompare(right.target);
    });
    const currentCycles = sortCycles([...currentMap.cycles]);
    const baselineCycles = sortCycles([...baselineLoad.baseline.cycles]);
    const currentCycleMap = new Map(currentCycles.map((cycle) => [cycleKey(cycle), cycle]));
    const baselineCycleMap = new Map(baselineCycles.map((cycle) => [cycleKey(cycle), cycle]));
    const cyclesAdded = [...currentCycleMap.entries()]
        .filter(([key]) => !baselineCycleMap.has(key))
        .map(([, cycle]) => toCycleDisplay(cycle))
        .sort((left, right) => left.localeCompare(right));
    const cyclesRemoved = [...baselineCycleMap.entries()]
        .filter(([key]) => !currentCycleMap.has(key))
        .map(([, cycle]) => toCycleDisplay(cycle))
        .sort((left, right) => left.localeCompare(right));
    const report = {
        reportVersion: 1,
        projectName: currentMap.projectName,
        generatedAtUtc: new Date().toISOString(),
        baselineCreatedAtUtc: baselineLoad.baseline.createdAtUtc,
        modulesAdded,
        modulesRemoved,
        dependenciesAdded,
        dependenciesRemoved,
        cyclesAdded,
        cyclesRemoved,
        summaryCounts: {
            modulesAdded: modulesAdded.length,
            modulesRemoved: modulesRemoved.length,
            dependenciesAdded: dependenciesAdded.length,
            dependenciesRemoved: dependenciesRemoved.length,
            cyclesAdded: cyclesAdded.length,
            cyclesRemoved: cyclesRemoved.length,
            totalChanges: modulesAdded.length +
                modulesRemoved.length +
                dependenciesAdded.length +
                dependenciesRemoved.length +
                cyclesAdded.length +
                cyclesRemoved.length,
        },
    };
    const driftPath = driftReportFilePath(workspaceRoot);
    await node_fs_1.promises.mkdir(path.dirname(driftPath), { recursive: true });
    await node_fs_1.promises.writeFile(driftPath, `${JSON.stringify(report, null, 2)}\n`, { encoding: 'utf8' });
    return {
        kind: 'ok',
        driftDetected: report.summaryCounts.totalChanges > 0,
        report,
        baselinePath: normalizePath(baselineLoad.baselinePath),
        driftReportPath: normalizePath(driftPath),
    };
}
//# sourceMappingURL=architectureBaseline.js.map