"""
Reporting models and console/HTML/JSON reporters.

Rich console output with full colour — far better than competitors'
plain-text logging.
"""

from __future__ import annotations

import json
import time
from dataclasses import asdict, dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional

try:
    from rich.console import Console
    from rich.table import Table
    from rich import print as rprint
    _RICH = True
except ImportError:
    _RICH = False

_console = Console(highlight=False) if _RICH else None


@dataclass
class HealingEvent:
    """Record of a single healing attempt."""

    selector: str
    description: str
    url: str
    healed_selector: str = ""
    stage: str = ""            # ORIGINAL | HEURISTIC | DOM_FUZZY | AI_DOM | AI_VISUAL | CACHE | NONE
    success: bool = False
    confidence: float = 0.0
    latency_ms: float = 0.0
    tokens_used: int = 0
    provider: str = ""
    model: str = ""
    test_name: str = ""
    timestamp: float = field(default_factory=time.time)
    error: str = ""


@dataclass
class SessionReport:
    """Aggregate report for a test session."""

    session_id: str = ""
    start_time: float = field(default_factory=time.time)
    end_time: float = 0.0
    events: List[HealingEvent] = field(default_factory=list)

    @property
    def total(self) -> int:
        return len(self.events)

    @property
    def healed(self) -> int:
        return sum(1 for e in self.events if e.success and e.stage != "ORIGINAL")

    @property
    def from_cache(self) -> int:
        return sum(1 for e in self.events if e.stage == "CACHE")

    @property
    def failed(self) -> int:
        return sum(1 for e in self.events if not e.success)

    @property
    def total_tokens(self) -> int:
        return sum(e.tokens_used for e in self.events)

    @property
    def avg_latency_ms(self) -> float:
        lats = [e.latency_ms for e in self.events if e.latency_ms > 0]
        return sum(lats) / len(lats) if lats else 0.0

    def to_dict(self) -> dict:
        d = asdict(self)
        d["summary"] = {
            "total": self.total,
            "healed": self.healed,
            "from_cache": self.from_cache,
            "failed": self.failed,
            "total_tokens": self.total_tokens,
            "avg_latency_ms": round(self.avg_latency_ms, 1),
        }
        return d


class ConsoleReporter:
    """Rich coloured console output for healing events."""

    STAGE_COLORS = {
        "ORIGINAL":   "green",
        "CACHE":      "cyan",
        "HEURISTIC":  "blue",
        "DOM_FUZZY":  "magenta",
        "AI_DOM":     "yellow",
        "AI_VISUAL":  "bright_yellow",
        "NONE":       "red",
    }

    def log_event(self, event: HealingEvent, enabled: bool = True) -> None:
        if not enabled:
            return
        if _RICH and _console:
            self._log_rich(event)
        else:
            self._log_plain(event)

    def _log_rich(self, event: HealingEvent) -> None:
        assert _console
        stage = event.stage
        color = self.STAGE_COLORS.get(stage, "white")
        status = "[bold green]HEALED[/]" if event.success else "[bold red]FAILED[/]"
        symbol = "✓" if event.success else "✗"

        if stage == "ORIGINAL":
            _console.print(
                f"  [dim]{symbol}[/dim] [dim]ORIGINAL[/dim] [{color}]{event.selector}[/{color}]"
            )
        elif event.success:
            tokens_str = f" [{event.tokens_used}t]" if event.tokens_used else ""
            _console.print(
                f"  [bold green]{symbol}[/bold green] {status} "
                f"[{color}]{stage}[/{color}]"
                f"  [dim]{event.selector}[/dim] → [bold]{event.healed_selector}[/bold]"
                f"  [dim]{event.latency_ms:.0f}ms{tokens_str}[/dim]"
                f"  [dim]conf={event.confidence:.0%}[/dim]"
            )
        else:
            _console.print(
                f"  [bold red]{symbol}[/bold red] {status} "
                f"[dim]{event.selector}[/dim]"
                + (f"  [red]{event.error[:80]}[/red]" if event.error else "")
            )

    def _log_plain(self, event: HealingEvent) -> None:
        status = "SUCCESS" if event.success else "FAILED"
        print(
            f"  [{status}] [{event.stage}] {event.latency_ms:.0f}ms "
            f"{event.selector} -> {event.healed_selector}"
        )

    def print_summary(self, report: SessionReport, enabled: bool = True) -> None:
        if not enabled:
            return
        if _RICH and _console:
            self._summary_rich(report)
        else:
            self._summary_plain(report)

    def _summary_rich(self, report: SessionReport) -> None:
        assert _console
        table = Table(title="playwright-healer Session Summary", show_header=True)
        table.add_column("Metric", style="bold")
        table.add_column("Value")
        table.add_row("Total lookups", str(report.total))
        table.add_row("Healed (non-trivial)", str(report.healed))
        table.add_row("From cache", str(report.from_cache))
        table.add_row("Failed", str(report.failed) if report.failed == 0 else f"[red]{report.failed}[/red]")
        table.add_row("AI tokens used", str(report.total_tokens))
        table.add_row("Avg latency", f"{report.avg_latency_ms:.0f} ms")
        _console.print(table)

    def _summary_plain(self, report: SessionReport) -> None:
        print(f"\nplaywright-healer: {report.healed}/{report.total} healed "
              f"({report.from_cache} cached, {report.failed} failed)")


