// engine/convention-sync.ts — Convention sync health calculator.
// Combines rules, skills, hooks and convention scanner scores into a single
// weighted percentage showing how well the project enforces its own conventions.
import { reconcileRules } from './rules-reconciler.js';
import { reconcileSkills } from './skills-reconciler.js';
import { reconcileHooks } from './hooks-reconciler.js';
import { parseConventions, scanConventions } from './convention-scanner/index.js';
// ---------------------------------------------------------------------------
// Weights (must sum to 1.0)
// ---------------------------------------------------------------------------
const WEIGHT_RULES = 0.25;
const WEIGHT_SKILLS = 0.25;
const WEIGHT_HOOKS = 0.25;
const WEIGHT_CONVENTIONS = 0.25;
// Violation count that maps to 0 conventionHealth (linear scale).
const MAX_VIOLATIONS_FOR_ZERO = 40;
// ---------------------------------------------------------------------------
// Convention health score
// ---------------------------------------------------------------------------
/**
 * Derive a 0–100 score from raw violation count.
 * 0 violations → 100; MAX_VIOLATIONS_FOR_ZERO+ violations → 0.
 */
function conventionScoreFromViolations(violationCount) {
    if (violationCount <= 0) {
        return 100;
    }
    const ratio = Math.min(violationCount / MAX_VIOLATIONS_FOR_ZERO, 1);
    return Math.max(0, Math.round((1 - ratio) * 100));
}
// ---------------------------------------------------------------------------
// Recommendations
// ---------------------------------------------------------------------------
function buildAreaSuggestions(rulesHealth, skillsHealth, hooksHealth, conventionHealth) {
    const areas = [
        {
            label: 'rules',
            score: rulesHealth,
            suggestions: [
                'Run reconcile_rules to auto-generate missing .claude/rules/ files.',
                'Review stale rules files and remove or update them.',
            ],
        },
        {
            label: 'skills',
            score: skillsHealth,
            suggestions: [
                'Run reconcile_skills to identify skills your stack recommends.',
                'Install missing skills with skill_install or remove stale ones.',
            ],
        },
        {
            label: 'hooks',
            score: hooksHealth,
            suggestions: [
                'Run reconcile_hooks to find missing git hook steps.',
                'Run configure_hooks to add typecheck, lint, or test steps to hooks.',
            ],
        },
        {
            label: 'conventions',
            score: conventionHealth,
            suggestions: [
                'Run scan_project to get a detailed list of convention violations.',
                'Fix critical violations first (architecture imports, naming rules).',
            ],
        },
    ];
    // Sort by ascending score so lowest-scoring areas come first.
    return areas.sort((a, b) => a.score - b.score);
}
function pickTopRecommendations(areas, maxItems) {
    const recs = [];
    for (const area of areas) {
        if (area.score < 100) {
            for (const s of area.suggestions) {
                if (recs.length < maxItems) {
                    recs.push(s);
                }
            }
        }
        if (recs.length >= maxItems) {
            break;
        }
    }
    return recs;
}
// ---------------------------------------------------------------------------
// Summary string
// ---------------------------------------------------------------------------
function buildSummary(overallScore, worstArea) {
    const grade = overallScore >= 90
        ? 'Excellent'
        : overallScore >= 75
            ? 'Good'
            : overallScore >= 50
                ? 'Fair'
                : 'Poor';
    if (!worstArea || overallScore >= 90) {
        return `${grade} (${overallScore}/100) — conventions and enforcement mechanisms are in sync.`;
    }
    return `${grade} (${overallScore}/100) — worst area: ${worstArea.label} (${worstArea.score}/100). Focus here first.`;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Calculate overall convention sync health by running all four reconcilers
 * in parallel and combining their scores with equal 25% weights.
 *
 * Never throws — returns zero scores on unexpected errors.
 */
export async function calculateConventionSync(projectPath, knowledge) {
    try {
        const [rulesResult, skillsResult, hooksResult] = await Promise.all([
            Promise.resolve(reconcileRules(projectPath)),
            reconcileSkills(projectPath, knowledge),
            Promise.resolve(reconcileHooks(projectPath)),
        ]);
        const rules = parseConventions(projectPath);
        const violations = scanConventions(projectPath, rules);
        const rulesHealth = rulesResult.healthScore;
        const skillsHealth = skillsResult.healthScore;
        const hooksHealth = hooksResult.healthScore;
        const conventionHealth = conventionScoreFromViolations(violations.length);
        const overallScore = Math.round(rulesHealth * WEIGHT_RULES +
            skillsHealth * WEIGHT_SKILLS +
            hooksHealth * WEIGHT_HOOKS +
            conventionHealth * WEIGHT_CONVENTIONS);
        const areas = buildAreaSuggestions(rulesHealth, skillsHealth, hooksHealth, conventionHealth);
        const worstArea = areas[0];
        const summary = buildSummary(overallScore, worstArea);
        const recommendations = pickTopRecommendations(areas, 4);
        return {
            overallScore,
            rulesHealth,
            skillsHealth,
            hooksHealth,
            conventionHealth,
            summary,
            recommendations,
        };
    }
    catch {
        return {
            overallScore: 0,
            rulesHealth: 0,
            skillsHealth: 0,
            hooksHealth: 0,
            conventionHealth: 0,
            summary: 'Error: could not calculate convention sync health.',
            recommendations: ['Ensure the project has been initialised with init_project.'],
        };
    }
}
//# sourceMappingURL=convention-sync.js.map