// engine/living-spec/dashboard-collector.ts — AC-7: Dashboard data collection
// Collects spec entries, summaries, trends, and diff rows for living dashboards.
const MAX_TREND_POINTS = 30;
/**
 * Collect dashboard entries from specs and their hash snapshots.
 */
export function collectSpecEntries(specs, hashSnapshots) {
    const now = new Date().toISOString();
    return specs.map((spec) => {
        const snapshot = hashSnapshots.get(spec.id);
        const hasChanges = snapshot !== null && snapshot !== undefined;
        return {
            specId: spec.id,
            status: spec.status,
            completion: spec.completion,
            driftDetected: hasChanges && snapshot.files.length > 0,
            changedFileCount: hasChanges ? snapshot.files.length : 0,
            signatureChangeCount: hasChanges ? snapshot.signatures.length : 0,
            lastCheckedAt: hasChanges ? snapshot.createdAt : now,
        };
    });
}
/**
 * Compute summary statistics from dashboard entries.
 */
export function collectSummary(entries) {
    const totalSpecs = entries.length;
    const specsWithDrift = entries.filter((e) => e.driftDetected).length;
    const averageCompletion = totalSpecs > 0 ? Math.round(entries.reduce((sum, e) => sum + e.completion, 0) / totalSpecs) : 0;
    const driftPenalty = totalSpecs > 0 ? (specsWithDrift / totalSpecs) * 50 : 0;
    const completionPenalty = (100 - averageCompletion) * 0.5;
    const healthScore = Math.max(0, Math.round(100 - driftPenalty - completionPenalty));
    return {
        totalSpecs,
        specsWithDrift,
        averageCompletion,
        healthScore,
        generatedAt: new Date().toISOString(),
    };
}
/**
 * Collect trend data points, capping at MAX_TREND_POINTS.
 */
export function collectTrends(entries, history) {
    const summary = collectSummary(entries);
    const newPoint = {
        timestamp: new Date().toISOString(),
        specsWithDrift: summary.specsWithDrift,
        averageCompletion: summary.averageCompletion,
        healthScore: summary.healthScore,
    };
    const updated = [...history, newPoint];
    if (updated.length > MAX_TREND_POINTS) {
        return updated.slice(updated.length - MAX_TREND_POINTS);
    }
    return updated;
}
/**
 * Build diff rows comparing old and new hash snapshots.
 */
export function buildSpecDiffRows(oldHashes, newHashes, specId) {
    const rows = [];
    for (const [file, oldHash] of oldHashes) {
        const newHash = newHashes.get(file);
        if (newHash === undefined) {
            rows.push({ specId, file, previousHash: oldHash, currentHash: '', status: 'removed' });
        }
        else if (newHash !== oldHash) {
            rows.push({ specId, file, previousHash: oldHash, currentHash: newHash, status: 'modified' });
        }
    }
    for (const [file, newHash] of newHashes) {
        if (!oldHashes.has(file)) {
            rows.push({ specId, file, previousHash: '', currentHash: newHash, status: 'added' });
        }
    }
    return rows;
}
/**
 * Format diff rows as a Markdown table.
 */
export function formatMarkdownDiff(rows) {
    if (rows.length === 0) {
        return 'No changes detected.';
    }
    const lines = [
        '| Spec | File | Status | Previous Hash | Current Hash |',
        '|------|------|--------|---------------|--------------|',
    ];
    for (const row of rows) {
        const prev = row.previousHash ? row.previousHash.slice(0, 8) : '-';
        const curr = row.currentHash ? row.currentHash.slice(0, 8) : '-';
        lines.push(`| ${row.specId} | ${row.file} | ${row.status} | ${prev} | ${curr} |`);
    }
    return lines.join('\n');
}
//# sourceMappingURL=dashboard-collector.js.map