class HTMLReporter:
    """Generate a self-contained HTML report."""

    def generate(self, report: SessionReport, output_dir: str) -> str:
        out = Path(output_dir)
        out.mkdir(parents=True, exist_ok=True)
        ts = datetime.fromtimestamp(report.start_time).strftime("%Y%m%d_%H%M%S")
        filename = out / f"playwright_healer_{ts}.html"

        rows = ""
        for e in report.events:
            stage_class = e.stage.lower().replace("_", "-")
            status_class = "success" if e.success else "failed"
            rows += f"""
            <tr class="{status_class}">
              <td>{e.test_name or 'N/A'}</td>
              <td class="selector">{_esc(e.selector)}</td>
              <td class="selector">{_esc(e.healed_selector) if e.healed_selector else '—'}</td>
              <td><span class="badge {stage_class}">{e.stage}</span></td>
              <td>{e.confidence:.0%}</td>
              <td>{e.latency_ms:.0f} ms</td>
              <td>{e.tokens_used}</td>
              <td>{e.provider}</td>
            </tr>"""

        html = _HTML_TEMPLATE.format(
            ts=datetime.fromtimestamp(report.start_time).strftime("%Y-%m-%d %H:%M:%S"),
            total=report.total,
            healed=report.healed,
            cached=report.from_cache,
            failed=report.failed,
            tokens=report.total_tokens,
            avg_lat=f"{report.avg_latency_ms:.0f}",
            rows=rows,
        )
        filename.write_text(html, encoding="utf-8")
        return str(filename)


class JSONReporter:
    """Generate a machine-readable JSON report."""

    def generate(self, report: SessionReport, output_dir: str) -> str:
        out = Path(output_dir)
        out.mkdir(parents=True, exist_ok=True)
        ts = datetime.fromtimestamp(report.start_time).strftime("%Y%m%d_%H%M%S")
        filename = out / f"playwright_healer_{ts}.json"
        filename.write_text(
            json.dumps(report.to_dict(), indent=2, ensure_ascii=False),
            encoding="utf-8",
        )
        return str(filename)


def _esc(s: str) -> str:
    return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")


_HTML_TEMPLATE = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>playwright-healer Report</title>
<style>
  body {{ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
         margin: 40px; background: #0f172a; color: #e2e8f0; }}
  h1 {{ color: #7c3aed; margin-bottom: 4px; }}
  .subtitle {{ color: #64748b; margin-bottom: 32px; }}
  .stats {{ display: flex; gap: 20px; margin-bottom: 32px; flex-wrap: wrap; }}
  .stat {{ background: #1e293b; border-radius: 12px; padding: 20px 28px;
           min-width: 120px; text-align: center; }}
  .stat-value {{ font-size: 2rem; font-weight: 700; color: #7c3aed; }}
  .stat-label {{ font-size: 0.8rem; color: #64748b; margin-top: 4px; }}
  table {{ width: 100%; border-collapse: collapse; background: #1e293b;
           border-radius: 12px; overflow: hidden; }}
  th {{ padding: 12px 16px; background: #334155; text-align: left;
        font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }}
  td {{ padding: 10px 16px; border-bottom: 1px solid #334155; font-size: 0.85rem; }}
  tr.failed td {{ color: #f87171; }}
  tr.success td {{ color: #e2e8f0; }}
  .selector {{ font-family: monospace; font-size: 0.8rem; }}
  .badge {{ padding: 2px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: 600; }}
  .badge.cache {{ background: #0e7490; color: #cffafe; }}
  .badge.heuristic {{ background: #1d4ed8; color: #bfdbfe; }}
  .badge.dom-fuzzy {{ background: #7e22ce; color: #e9d5ff; }}
  .badge.ai-dom {{ background: #b45309; color: #fef3c7; }}
  .badge.ai-visual {{ background: #b45309; color: #fef3c7; }}
  .badge.original {{ background: #166534; color: #bbf7d0; }}
  .badge.none {{ background: #991b1b; color: #fee2e2; }}
</style>
</head>
<body>
<h1>⚡ playwright-healer</h1>
<p class="subtitle">Session report — {ts}</p>
<div class="stats">
  <div class="stat"><div class="stat-value">{total}</div><div class="stat-label">Total</div></div>
  <div class="stat"><div class="stat-value" style="color:#22c55e">{healed}</div><div class="stat-label">Healed</div></div>
  <div class="stat"><div class="stat-value" style="color:#06b6d4">{cached}</div><div class="stat-label">Cached</div></div>
  <div class="stat"><div class="stat-value" style="color:#f87171">{failed}</div><div class="stat-label">Failed</div></div>
  <div class="stat"><div class="stat-value">{tokens}</div><div class="stat-label">Tokens</div></div>
  <div class="stat"><div class="stat-value">{avg_lat}ms</div><div class="stat-label">Avg Latency</div></div>
</div>
<table>
<thead>
  <tr><th>Test</th><th>Original Selector</th><th>Healed Selector</th>
      <th>Stage</th><th>Confidence</th><th>Latency</th><th>Tokens</th><th>Provider</th></tr>
</thead>
<tbody>{rows}</tbody>
</table>
</body>
</html>"""
