"""Scoring engine — converts raw results into a graded report with severity aggregation."""

from __future__ import annotations

import datetime
from typing import Any

from .runner import SuiteOutput, TestResult

ENGINE_VERSION = "3.0.0"

# Deduction weights per status × severity
_DEDUCTIONS: dict[tuple[str, str], float] = {
    ("CRASH",  "CRITICAL"): 12,
    ("CRASH",  "HIGH"):     8,
    ("CRASH",  "MEDIUM"):   5,
    ("CRASH",  "LOW"):      3,
    ("CRASH",  "INFO"):     1,
    ("WARN",   "CRITICAL"): 6,
    ("WARN",   "HIGH"):     4,
    ("WARN",   "MEDIUM"):   2,
    ("WARN",   "LOW"):      1,
    ("WARN",   "INFO"):     0,
    ("FAIL",   "CRITICAL"): 10,
    ("FAIL",   "HIGH"):     6,
    ("FAIL",   "MEDIUM"):   4,
    ("FAIL",   "LOW"):      2,
    ("FAIL",   "INFO"):     0,
}


def grade(score: int) -> str:
    if score >= 90:
        return "A"
    if score >= 75:
        return "B"
    if score >= 60:
        return "C"
    if score >= 40:
        return "D"
    return "F"


def compute_report(
    suite_output: SuiteOutput,
    target: str,
    method: str,
    mode: str,
) -> dict[str, Any]:
    """Build a full structured report from suite results."""
    results = suite_output.results

    # ── Aggregate counts ──
    total = len(results)
    crashes = sum(1 for r in results if r.status == "CRASH")
    warnings = sum(1 for r in results if r.status == "WARN")
    passes = sum(1 for r in results if r.status == "PASS")
    fails = sum(1 for r in results if r.status == "FAIL")

    # ── Severity breakdown ──
    severity_counts = {"CRITICAL": 0, "HIGH": 0, "MEDIUM": 0, "LOW": 0, "INFO": 0}
    for r in results:
        if r.status in ("CRASH", "WARN", "FAIL") and r.severity in severity_counts:
            severity_counts[r.severity] += 1

    # ── Score calculation ──
    score = 100
    for r in results:
        key = (r.status, r.severity)
        score -= _DEDUCTIONS.get(key, 0)
    score = max(0, min(100, score))

    # ── CWE summary ──
    cwe_map: dict[str, list[str]] = {}
    for r in results:
        if r.cwe and r.status in ("CRASH", "WARN", "FAIL"):
            cwe_map.setdefault(r.cwe, []).append(r.test)

    # ── Per-category breakdown ──
    categories: dict[str, dict] = {}
    for r in results:
        cat = r.category
        if cat not in categories:
            categories[cat] = {"total": 0, "crashes": 0, "warnings": 0, "passes": 0}
        categories[cat]["total"] += 1
        if r.status == "CRASH":
            categories[cat]["crashes"] += 1
        elif r.status == "WARN":
            categories[cat]["warnings"] += 1
        elif r.status == "PASS":
            categories[cat]["passes"] += 1

    # ── Latency stats ──
    latencies = [r.latency_ms for r in results if r.latency_ms > 0]
    latency_stats = {}
    if latencies:
        latencies_sorted = sorted(latencies)
        latency_stats = {
            "min_ms": round(latencies_sorted[0], 1),
            "max_ms": round(latencies_sorted[-1], 1),
            "avg_ms": round(sum(latencies) / len(latencies), 1),
            "p95_ms": round(latencies_sorted[int(len(latencies_sorted) * 0.95)], 1),
        }

    # ── Results serialized ──
    results_list = [
        {
            "test": r.test,
            "status": r.status,
            "detail": r.detail,
            "latency_ms": r.latency_ms,
            "category": r.category,
            "severity": r.severity,
            "cwe": r.cwe,
        }
        for r in results
    ]

    return {
        "meta": {
            "target": target,
            "method": method,
            "mode": mode,
            "engine_version": ENGINE_VERSION,
            "timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(),
            "duration_ms": suite_output.duration_ms,
            "total_tests": total,
        },
        "score": score,
        "grade": grade(score),
        "summary": {
            "total": total,
            "crashes": crashes,
            "warnings": warnings,
            "passes": passes,
            "failures": fails,
        },
        "severity": severity_counts,
        "categories": categories,
        "cwe_summary": {k: len(v) for k, v in cwe_map.items()},
        "latency": latency_stats,
        "results": results_list,
    }
