"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeDeveloperVelocity = computeDeveloperVelocity;
exports.formatDeveloperVelocity = formatDeveloperVelocity;
const database_1 = require("../database/database");
function computeDeveloperVelocity(project, days = 30) {
    const db = (0, database_1.getDb)();
    const since = new Date(Date.now() - days * 86400000).toISOString();
    // All events
    const events = db.prepare(`
    SELECT type, summary, importance, topic, created_at, files_json FROM memory_events
    WHERE project = ? AND created_at >= ?
    ORDER BY created_at
  `).all(project, since);
    // Metrics
    const byType = {};
    const byDay = {};
    const byHour = {};
    const topicMap = new Map();
    for (const e of events) {
        byType[e.type] = (byType[e.type] || 0) + 1;
        const day = e.created_at.slice(0, 10);
        byDay[day] = (byDay[day] || 0) + 1;
        const hour = e.created_at.slice(11, 13);
        byHour[hour] = (byHour[hour] || 0) + 1;
        if (e.topic)
            topicMap.set(e.topic, (topicMap.get(e.topic) || 0) + 1);
    }
    const topTopics = [...topicMap.entries()]
        .sort((a, b) => b[1] - a[1])
        .slice(0, 10)
        .map(([topic, count]) => ({ topic, count }));
    const commitCount = byType.branch || 0;
    const editCount = byType.edit || 0;
    const decisionCount = byType.decision || 0;
    const fixCount = byType.fix || 0;
    const verificationCount = byType.verification || 0;
    const avgDailyCommits = Math.round(commitCount / days * 10) / 10;
    const avgDailyEdits = Math.round(editCount / days * 10) / 10;
    const peakDay = Object.entries(byDay).reduce((max, [d, c]) => c > max.c ? { d, c } : max, { d: 'none', c: 0 });
    // Decision frequency
    const decisionFreq = decisionCount > 0
        ? `1 decision per ${Math.round(days / decisionCount)} days`
        : 'no decisions';
    // Fix speed: time between error and fix
    const errors = events.filter(e => e.type === 'error');
    const fixes = events.filter(e => e.type === 'fix');
    let avgFixMs = 0;
    if (errors.length > 0 && fixes.length > 0) {
        const fixTimes = [];
        for (const fix of fixes) {
            const closestError = errors
                .filter(e => new Date(e.created_at) < new Date(fix.created_at))
                .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
            if (closestError) {
                fixTimes.push(new Date(fix.created_at).getTime() - new Date(closestError.created_at).getTime());
            }
        }
        avgFixMs = fixTimes.length > 0 ? fixTimes.reduce((s, t) => s + t, 0) / fixTimes.length : 0;
    }
    const avgFixSpeed = avgFixMs > 0
        ? avgFixMs < 3600000 ? `${Math.round(avgFixMs / 60000)}min`
            : avgFixMs < 86400000 ? `${Math.round(avgFixMs / 3600000)}h`
                : `${Math.round(avgFixMs / 86400000)}d`
        : 'N/A';
    const verificationRatio = editCount > 0 ? Math.round(verificationCount / editCount * 100) : 0;
    const metrics = {
        totalCommits: commitCount,
        avgDailyCommits,
        peakCommitDay: peakDay.d,
        peakCommitCount: peakDay.c,
        totalEdits: editCount,
        avgDailyEdits,
        totalDecisions: decisionCount,
        avgDecisionFrequency: decisionFreq,
        totalFixes: fixCount,
        avgFixSpeed,
        totalVerifications: verificationCount,
        verificationRatio,
    };
    // Daily trends
    const trends = [];
    const sortedDays = Object.keys(byDay).sort();
    let runningTotal = 0;
    for (const day of sortedDays) {
        runningTotal += byDay[day];
        trends.push({
            date: day,
            commits: events.filter(e => e.type === 'branch' && e.created_at.startsWith(day)).length,
            edits: events.filter(e => e.type === 'edit' && e.created_at.startsWith(day)).length,
            decisions: events.filter(e => e.type === 'decision' && e.created_at.startsWith(day)).length,
            fixes: events.filter(e => e.type === 'fix' && e.created_at.startsWith(day)).length,
            velocity: byDay[day],
        });
    }
    // Score
    const score = computeVelocityScore(metrics, days);
    // Chart
    const chart = renderVelocityChart(trends, metrics);
    return {
        project,
        period: `${days}d`,
        metrics,
        breakdown: { byType, byDay, byHour, topTopics },
        trends,
        score,
        chart,
    };
}
function computeVelocityScore(metrics, days) {
    // Productivity (0-100): commits + edits per day
    let productivity = 0;
    if (metrics.avgDailyCommits > 0)
        productivity += 30;
    if (metrics.avgDailyCommits > 2)
        productivity += 20;
    if (metrics.avgDailyCommits > 5)
        productivity += 10;
    if (metrics.avgDailyEdits > 0)
        productivity += 15;
    if (metrics.avgDailyEdits > 5)
        productivity += 15;
    if (metrics.avgDailyEdits > 10)
        productivity += 10;
    // Consistency (0-100): active days / total days
    const activeDays = Object.keys(metrics).length > 0 ? days : 0; // simplified
    let consistency = Math.min(100, activeDays * 3);
    // Quality (0-100): verification ratio + decisions
    let quality = 50;
    if (metrics.verificationRatio > 50)
        quality += 20;
    else if (metrics.verificationRatio > 20)
        quality += 10;
    if (metrics.totalDecisions > 3)
        quality += 15;
    if (metrics.totalDecisions > 10)
        quality += 15;
    // Learning (0-100): diverse event types
    const typeCount = Object.keys(metrics).length;
    let learning = Math.min(100, typeCount * 15);
    const overall = Math.round(productivity * 0.35 + consistency * 0.25 + quality * 0.25 + learning * 0.15);
    let grade = 'F';
    if (overall >= 90)
        grade = 'S';
    else if (overall >= 80)
        grade = 'A';
    else if (overall >= 70)
        grade = 'B';
    else if (overall >= 55)
        grade = 'C';
    else if (overall >= 40)
        grade = 'D';
    return {
        overall,
        grade,
        dimensions: { productivity, consistency, quality, learning },
    };
}
function renderVelocityChart(trends, metrics) {
    if (trends.length === 0)
        return '  No data available.';
    const maxVelocity = Math.max(...trends.map(t => t.velocity), 1);
    const chartHeight = 8;
    const lines = [];
    lines.push(`  Developer Velocity (${trends.length} days)`);
    lines.push('');
    for (let row = chartHeight; row >= 1; row--) {
        const threshold = (row / chartHeight) * maxVelocity;
        const label = row === chartHeight ? String(maxVelocity).padStart(4) : row === 1 ? '   1' : '    ';
        let line = `  ${label} │`;
        for (const t of trends) {
            if (t.velocity >= threshold) {
                line += ' ▓';
            }
            else {
                line += '  ';
            }
        }
        lines.push(line);
    }
    lines.push(`      └${'─'.repeat(trends.length * 2)}`);
    if (trends.length > 0) {
        const first = trends[0].date.slice(5);
        const last = trends[trends.length - 1].date.slice(5);
        lines.push(`       ${first}${' '.repeat(Math.max(0, trends.length * 2 - first.length - last.length))}${last}`);
    }
    lines.push('');
    lines.push(`  Commits: ${metrics.totalCommits} | Edits: ${metrics.totalEdits} | Decisions: ${metrics.totalDecisions} | Fixes: ${metrics.totalFixes}`);
    return lines.join('\n');
}
function formatDeveloperVelocity(vel) {
    const lines = [];
    lines.push(`## Developer Velocity — ${vel.project} (${vel.period})\n`);
    lines.push(vel.chart);
    lines.push('');
    lines.push(`### Score: ${vel.score.overall}/100 (${vel.score.grade})`);
    lines.push(`| Dimension | Score |`);
    lines.push(`|-----------|-------|`);
    lines.push(`| Productivity | ${vel.score.dimensions.productivity} |`);
    lines.push(`| Consistency | ${vel.score.dimensions.consistency} |`);
    lines.push(`| Quality | ${vel.score.dimensions.quality} |`);
    lines.push(`| Learning | ${vel.score.dimensions.learning} |`);
    lines.push('');
    lines.push(`### Metrics`);
    lines.push(`| Metric | Value |`);
    lines.push(`|--------|-------|`);
    lines.push(`| Total commits | ${vel.metrics.totalCommits} |`);
    lines.push(`| Avg daily commits | ${vel.metrics.avgDailyCommits} |`);
    lines.push(`| Total edits | ${vel.metrics.totalEdits} |`);
    lines.push(`| Avg daily edits | ${vel.metrics.avgDailyEdits} |`);
    lines.push(`| Decisions | ${vel.metrics.totalDecisions} |`);
    lines.push(`| Decision frequency | ${vel.metrics.avgDecisionFrequency} |`);
    lines.push(`| Fixes | ${vel.metrics.totalFixes} |`);
    lines.push(`| Avg fix speed | ${vel.metrics.avgFixSpeed} |`);
    lines.push(`| Verification ratio | ${vel.metrics.verificationRatio}% |`);
    if (vel.breakdown.topTopics.length > 0) {
        lines.push('');
        lines.push(`### Top Topics`);
        for (const t of vel.breakdown.topTopics.slice(0, 5)) {
            lines.push(`- ${t.topic}: ${t.count}`);
        }
    }
    return lines.join('\n');
}
//# sourceMappingURL=developer-velocity.js.map