/**
 * Trends Repository
 *
 * Historical trend calculations and aggregations.
 *
 * @module persistence/repositories/trends
 */
export class TrendsRepository {
    db;
    constructor(db) {
        this.db = db;
    }
    calculateTrends(projectId, period, lookbackPeriods = 30) {
        const periodFormat = this.getPeriodFormat(period);
        const periodInterval = this.getPeriodInterval(period);
        const sql = `
      WITH RECURSIVE dates(period_start) AS (
        SELECT date('now', '-${lookbackPeriods * periodInterval} days')
        UNION ALL
        SELECT date(period_start, '+${periodInterval} days')
        FROM dates
        WHERE period_start < date('now')
      ),
      period_data AS (
        SELECT
          strftime('${periodFormat}', d.period_start) as period,
          d.period_start,
          COALESCE(SUM(CASE WHEN f.first_seen_at >= d.period_start
            AND f.first_seen_at < date(d.period_start, '+${periodInterval} days') THEN 1 ELSE 0 END), 0) as new_findings,
          COALESCE(SUM(CASE WHEN f.fixed_at >= d.period_start
            AND f.fixed_at < date(d.period_start, '+${periodInterval} days') THEN 1 ELSE 0 END), 0) as fixed_findings,
          COALESCE(SUM(CASE WHEN f.status = 'open'
            AND f.first_seen_at <= date(d.period_start, '+${periodInterval} days') THEN 1 ELSE 0 END), 0) as open_findings
        FROM dates d
        LEFT JOIN findings f ON f.project_id = ?
        GROUP BY d.period_start
        ORDER BY d.period_start
      )
      SELECT * FROM period_data WHERE period IS NOT NULL
    `;
        const rows = this.db.prepare(sql).all(projectId);
        return rows.map((r) => ({
            period: r.period,
            periodStart: r.period_start,
            newFindings: r.new_findings,
            fixedFindings: r.fixed_findings,
            openFindings: r.open_findings,
        }));
    }
    getMTTR(projectId, period, lookbackPeriods = 12) {
        const periodFormat = this.getPeriodFormat(period);
        const periodInterval = this.getPeriodInterval(period);
        const sql = `
      SELECT
        strftime('${periodFormat}', fixed_at) as period,
        AVG((julianday(fixed_at) - julianday(first_seen_at)) * 24) as mttr_hours
      FROM findings
      WHERE project_id = ?
        AND status = 'fixed'
        AND fixed_at IS NOT NULL
        AND fixed_at >= date('now', '-${lookbackPeriods * periodInterval} days')
      GROUP BY strftime('${periodFormat}', fixed_at)
      ORDER BY period
    `;
        const rows = this.db.prepare(sql).all(projectId);
        return rows.map((r) => ({
            period: r.period,
            mttrHours: r.mttr_hours || 0,
        }));
    }
    getFixVelocity(projectId, period, lookbackPeriods = 12) {
        const periodFormat = this.getPeriodFormat(period);
        const periodInterval = this.getPeriodInterval(period);
        const sql = `
      SELECT
        strftime('${periodFormat}', fixed_at) as period,
        COUNT(*) as fixes_count
      FROM findings
      WHERE project_id = ?
        AND status = 'fixed'
        AND fixed_at IS NOT NULL
        AND fixed_at >= date('now', '-${lookbackPeriods * periodInterval} days')
      GROUP BY strftime('${periodFormat}', fixed_at)
      ORDER BY period
    `;
        const rows = this.db.prepare(sql).all(projectId);
        return rows.map((r) => ({
            period: r.period,
            fixesCount: r.fixes_count,
        }));
    }
    getSeverityTrends(projectId, period, lookbackPeriods = 12) {
        const periodFormat = this.getPeriodFormat(period);
        const periodInterval = this.getPeriodInterval(period);
        const sql = `
      SELECT
        strftime('${periodFormat}', first_seen_at) as period,
        severity,
        COUNT(*) as count
      FROM findings
      WHERE project_id = ?
        AND first_seen_at >= date('now', '-${lookbackPeriods * periodInterval} days')
      GROUP BY strftime('${periodFormat}', first_seen_at), severity
      ORDER BY period
    `;
        const rows = this.db.prepare(sql).all(projectId);
        const grouped = new Map();
        for (const row of rows) {
            if (!grouped.has(row.period)) {
                grouped.set(row.period, { critical: 0, high: 0, medium: 0, low: 0, info: 0 });
            }
            grouped.get(row.period)[row.severity] = row.count;
        }
        return Array.from(grouped.entries()).map(([period, bySeverity]) => ({
            period,
            bySeverity,
        }));
    }
    getCategoryBreakdown(projectId) {
        const total = this.db
            .prepare("SELECT COUNT(*) as count FROM findings WHERE project_id = ? AND status = 'open'")
            .get(projectId);
        const totalCount = total?.count || 0;
        if (totalCount === 0)
            return [];
        const rows = this.db
            .prepare(`SELECT category, COUNT(*) as count
         FROM findings
         WHERE project_id = ? AND status = 'open'
         GROUP BY category
         ORDER BY count DESC`)
            .all(projectId);
        return rows.map((r) => ({
            category: r.category,
            count: r.count,
            percentage: Math.round((r.count / totalCount) * 100),
        }));
    }
    getScannerEffectiveness(projectId) {
        const rows = this.db
            .prepare(`SELECT
          scanner_source,
          COUNT(*) as found,
          SUM(CASE WHEN status = 'false_positive' THEN 1 ELSE 0 END) as false_positives
         FROM findings
         WHERE project_id = ?
         GROUP BY scanner_source
         ORDER BY found DESC`)
            .all(projectId);
        return rows.map((r) => ({
            scanner: r.scanner_source,
            found: r.found,
            falsePositives: r.false_positives,
            accuracy: r.found > 0 ? Math.round(((r.found - r.false_positives) / r.found) * 100) : 100,
        }));
    }
    getPeriodFormat(period) {
        switch (period) {
            case "day":
                return "%Y-%m-%d";
            case "week":
                return "%Y-W%W";
            case "month":
                return "%Y-%m";
        }
    }
    getPeriodInterval(period) {
        switch (period) {
            case "day":
                return 1;
            case "week":
                return 7;
            case "month":
                return 30;
        }
    }
}
//# sourceMappingURL=trends.js.map