"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.buildGovernanceBaselineFromReviewSummary = buildGovernanceBaselineFromReviewSummary;
exports.getGovernanceBaselinePath = getGovernanceBaselinePath;
exports.writeGovernanceBaseline = writeGovernanceBaseline;
exports.createGovernanceBaselineFromSummaryArtifact = createGovernanceBaselineFromSummaryArtifact;
exports.readGovernanceBaseline = readGovernanceBaseline;
exports.compareWithGovernanceBaseline = compareWithGovernanceBaseline;
exports.getBaselineComparisonReportPath = getBaselineComparisonReportPath;
exports.writeBaselineComparisonReport = writeBaselineComparisonReport;
const path = __importStar(require("node:path"));
const node_fs_1 = require("node:fs");
function sortUnique(values) {
    return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
function normalizePath(value) {
    return value.replace(/\\/g, '/');
}
function baselineFindingKey(entry) {
    return [
        entry.id,
        entry.severity,
        entry.kind,
        entry.message,
        entry.sourceFile ? normalizePath(entry.sourceFile) : '',
    ].join('|');
}
function toBaselineFinding(entry) {
    return {
        key: baselineFindingKey(entry),
        id: entry.id,
        severity: entry.severity,
        kind: entry.kind,
        message: entry.message,
        ...(entry.sourceFile ? { sourceFile: normalizePath(entry.sourceFile) } : {}),
    };
}
function compareFindings(left, right) {
    return left.key.localeCompare(right.key);
}
function parseCategoryScores(value) {
    if (!value || typeof value !== 'object' || Array.isArray(value)) {
        return undefined;
    }
    const typed = value;
    const entries = Object.entries(typed)
        .filter(([key, entry]) => key.trim().length > 0 && typeof entry === 'number')
        .map(([key, entry]) => [key, Math.max(0, Math.min(100, Math.round(entry)))])
        .sort(([left], [right]) => left.localeCompare(right));
    return Object.fromEntries(entries);
}
function parseSummaryArtifact(value) {
    if (!value || typeof value !== 'object' || Array.isArray(value)) {
        return undefined;
    }
    const typed = value;
    if (typeof typed.projectName !== 'string' ||
        typeof typed.generatedAtUtc !== 'string' ||
        typeof typed.healthScore !== 'number' ||
        typeof typed.readinessScore !== 'number' ||
        typeof typed.findingCount !== 'number' ||
        typeof typed.remainingViolationsCount !== 'number' ||
        !typed.counts ||
        typeof typed.counts !== 'object' ||
        !Array.isArray(typed.findings) ||
        !typed.changeRisk ||
        typeof typed.changeRisk !== 'object') {
        return undefined;
    }
    const counts = typed.counts;
    const changeRisk = typed.changeRisk;
    const categoryScores = parseCategoryScores(typed.categoryScores);
    const readinessCategoryScores = parseCategoryScores(typed.readinessCategoryScores);
    if (typeof counts.errors !== 'number' ||
        typeof counts.warnings !== 'number' ||
        typeof counts.info !== 'number' ||
        typeof counts.passed !== 'number' ||
        !categoryScores ||
        !readinessCategoryScores ||
        typeof changeRisk.riskLevel !== 'string' ||
        typeof changeRisk.score !== 'number' ||
        typeof changeRisk.summary !== 'string') {
        return undefined;
    }
    const findings = typed.findings
        .filter((entry) => entry && typeof entry === 'object')
        .map((entry) => entry)
        .filter((entry) => typeof entry.id === 'string' &&
        typeof entry.severity === 'string' &&
        typeof entry.kind === 'string' &&
        typeof entry.message === 'string')
        .map((entry) => ({
        id: entry.id,
        severity: entry.severity,
        kind: entry.kind,
        message: entry.message,
        ...(typeof entry.sourceFile === 'string' ? { sourceFile: entry.sourceFile } : {}),
    }));
    const suppressionRaw = typed.suppressionSummary && typeof typed.suppressionSummary === 'object'
        ? typed.suppressionSummary
        : undefined;
    const suppressionSummary = suppressionRaw &&
        typeof suppressionRaw.configuredSuppressions === 'number' &&
        typeof suppressionRaw.activeSuppressions === 'number' &&
        typeof suppressionRaw.expiredSuppressions === 'number' &&
        typeof suppressionRaw.unusedSuppressions === 'number' &&
        typeof suppressionRaw.findingsSuppressed === 'number'
        ? {
            configuredSuppressions: suppressionRaw.configuredSuppressions,
            activeSuppressions: suppressionRaw.activeSuppressions,
            expiredSuppressions: suppressionRaw.expiredSuppressions,
            unusedSuppressions: suppressionRaw.unusedSuppressions,
            findingsSuppressed: suppressionRaw.findingsSuppressed,
        }
        : undefined;
    const impactRaw = typed.impactAnalysis && typeof typed.impactAnalysis === 'object'
        ? typed.impactAnalysis
        : undefined;
    const impactAnalysis = impactRaw &&
        Array.isArray(impactRaw.changedModules) &&
        Array.isArray(impactRaw.directDependents) &&
        Array.isArray(impactRaw.transitiveDependents) &&
        typeof impactRaw.totalAffectedModules === 'number' &&
        typeof impactRaw.impactRadiusScore === 'number' &&
        typeof impactRaw.impactLevel === 'string'
        ? {
            changedModules: sortUnique(impactRaw.changedModules
                .filter((entry) => typeof entry === 'string')
                .map((entry) => entry)),
            directDependents: sortUnique(impactRaw.directDependents
                .filter((entry) => typeof entry === 'string')
                .map((entry) => entry)),
            transitiveDependents: sortUnique(impactRaw.transitiveDependents
                .filter((entry) => typeof entry === 'string')
                .map((entry) => entry)),
            totalAffectedModules: Math.max(0, Math.floor(impactRaw.totalAffectedModules)),
            impactRadiusScore: Math.max(0, Math.floor(impactRaw.impactRadiusScore)),
            impactLevel: impactRaw.impactLevel === 'HIGH' || impactRaw.impactLevel === 'MEDIUM'
                ? impactRaw.impactLevel
                : 'LOW',
        }
        : undefined;
    return {
        projectName: typed.projectName,
        generatedAtUtc: typed.generatedAtUtc,
        healthScore: Math.max(0, Math.min(100, Math.round(typed.healthScore))),
        readinessScore: Math.max(0, Math.min(100, Math.round(typed.readinessScore))),
        categoryScores,
        readinessCategoryScores,
        counts: {
            errors: Math.max(0, Math.floor(counts.errors)),
            warnings: Math.max(0, Math.floor(counts.warnings)),
            info: Math.max(0, Math.floor(counts.info)),
            passed: Math.max(0, Math.floor(counts.passed)),
        },
        findingCount: Math.max(0, Math.floor(typed.findingCount)),
        remainingViolationsCount: Math.max(0, Math.floor(typed.remainingViolationsCount)),
        ...(suppressionSummary ? { suppressionSummary } : {}),
        findings,
        changeRisk: {
            riskLevel: changeRisk.riskLevel === 'high' || changeRisk.riskLevel === 'medium'
                ? changeRisk.riskLevel
                : 'low',
            score: Math.max(0, Math.floor(changeRisk.score)),
            summary: changeRisk.summary,
        },
        ...(impactAnalysis ? { impactAnalysis } : {}),
    };
}
function buildBaselineFromSummaryArtifact(artifact, nowUtcIso) {
    return {
        reportVersion: 1,
        projectName: artifact.projectName,
        capturedAtUtc: nowUtcIso ?? new Date().toISOString(),
        sourceSummaryGeneratedAtUtc: artifact.generatedAtUtc,
        healthScore: artifact.healthScore,
        readinessScore: artifact.readinessScore,
        categoryScores: artifact.categoryScores,
        readinessCategoryScores: artifact.readinessCategoryScores,
        counts: artifact.counts,
        findingCount: artifact.findingCount,
        remainingViolationsCount: artifact.remainingViolationsCount,
        ...(artifact.suppressionSummary ? { suppressionSummary: artifact.suppressionSummary } : {}),
        findings: artifact.findings.map((entry) => toBaselineFinding(entry)).sort(compareFindings),
        changeRisk: artifact.changeRisk,
        ...(artifact.impactAnalysis ? { impactAnalysis: artifact.impactAnalysis } : {}),
    };
}
function buildGovernanceBaselineFromReviewSummary(summary, nowUtcIso) {
    return {
        reportVersion: 1,
        projectName: summary.projectName,
        capturedAtUtc: nowUtcIso ?? new Date().toISOString(),
        sourceSummaryGeneratedAtUtc: summary.generatedAtUtc,
        healthScore: summary.healthScore,
        readinessScore: summary.readinessScore,
        categoryScores: summary.categoryScores,
        readinessCategoryScores: summary.readinessCategoryScores,
        counts: {
            errors: summary.counts.errors,
            warnings: summary.counts.warnings,
            info: summary.counts.info,
            passed: summary.counts.passed,
        },
        findingCount: summary.findings.length,
        remainingViolationsCount: summary.findings.filter((finding) => finding.kind === 'violation')
            .length,
        findings: summary.findings
            .map((entry) => toBaselineFinding({
            id: entry.id,
            severity: entry.severity,
            kind: entry.kind,
            message: entry.message,
            ...(entry.sourceFile ? { sourceFile: entry.sourceFile } : {}),
        }))
            .sort(compareFindings),
        changeRisk: {
            riskLevel: summary.changeRisk.riskLevel,
            score: summary.changeRisk.score,
            summary: summary.changeRisk.summary,
        },
        ...(summary.impactAnalysis ? { impactAnalysis: summary.impactAnalysis } : {}),
    };
}
function getGovernanceBaselinePath(workspaceRoot) {
    return path.join(workspaceRoot, '.archpilot', 'baseline', 'baseline.json');
}
async function writeGovernanceBaseline(workspaceRoot, baseline) {
    const baselinePath = getGovernanceBaselinePath(workspaceRoot);
    await node_fs_1.promises.mkdir(path.dirname(baselinePath), { recursive: true });
    await node_fs_1.promises.writeFile(baselinePath, `${JSON.stringify(baseline, null, 2)}\n`, {
        encoding: 'utf8',
    });
    return baselinePath;
}
async function createGovernanceBaselineFromSummaryArtifact(workspaceRoot) {
    const summaryPath = path.join(workspaceRoot, '.archpilot', 'reports', 'architecture-summary.json');
    const content = await node_fs_1.promises.readFile(summaryPath, { encoding: 'utf8' });
    const parsed = parseSummaryArtifact(JSON.parse(content));
    if (!parsed) {
        throw new Error('architecture-summary.json is missing required fields. Run `archpilot validate` first.');
    }
    const baseline = buildBaselineFromSummaryArtifact(parsed);
    const baselinePath = await writeGovernanceBaseline(workspaceRoot, baseline);
    return { baselinePath, baseline };
}
async function readGovernanceBaseline(workspaceRoot) {
    const baselinePath = getGovernanceBaselinePath(workspaceRoot);
    try {
        const content = await node_fs_1.promises.readFile(baselinePath, { encoding: 'utf8' });
        const parsed = JSON.parse(content);
        if (!parsed || typeof parsed !== 'object') {
            return { kind: 'invalid', baselinePath, details: 'Baseline JSON is invalid.' };
        }
        const typed = parsed;
        if (typeof typed.projectName !== 'string' ||
            typeof typed.capturedAtUtc !== 'string' ||
            typeof typed.sourceSummaryGeneratedAtUtc !== 'string' ||
            typeof typed.healthScore !== 'number' ||
            typeof typed.readinessScore !== 'number' ||
            !Array.isArray(typed.findings) ||
            !typed.counts ||
            typeof typed.counts !== 'object') {
            return {
                kind: 'invalid',
                baselinePath,
                details: 'Baseline JSON does not match expected governance baseline shape.',
            };
        }
        const summaryArtifact = parseSummaryArtifact({
            projectName: typed.projectName,
            generatedAtUtc: typed.sourceSummaryGeneratedAtUtc,
            healthScore: typed.healthScore,
            readinessScore: typed.readinessScore,
            categoryScores: typed.categoryScores,
            readinessCategoryScores: typed.readinessCategoryScores,
            counts: typed.counts,
            findingCount: typed.findingCount,
            remainingViolationsCount: typed.remainingViolationsCount,
            suppressionSummary: typed.suppressionSummary,
            findings: typed.findings,
            changeRisk: typed.changeRisk,
            impactAnalysis: typed.impactAnalysis,
        });
        if (!summaryArtifact) {
            return {
                kind: 'invalid',
                baselinePath,
                details: 'Baseline JSON contains invalid summary snapshot fields.',
            };
        }
        return {
            kind: 'ok',
            baselinePath,
            baseline: {
                ...buildBaselineFromSummaryArtifact(summaryArtifact, typed.capturedAtUtc),
                capturedAtUtc: typed.capturedAtUtc,
            },
        };
    }
    catch (error) {
        if (error.code === 'ENOENT') {
            return { kind: 'missing', baselinePath };
        }
        return {
            kind: 'invalid',
            baselinePath,
            details: error instanceof Error ? error.message : 'Unable to read baseline JSON.',
        };
    }
}
function compareFindingsByKey(current, baseline) {
    const currentMap = new Map(current.map((entry) => [entry.key, entry]));
    const baselineMap = new Map(baseline.map((entry) => [entry.key, entry]));
    const newlyIntroducedFindings = [...currentMap.entries()]
        .filter(([key]) => !baselineMap.has(key))
        .map(([, entry]) => entry)
        .sort(compareFindings);
    const resolvedFindings = [...baselineMap.entries()]
        .filter(([key]) => !currentMap.has(key))
        .map(([, entry]) => entry)
        .sort(compareFindings);
    const unchangedFindings = [...currentMap.entries()]
        .filter(([key]) => baselineMap.has(key))
        .map(([, entry]) => entry)
        .sort(compareFindings);
    return { newlyIntroducedFindings, resolvedFindings, unchangedFindings };
}
function compareWithGovernanceBaseline(currentSummary, baselineLoad) {
    const currentFindings = currentSummary.findings
        .map((entry) => toBaselineFinding({
        id: entry.id,
        severity: entry.severity,
        kind: entry.kind,
        message: entry.message,
        ...(entry.sourceFile ? { sourceFile: entry.sourceFile } : {}),
    }))
        .sort(compareFindings);
    const currentRemainingViolations = currentSummary.findings.filter((entry) => entry.kind === 'violation').length;
    if (baselineLoad.kind !== 'ok') {
        return {
            reportVersion: 1,
            baselineAvailable: false,
            status: 'NO_BASELINE',
            summary: baselineLoad.kind === 'invalid'
                ? `Baseline unavailable: ${baselineLoad.details}`
                : 'No baseline found. Run `archpilot baseline refresh` after validation.',
            current: {
                projectName: currentSummary.projectName,
                generatedAtUtc: currentSummary.generatedAtUtc,
                healthScore: currentSummary.healthScore,
                readinessScore: currentSummary.readinessScore,
            },
            deltas: {
                healthScoreDelta: 0,
                readinessScoreDelta: 0,
                errorDelta: 0,
                warningDelta: 0,
                findingDelta: 0,
                remainingViolationsDelta: 0,
            },
            newlyIntroducedFindings: currentFindings,
            resolvedFindings: [],
            unchangedFindings: [],
        };
    }
    const baseline = baselineLoad.baseline;
    const comparison = compareFindingsByKey(currentFindings, baseline.findings);
    const deltas = {
        healthScoreDelta: currentSummary.healthScore - baseline.healthScore,
        readinessScoreDelta: currentSummary.readinessScore - baseline.readinessScore,
        errorDelta: currentSummary.counts.errors - baseline.counts.errors,
        warningDelta: currentSummary.counts.warnings - baseline.counts.warnings,
        findingDelta: currentFindings.length - baseline.findings.length,
        remainingViolationsDelta: currentRemainingViolations - baseline.remainingViolationsCount,
    };
    const hasRegression = deltas.healthScoreDelta < 0 ||
        deltas.readinessScoreDelta < 0 ||
        deltas.errorDelta > 0 ||
        deltas.warningDelta > 0 ||
        deltas.findingDelta > 0 ||
        deltas.remainingViolationsDelta > 0 ||
        comparison.newlyIntroducedFindings.length > 0;
    const hasImprovement = deltas.healthScoreDelta > 0 ||
        deltas.readinessScoreDelta > 0 ||
        deltas.errorDelta < 0 ||
        deltas.warningDelta < 0 ||
        deltas.findingDelta < 0 ||
        deltas.remainingViolationsDelta < 0 ||
        comparison.resolvedFindings.length > 0;
    const status = hasRegression
        ? 'REGRESSED'
        : hasImprovement
            ? 'IMPROVED'
            : 'STABLE';
    const summary = status === 'REGRESSED'
        ? `Baseline regression detected: +${comparison.newlyIntroducedFindings.length} new finding(s), ${comparison.resolvedFindings.length} resolved, health delta ${deltas.healthScoreDelta}.`
        : status === 'IMPROVED'
            ? `Baseline improvement detected: ${comparison.resolvedFindings.length} finding(s) resolved, health delta +${deltas.healthScoreDelta}.`
            : 'Baseline comparison stable: no material regressions or improvements detected.';
    return {
        reportVersion: 1,
        baselineAvailable: true,
        status,
        summary,
        baseline: {
            projectName: baseline.projectName,
            capturedAtUtc: baseline.capturedAtUtc,
            sourceSummaryGeneratedAtUtc: baseline.sourceSummaryGeneratedAtUtc,
            healthScore: baseline.healthScore,
            readinessScore: baseline.readinessScore,
        },
        current: {
            projectName: currentSummary.projectName,
            generatedAtUtc: currentSummary.generatedAtUtc,
            healthScore: currentSummary.healthScore,
            readinessScore: currentSummary.readinessScore,
        },
        deltas,
        newlyIntroducedFindings: comparison.newlyIntroducedFindings,
        resolvedFindings: comparison.resolvedFindings,
        unchangedFindings: comparison.unchangedFindings,
    };
}
function getBaselineComparisonReportPath(workspaceRoot) {
    return path.join(workspaceRoot, '.archpilot', 'reports', 'baseline-comparison.json');
}
async function writeBaselineComparisonReport(workspaceRoot, comparison) {
    const targetPath = getBaselineComparisonReportPath(workspaceRoot);
    await node_fs_1.promises.mkdir(path.dirname(targetPath), { recursive: true });
    await node_fs_1.promises.writeFile(targetPath, `${JSON.stringify(comparison, null, 2)}\n`, {
        encoding: 'utf8',
    });
    return targetPath;
}
//# sourceMappingURL=architectureGovernanceBaseline.js.map