"""Benchmarking for GreyMatter.

Tracks build runs, quality scores, and review issues to measure
the quality delta between different development approaches
(GreyMatter-orchestrated, subagent, raw Claude, plugins).
"""
from typing import Any

from .db import Database
from .ids import generate_build_run_id

VALID_APPROACHES = {"greymatter", "subagent", "raw_claude", "plugin"}
VALID_SEVERITIES = {"critical", "important", "minor"}


class BenchmarkManager:
    """Tracks build quality across development approaches."""

    def __init__(self, db: Database) -> None:
        self.db = db

    def start_run(
        self, approach: str, task_name: str, session_id: str | None = None
    ) -> dict[str, Any]:
        """Start a new build run and return its record."""
        if approach not in VALID_APPROACHES:
            raise ValueError(f"Invalid approach {approach!r}. Must be one of: {VALID_APPROACHES}")
        run_id = generate_build_run_id()
        self.db.execute(
            """INSERT INTO build_runs (id, session_id, approach, task_name)
               VALUES (?, ?, ?, ?)""",
            (run_id, session_id, approach, task_name),
        )
        return self.get_run(run_id)

    def get_run(self, run_id: str) -> dict[str, Any] | None:
        """Fetch a single build run by ID."""
        return self.db.execute_one("SELECT * FROM build_runs WHERE id = ?", (run_id,))

    def complete_run(
        self, run_id: str, lines: int, tests: int, passing: int, first_pass: bool
    ) -> dict[str, Any]:
        """Mark a build run as completed with metrics."""
        self.db.execute(
            """UPDATE build_runs SET completed_at = datetime('now'),
               lines_written = ?, test_count = ?, tests_passing = ?,
               first_pass_success = ?
               WHERE id = ?""",
            (lines, tests, passing, 1 if first_pass else 0, run_id),
        )
        return self.get_run(run_id)

    def score_run(
        self,
        run_id: str,
        standard_id: str,
        passed: bool,
        found_by: str,
        detail: str | None = None,
    ) -> None:
        """Record a quality score for a build run against a standard."""
        self.db.execute(
            """INSERT INTO quality_scores
               (build_run_id, standard_id, passed, detail, found_by)
               VALUES (?, ?, ?, ?, ?)""",
            (run_id, standard_id, 1 if passed else 0, detail, found_by),
        )

    def get_scores(self, run_id: str) -> list[dict[str, Any]]:
        """Get all quality scores for a build run."""
        return self.db.execute(
            "SELECT * FROM quality_scores WHERE build_run_id = ? ORDER BY found_at",
            (run_id,),
        )

    def record_issue(
        self,
        run_id: str,
        severity: str,
        category: str,
        description: str,
        found_by: str,
    ) -> int:
        """Record a review issue against a build run. Returns the issue ID."""
        if severity not in VALID_SEVERITIES:
            raise ValueError(f"Invalid severity {severity!r}. Must be one of: {VALID_SEVERITIES}")
        self.db.execute(
            """INSERT INTO review_issues
               (build_run_id, severity, category, description, found_by)
               VALUES (?, ?, ?, ?, ?)""",
            (run_id, severity, category, description, found_by),
        )
        row = self.db.execute_one("SELECT last_insert_rowid() as id")
        if row is None:
            raise RuntimeError("Failed to retrieve inserted review_issues row ID")
        return row["id"]

    def get_issues(self, run_id: str) -> list[dict[str, Any]]:
        """Get all review issues for a build run."""
        return self.db.execute(
            "SELECT * FROM review_issues WHERE build_run_id = ? ORDER BY id",
            (run_id,),
        )

    def resolve_issue(self, issue_id: int, fix_minutes: int) -> None:
        """Mark an issue as resolved with time-to-fix."""
        self.db.execute(
            """UPDATE review_issues SET fixed_at = datetime('now'),
               time_to_fix_minutes = ?
               WHERE id = ?""",
            (fix_minutes, issue_id),
        )

    def defect_density(self, approach: str | None = None) -> list[dict[str, Any]]:
        """Calculate defects per KLOC, optionally filtered by approach."""
        query = """SELECT approach,
                          SUM(issue_count) * 1000.0 / NULLIF(SUM(lines_written), 0) AS defects_per_kloc
                   FROM (
                       SELECT br.approach, br.lines_written,
                              (SELECT COUNT(*) FROM review_issues ri WHERE ri.build_run_id = br.id) AS issue_count
                       FROM build_runs br
                       WHERE br.completed_at IS NOT NULL"""
        params: list = []
        if approach:
            query += " AND br.approach = ?"
            params.append(approach)
        query += ") sub GROUP BY approach"
        return self.db.execute(query, tuple(params))

    def first_pass_quality(self, approach: str | None = None) -> list[dict[str, Any]]:
        """Calculate first-pass quality percentage by approach."""
        query = """SELECT br.approach,
                          AVG(qs.passed) * 100 AS first_pass_pct
                   FROM quality_scores qs
                   JOIN build_runs br ON qs.build_run_id = br.id"""
        params: list = []
        if approach:
            query += " WHERE br.approach = ?"
            params.append(approach)
        query += " GROUP BY br.approach"
        return self.db.execute(query, tuple(params))

    def time_to_correct(self, approach: str | None = None) -> list[dict[str, Any]]:
        """Calculate average time-to-fix in minutes by approach."""
        query = """SELECT br.approach,
                          AVG(ri.time_to_fix_minutes) AS avg_fix_minutes
                   FROM review_issues ri
                   JOIN build_runs br ON ri.build_run_id = br.id
                   WHERE ri.fixed_at IS NOT NULL"""
        params: list = []
        if approach:
            query += " AND br.approach = ?"
            params.append(approach)
        query += " GROUP BY br.approach"
        return self.db.execute(query, tuple(params))

    def summary(self) -> list[dict[str, Any]]:
        """Get a high-level summary of all completed runs by approach."""
        return self.db.execute(
            """SELECT approach,
                      COUNT(*) AS total_runs,
                      SUM(lines_written) AS total_lines,
                      SUM(test_count) AS total_tests,
                      SUM(issue_count) AS total_issues,
                      SUM(issue_count) * 1000.0 / NULLIF(SUM(lines_written), 0) AS defects_per_kloc
               FROM (
                   SELECT br.approach, br.lines_written, br.test_count,
                          (SELECT COUNT(*) FROM review_issues ri WHERE ri.build_run_id = br.id) AS issue_count
                   FROM build_runs br
                   WHERE br.completed_at IS NOT NULL
               ) sub
               GROUP BY approach"""
        )
