"""Vulnerability report — generates a detailed vuln.md after each scan."""

from __future__ import annotations

import logging
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path

from secagent.models import Severity, Vulnerability, VerificationStatus

logger = logging.getLogger(__name__)

_SEVERITY_ORDER = [
    Severity.CRITICAL,
    Severity.HIGH,
    Severity.MEDIUM,
    Severity.LOW,
    Severity.INFO,
    Severity.UNKNOWN,
]

_SEVERITY_BADGE = {
    Severity.CRITICAL: "🔴 CRITICAL",
    Severity.HIGH:     "🟠 HIGH",
    Severity.MEDIUM:   "🟡 MEDIUM",
    Severity.LOW:      "🟢 LOW",
    Severity.INFO:     "⚪ INFO",
    Severity.UNKNOWN:  "⬜ UNKNOWN",
}


def generate_vuln_report(
    vulns: list[Vulnerability],
    target: str,
    output_dir: Path,
) -> Path:
    """Write a detailed Markdown vulnerability report to *output_dir*/vuln.md.

    Parameters
    ----------
    vulns:
        Deduplicated list of vulnerabilities from the scan stage.
    target:
        Path string of the scanned file or directory.
    output_dir:
        The ``.secagent/`` directory to write into.

    Returns
    -------
    Path
        Absolute path to the written ``vuln.md``.
    """
    report_path = output_dir / "vuln.md"

    now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")

    # ── Count by severity ──────────────────────────────────────────────
    counts: dict[Severity, int] = defaultdict(int)
    for v in vulns:
        counts[v.severity] += 1

    lines: list[str] = [
        "# SecAgent Vulnerability Report\n",
        f"**Generated:** {now}  ",
        f"**Target:** `{target}`  ",
        f"**Total findings:** {len(vulns)}\n",
    ]

    # ── Severity summary table ─────────────────────────────────────────
    if vulns:
        lines += [
            "## Summary\n",
            "| Severity | Count |",
            "|---|---|",
        ]
        for sev in _SEVERITY_ORDER:
            if counts[sev]:
                lines.append(f"| {_SEVERITY_BADGE[sev]} | {counts[sev]} |")
        lines.append("")

        # ── Group by file ──────────────────────────────────────────────
        by_file: dict[str, list[Vulnerability]] = defaultdict(list)
        no_file: list[Vulnerability] = []
        for v in vulns:
            if v.file:
                by_file[v.file].append(v)
            else:
                no_file.append(v)

        lines += ["---\n", "## Findings\n"]

        # Sort files; within each file sort by severity then line
        for filepath in sorted(by_file.keys()):
            file_vulns = sorted(
                by_file[filepath],
                key=lambda v: (_SEVERITY_ORDER.index(v.severity), v.line),
            )
            lines.append(f"### `{filepath}`\n")
            for v in file_vulns:
                _append_vuln(lines, v)

        if no_file:
            lines.append("### (No specific file)\n")
            for v in sorted(no_file, key=lambda v: _SEVERITY_ORDER.index(v.severity)):
                _append_vuln(lines, v)

    else:
        lines += ["---\n", "**No vulnerabilities found.** \n"]

    report_path.write_text("\n".join(lines), encoding="utf-8")
    logger.info("Vuln report written to %s", report_path)
    return report_path


def _append_vuln(lines: list[str], v: Vulnerability) -> None:
    """Append a single vulnerability block to *lines*."""
    badge = _SEVERITY_BADGE.get(v.severity, str(v.severity))
    verification = ""
    if v.verification == VerificationStatus.TP:
        verification = " — ✅ True Positive"
    elif v.verification == VerificationStatus.FP:
        verification = " — ❌ False Positive"

    lines.append(f"#### {badge} — {v.description}{verification}\n")
    lines.append(f"| Field | Value |")
    lines.append(f"|---|---|")
    lines.append(f"| Scanner | `{v.scanner}` |")
    lines.append(f"| Type | `{v.vuln_type}` |")
    lines.append(f"| File | `{v.file}` |")
    lines.append(f"| Line | {v.line if v.line > 0 else '—'} |")
    if v.verification:
        lines.append(f"| Verification | {v.verification.value} |")
    lines.append("")
