"""Built-in Rich progress display for the pentesting agent.

Renders a live console view of agent activity including
planner/executor/reasoner events and scan-level progress.

The display is enabled by default when using ``PentestOrchestrator``.
Disable it by passing ``show_progress=False``::

    orchestrator = PentestOrchestrator(
        adapter=adapter,
        llm_client=llm_client,
        show_progress=False,  # suppress console output
    )
"""

from __future__ import annotations

import time
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from ziran.application.agent_scanner.scanner import ProgressEvent

# Lazy import Rich so the module can be imported even if rich isn't installed.
_RICH_AVAILABLE = True
try:
    from rich.console import Console
    from rich.table import Table
except ImportError:
    _RICH_AVAILABLE = False


# ── Emoji / symbol helpers ───────────────────────────────────────────────

_EVENT_STYLES: dict[str, tuple[str, str]] = {
    "plan": ("🧠", "bold cyan"),
    "execute": ("⚡", "bold yellow"),
    "reason": ("🔍", "bold magenta"),
    "report": ("📝", "bold green"),
}

_SEVERITY_COLORS: dict[str, str] = {
    "critical": "bold red",
    "high": "red",
    "medium": "yellow",
    "low": "green",
}


class PentestProgressDisplay:
    """Rich-based live progress display for pentesting sessions.

    Provides two callbacks that can be passed directly to
    ``PentestOrchestrator``:

    - ``on_agent_event(event_type, message)`` — agent-level events
      (plan, execute, reason, report)
    - ``on_progress(event)`` — scan-level progress events
      (attacks loaded, running, completed)
    """

    def __init__(self, *, console: Any | None = None, verbose: bool = False) -> None:
        if not _RICH_AVAILABLE:
            self._console = None
            return
        self._console: Console | None = console or Console()  # type: ignore[no-redef]
        self._verbose = verbose
        self._start_time = time.monotonic()
        self._current_phase: str | None = None
        self._attacks_complete = 0
        self._attacks_total = 0
        self._vulns_found = 0
        self._header_shown = False

    # ── Agent-level callback ─────────────────────────────────────────

    def on_agent_event(self, event_type: str, message: str) -> None:
        """Handle agent node events (plan/execute/reason/report)."""
        if self._console is None:
            return

        if not self._header_shown:
            self._show_header()
            self._header_shown = True

        icon, style = _EVENT_STYLES.get(event_type, ("▸", "dim"))
        elapsed = time.monotonic() - self._start_time

        self._console.print(
            f"  {icon} [{style}]{event_type.upper():>8}[/{style}]  "
            f"{message}  [dim]({elapsed:.1f}s)[/dim]"
        )

    # ── Scan-level callback ──────────────────────────────────────────

    def on_progress(self, event: ProgressEvent) -> None:
        """Handle scan-level progress events."""
        if self._console is None:
            return

        from ziran.application.agent_scanner.scanner import ProgressEventType

        etype = event.event

        if etype == ProgressEventType.PHASE_START:
            self._current_phase = event.phase
            self._attacks_complete = 0
            self._attacks_total = 0
            phase_label = (event.phase or "unknown").replace("_", " ").title()
            self._console.print(
                f"  {'🔄':>3} [bold blue]  PHASE[/bold blue]  "
                f"{phase_label} "
                f"[dim]({event.phase_index + 1}/{event.total_phases})[/dim]"
            )

        elif etype == ProgressEventType.PHASE_ATTACKS_LOADED:
            self._attacks_total = event.total_attacks
            if self._verbose:
                self._console.print(
                    f"         [dim]Loaded {event.total_attacks} attack vectors[/dim]"
                )

        elif etype == ProgressEventType.ATTACK_START:
            self._attacks_complete = event.attack_index
            if self._verbose:
                self._console.print(
                    f"         [dim]({event.attack_index + 1}/{event.total_attacks}) "
                    f"{event.attack_name}[/dim]"
                )

        elif etype == ProgressEventType.ATTACK_COMPLETE:
            self._attacks_complete = event.attack_index + 1
            successful = event.extra.get("successful", False)
            if successful:
                self._vulns_found += 1
                sev = event.extra.get("severity", "medium")
                sev_style = _SEVERITY_COLORS.get(sev, "yellow")
                self._console.print(
                    f"  {'💥':>3} [bold red]    HIT![/bold red]  "
                    f"[{sev_style}]{event.attack_name}[/{sev_style}] "
                    f"[dim]({sev})[/dim]"
                )
            elif self._verbose:
                self._console.print(
                    f"         [dim]({event.attack_index + 1}/{event.total_attacks}) blocked[/dim]"
                )

        elif etype == ProgressEventType.PHASE_COMPLETE:
            vulns = event.extra.get("vulnerabilities_found", 0)
            attacks = event.extra.get("attacks_executed", 0)
            if vulns > 0:
                self._console.print(
                    f"  {'✓':>3} [bold green]  DONE[/bold green]  "
                    f"[bold]{vulns}[/bold] vuln{'s' if vulns != 1 else ''} "
                    f"in {attacks} attacks"
                )
            else:
                self._console.print(f"  {'✓':>3} [dim]  DONE[/dim]  0 vulns in {attacks} attacks")

        elif etype == ProgressEventType.CAMPAIGN_COMPLETE:
            pass  # Summary handled by show_summary

    # ── Header / Summary ─────────────────────────────────────────────

    def _show_header(self) -> None:
        """Print the session header."""
        if self._console is None:
            return
        self._start_time = time.monotonic()
        self._console.print()
        self._console.rule("[bold cyan]⛩️  ZIRAN Pentesting Agent[/bold cyan]")
        self._console.print()

    def show_summary(
        self,
        *,
        session_id: str,
        status: str,
        iterations: int,
        vulnerabilities: int,
        attacks: int,
        findings: int,
        tokens: int,
    ) -> None:
        """Print a final summary table after the session completes."""
        if self._console is None:
            return

        elapsed = time.monotonic() - self._start_time

        self._console.print()

        table = Table(
            title="Session Summary",
            show_header=False,
            border_style="dim",
            padding=(0, 1),
        )
        table.add_column("Metric", style="bold")
        table.add_column("Value", justify="right")

        status_style = "bold green" if status == "complete" else "bold red"
        table.add_row("Status", f"[{status_style}]{status.upper()}[/{status_style}]")
        table.add_row("Session", f"[dim]{session_id}[/dim]")
        table.add_row("Iterations", str(iterations))
        table.add_row(
            "Vulnerabilities", f"[bold red]{vulnerabilities}[/bold red]" if vulnerabilities else "0"
        )
        table.add_row("Unique Findings", str(findings))
        table.add_row("Attacks Executed", str(attacks))
        table.add_row("Tokens Used", f"{tokens:,}")
        table.add_row("Duration", f"{elapsed:.1f}s")

        self._console.print(table)
        self._console.print()
