"""Rich terminal reporter with severity colours and scan summary."""
from __future__ import annotations

from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from pyguard.models import ScanResult, Severity

_SEVERITY_STYLE: dict[Severity, str] = {
    Severity.CRITICAL: "bold red",
    Severity.HIGH: "red",
    Severity.MEDIUM: "yellow",
    Severity.LOW: "cyan",
    Severity.INFO: "dim",
}

_SEVERITY_ICON: dict[Severity, str] = {
    Severity.CRITICAL: "🔴",
    Severity.HIGH: "🟠",
    Severity.MEDIUM: "🟡",
    Severity.LOW: "🔵",
    Severity.INFO: "⚪",
}


def _severity_text(sev: Severity) -> Text:
    label = sev.value.upper()
    style = _SEVERITY_STYLE[sev]
    return Text(f"{_SEVERITY_ICON[sev]} {label}", style=style)


def render_terminal(result: ScanResult, console: Console) -> None:
    # ── Header panel ─────────────────────────────────────────────────
    layers = ", ".join(result.layers_run)
    header = (
        f"[bold]{result.package.name}[/bold] [dim]v{result.package.version}[/dim]  "
        f"Risk: {_severity_text(result.risk_label).markup}  "
        f"Score: {result.risk_score:.1f}/10  "
        f"Layers: [dim]{layers}[/dim]  "
        f"[dim]{result.scan_duration_ms} ms[/dim]"
    )
    console.print(Panel(header, expand=False))

    if not result.findings:
        console.print("[green]  ✅  No findings — package looks clean.[/green]\n")
        return

    # ── Findings table ────────────────────────────────────────────────
    table = Table(show_header=True, header_style="bold", expand=True)
    table.add_column("Severity", width=12)
    table.add_column("Layer", width=8)
    table.add_column("Title")
    table.add_column("Location", width=30)
    table.add_column("Conf.", width=6)

    for finding in sorted(
        result.findings,
        key=lambda f: (-_sev_rank(f.severity), f.layer),
    ):
        location = "—"
        if finding.file:
            location = finding.file
            if finding.line:
                location += f":{finding.line}"

        table.add_row(
            _severity_text(finding.severity),
            finding.layer,
            finding.title,
            location,
            f"{finding.confidence:.0%}",
        )

    console.print(table)

    # ── Finding details ───────────────────────────────────────────────
    for finding in sorted(result.findings, key=lambda f: -_sev_rank(f.severity)):
        style = _SEVERITY_STYLE[finding.severity]
        console.print(f"  [{style}]▶ {finding.title}[/{style}]")
        console.print(f"    {finding.description}")
        if finding.remediation:
            console.print(f"    [green]Fix:[/green] {finding.remediation}")
        if finding.cve_id:
            console.print(f"    [dim]CVE:[/dim] {finding.cve_id}")
        console.print()

    # ── Summary line ──────────────────────────────────────────────────
    counts = _count_by_severity(result.findings)
    parts = [
        f"[bold red]{counts.get(Severity.CRITICAL, 0)} CRITICAL[/bold red]",
        f"[red]{counts.get(Severity.HIGH, 0)} HIGH[/red]",
        f"[yellow]{counts.get(Severity.MEDIUM, 0)} MEDIUM[/yellow]",
        f"[cyan]{counts.get(Severity.LOW, 0)} LOW[/cyan]",
    ]
    console.print("  " + "  ".join(parts) + "\n")


def render_summary_table(results: list[ScanResult], console: Console) -> None:
    """Print a compact multi-package summary table."""
    table = Table(title="pyguard scan summary", show_header=True, header_style="bold")
    table.add_column("Package", style="bold")
    table.add_column("Version")
    table.add_column("Risk")
    table.add_column("Score", justify="right")
    table.add_column("Findings", justify="right")
    table.add_column("Duration")

    for result in results:
        table.add_row(
            result.package.name,
            result.package.version,
            _severity_text(result.risk_label),
            f"{result.risk_score:.1f}",
            str(len(result.findings)),
            f"{result.scan_duration_ms} ms",
        )

    console.print(table)


def _sev_rank(sev: Severity) -> int:
    return {
        Severity.CRITICAL: 5,
        Severity.HIGH: 4,
        Severity.MEDIUM: 3,
        Severity.LOW: 2,
        Severity.INFO: 1,
    }[sev]


def _count_by_severity(findings: list) -> dict[Severity, int]:
    counts: dict[Severity, int] = {}
    for f in findings:
        counts[f.severity] = counts.get(f.severity, 0) + 1
    return counts
