"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeErrorTrends = computeErrorTrends;
exports.formatErrorTrend = formatErrorTrend;
const database_1 = require("../database/database");
function computeErrorTrends(project, days = 30) {
    const db = (0, database_1.getDb)();
    const since = new Date(Date.now() - days * 86400000).toISOString();
    // Total errors and fixes
    const errorCount = db.prepare("SELECT COUNT(*) as c FROM memory_events WHERE project = ? AND type = 'error' AND created_at >= ?").get(project, since);
    const fixCount = db.prepare("SELECT COUNT(*) as c FROM memory_events WHERE project = ? AND type = 'fix' AND created_at >= ?").get(project, since);
    // Daily trend
    const dailyErrors = db.prepare(`
    SELECT date(created_at) as date, COUNT(*) as count FROM memory_events
    WHERE project = ? AND type = 'error' AND created_at >= ?
    GROUP BY date(created_at) ORDER BY date
  `).all(project, since);
    const dailyFixes = db.prepare(`
    SELECT date(created_at) as date, COUNT(*) as count FROM memory_events
    WHERE project = ? AND type = 'fix' AND created_at >= ?
    GROUP BY date(created_at) ORDER BY date
  `).all(project, since);
    const dailyTotal = db.prepare(`
    SELECT date(created_at) as date, COUNT(*) as count FROM memory_events
    WHERE project = ? AND created_at >= ?
    GROUP BY date(created_at) ORDER BY date
  `).all(project, since);
    const errorMap = new Map(dailyErrors.map(r => [r.date, r.count]));
    const fixMap = new Map(dailyFixes.map(r => [r.date, r.count]));
    const totalMap = new Map(dailyTotal.map(r => [r.date, r.count]));
    const allDates = [...new Set([...errorMap.keys(), ...fixMap.keys(), ...totalMap.keys()])].sort();
    const dailyTrend = allDates.map(date => {
        const errors = errorMap.get(date) || 0;
        const fixes = fixMap.get(date) || 0;
        const total = totalMap.get(date) || 1;
        return { date, errors, fixes, errorRate: Math.round(errors / total * 100) };
    });
    // Peak error day
    const peakDay = dailyErrors.reduce((max, r) => r.count > max.count ? r : max, { date: 'none', count: 0 });
    // Trend detection (compare first half vs second half)
    const half = Math.floor(dailyTrend.length / 2);
    const firstHalfRate = dailyTrend.slice(0, half);
    const secondHalfRate = dailyTrend.slice(half);
    const firstAvg = firstHalfRate.length > 0 ? firstHalfRate.reduce((s, d) => s + d.errorRate, 0) / firstHalfRate.length : 0;
    const secondAvg = secondHalfRate.length > 0 ? secondHalfRate.reduce((s, d) => s + d.errorRate, 0) / secondHalfRate.length : 0;
    let trend = 'stable';
    if (secondAvg < firstAvg * 0.8)
        trend = 'improving';
    else if (secondAvg > firstAvg * 1.2)
        trend = 'worsening';
    const avgErrorsPerDay = dailyTrend.length > 0
        ? Math.round(dailyTrend.reduce((s, d) => s + d.errors, 0) / dailyTrend.length * 10) / 10
        : 0;
    const totalEvents = db.prepare('SELECT COUNT(*) as c FROM memory_events WHERE project = ? AND created_at >= ?').get(project, since);
    const summary = {
        totalErrors: errorCount.c,
        totalFixes: fixCount.c,
        unfixedErrors: errorCount.c - fixCount.c,
        errorRate: totalEvents.c > 0 ? Math.round(errorCount.c / totalEvents.c * 100) : 0,
        avgErrorsPerDay,
        peakErrorDay: peakDay.date,
        peakErrorCount: peakDay.count,
        trend,
    };
    // Regressions: errors that appear in second half but not first
    const firstHalfErrors = new Set(db.prepare(`
      SELECT DISTINCT summary FROM memory_events
      WHERE project = ? AND type = 'error' AND created_at >= ? AND created_at < ?
    `).all(project, since, new Date(Date.now() - days / 2 * 86400000).toISOString()).map((r) => r.summary));
    const secondHalfErrors = db.prepare(`
    SELECT summary, COUNT(*) as c FROM memory_events
    WHERE project = ? AND type = 'error' AND created_at >= ?
    GROUP BY summary HAVING c >= 2
  `).all(project, new Date(Date.now() - days / 2 * 86400000).toISOString());
    const regressions = secondHalfErrors
        .filter(e => !firstHalfErrors.has(e.summary))
        .map(e => ({
        pattern: e.summary.slice(0, 100),
        count: e.c,
        firstSeen: since,
        lastSeen: new Date().toISOString(),
        severity: e.c > 5 ? 'high' : e.c > 2 ? 'medium' : 'low',
        suggestion: e.c > 3 ? 'Systematic fix needed' : 'Monitor for recurrence',
    }));
    // Top errors
    const topErrorRows = db.prepare(`
    SELECT summary, COUNT(*) as c, topic, importance, MAX(created_at) as lastSeen
    FROM memory_events WHERE project = ? AND type = 'error' AND created_at >= ?
    GROUP BY summary ORDER BY c DESC LIMIT 10
  `).all(project, since);
    const fixedSummaries = new Set(db.prepare(`
      SELECT DISTINCT summary FROM memory_events WHERE project = ? AND type = 'fix' AND created_at >= ?
    `).all(project, since).map((r) => r.summary));
    const topErrors = topErrorRows.map(r => ({
        summary: r.summary.slice(0, 120),
        count: r.c,
        topic: r.topic,
        importance: r.importance,
        lastSeen: r.lastSeen,
        fixed: fixedSummaries.has(r.summary),
    }));
    // Fix rate
    const fixRateRows = db.prepare(`
    SELECT e.summary as errorSummary, e.created_at as errorTime, f.created_at as fixTime
    FROM memory_events e
    JOIN memory_events f ON f.project = e.project AND f.type = 'fix'
    WHERE e.project = ? AND e.type = 'error' AND e.created_at >= ?
    AND f.created_at > e.created_at
    ORDER BY e.created_at, f.created_at
  `).all(project, since);
    // Deduplicate: pair each error with its closest fix
    const fixTimes = [];
    const errorTimes = db.prepare(`
    SELECT created_at FROM memory_events WHERE project = ? AND type = 'error' AND created_at >= ? ORDER BY created_at
  `).all(project, since);
    const fixTimesAll = db.prepare(`
    SELECT created_at FROM memory_events WHERE project = ? AND type = 'fix' AND created_at >= ? ORDER BY created_at
  `).all(project, since);
    for (const err of errorTimes) {
        const closestFix = fixTimesAll.find(f => new Date(f.created_at) > new Date(err.created_at));
        if (closestFix) {
            fixTimes.push(new Date(closestFix.created_at).getTime() - new Date(err.created_at).getTime());
        }
    }
    const avgFixMs = fixTimes.length > 0 ? fixTimes.reduce((s, t) => s + t, 0) / fixTimes.length : 0;
    const minFix = fixTimes.length > 0 ? Math.min(...fixTimes) : 0;
    const maxFix = fixTimes.length > 0 ? Math.max(...fixTimes) : 0;
    const fixRate = {
        total: errorCount.c,
        fixed: fixCount.c,
        rate: errorCount.c > 0 ? Math.round(fixCount.c / errorCount.c * 100) : 0,
        avgTimeToFix: formatDuration(avgFixMs),
        fastestFix: formatDuration(minFix),
        slowestFix: formatDuration(maxFix),
    };
    // Chart
    const chart = renderErrorChart(dailyTrend, summary);
    return {
        project,
        period: `${days}d`,
        summary,
        dailyTrend,
        regressions,
        topErrors,
        fixRate,
        chart,
    };
}
function renderErrorChart(trend, summary) {
    if (trend.length === 0)
        return '  No error data.';
    const maxErrors = Math.max(...trend.map(t => t.errors), 1);
    const chartHeight = 8;
    const lines = [];
    lines.push(`  Error Trend — ${summary.trend.toUpperCase()} (rate: ${summary.errorRate}%)`);
    lines.push('');
    for (let row = chartHeight; row >= 1; row--) {
        const threshold = (row / chartHeight) * maxErrors;
        const label = row === chartHeight ? String(maxErrors).padStart(4) : row === 1 ? '   1' : '    ';
        let line = `  ${label} │`;
        for (const t of trend) {
            if (t.errors >= threshold) {
                line += ' ▓';
            }
            else if (t.fixes >= threshold) {
                line += ' ░';
            }
            else {
                line += '  ';
            }
        }
        lines.push(line);
    }
    lines.push(`      └${'─'.repeat(trend.length * 2)}`);
    if (trend.length > 0) {
        const first = trend[0].date.slice(5);
        const last = trend[trend.length - 1].date.slice(5);
        lines.push(`       ${first}${' '.repeat(Math.max(0, trend.length * 2 - first.length - last.length))}${last}`);
    }
    lines.push('');
    lines.push(`  ▓ errors  ░ fixes`);
    lines.push(`  Errors: ${summary.totalErrors} | Fixes: ${summary.totalFixes} | Unfixed: ${summary.unfixedErrors}`);
    return lines.join('\n');
}
function formatDuration(ms) {
    if (ms === 0)
        return 'N/A';
    if (ms < 60000)
        return `${Math.round(ms / 1000)}s`;
    if (ms < 3600000)
        return `${Math.round(ms / 60000)}min`;
    if (ms < 86400000)
        return `${Math.round(ms / 3600000)}h`;
    return `${Math.round(ms / 86400000)}d`;
}
function formatErrorTrend(trend) {
    const lines = [];
    lines.push(`## Error Trend — ${trend.project} (${trend.period})\n`);
    lines.push(trend.chart);
    lines.push('');
    lines.push(`### Summary`);
    lines.push(`| Metric | Value |`);
    lines.push(`|--------|-------|`);
    lines.push(`| Total errors | ${trend.summary.totalErrors} |`);
    lines.push(`| Total fixes | ${trend.summary.totalFixes} |`);
    lines.push(`| Unfixed | ${trend.summary.unfixedErrors} |`);
    lines.push(`| Error rate | ${trend.summary.errorRate}% |`);
    lines.push(`| Avg/day | ${trend.summary.avgErrorsPerDay} |`);
    lines.push(`| Peak day | ${trend.summary.peakErrorDay} (${trend.summary.peakErrorCount}) |`);
    lines.push(`| Trend | ${trend.summary.trend} |`);
    lines.push('');
    lines.push(`### Fix Rate`);
    lines.push(`- Fixed: ${trend.fixRate.rate}%`);
    lines.push(`- Avg time to fix: ${trend.fixRate.avgTimeToFix}`);
    lines.push(`- Fastest: ${trend.fixRate.fastestFix} | Slowest: ${trend.fixRate.slowestFix}`);
    if (trend.regressions.length > 0) {
        lines.push('');
        lines.push(`### Regressions`);
        for (const r of trend.regressions) {
            lines.push(`- [${r.severity}] ${r.pattern} (×${r.count}) — ${r.suggestion}`);
        }
    }
    if (trend.topErrors.length > 0) {
        lines.push('');
        lines.push(`### Top Errors`);
        for (const e of trend.topErrors.slice(0, 5)) {
            lines.push(`- ${e.fixed ? '✓' : '✗'} [×${e.count}] ${e.summary}`);
        }
    }
    return lines.join('\n');
}
//# sourceMappingURL=error-trends.js.map