"""Structured output for container watcher integration.

Results and errors are printed directly to stdout/stderr to ensure
they're always visible regardless of log level settings.
"""

import json
import sys
import time
from datetime import datetime
from typing import Any

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

_stderr_console = Console(stderr=True, highlight=False)


class ProgressTracker:
    """Rich-based CLI progress tracker.

    Prints a branded header, then shows each pipeline step with a spinner
    while active and a checkmark (with detail + duration) once completed.

    Usage::

        tracker = ProgressTracker(...)
        tracker.start()
        try:
            tracker.step("Fetching PR...")
            ...
            tracker.done("found 3 files")
            tracker.step("Triaging...")
            ...
        finally:
            tracker.finish()           # prints last ✓ + total time
            # or tracker.fail(msg)     # prints ✗ + error
    """

    def __init__(
        self,
        *,
        repo: str,
        pr: str,
        workflows: str,
        review_model: str,
        utility_model: str,
        version: str,
        console: Console | None = None,
    ) -> None:
        self._console = console or Console(stderr=True, highlight=False)
        self._repo = repo
        self._pr = pr
        self._workflows = workflows
        self._review_model = review_model
        self._utility_model = utility_model
        self._version = version

        self._status: Status | None = None
        self._current_step: str | None = None
        self._step_detail: str = ""
        self._step_start: float = 0.0
        self._total_start: float = 0.0

    # -- Public API (passed as callbacks to workflows) --

    def step(self, msg: str) -> None:
        """Start a new pipeline step. Completes the previous one if any."""
        if self._status is None:
            return
        if self._current_step is not None:
            self._status.stop()
            self._print_completed()
            self._status.start()
        self._current_step = msg
        self._step_detail = ""
        self._step_start = time.time()
        self._status.update(f"  [bold cyan]{msg}[/]")

    def done(self, detail: str) -> None:
        """Attach a result detail to the current step (shown on the ✓ line)."""
        self._step_detail = detail

    # -- Lifecycle --

    def start(self) -> None:
        """Print the header panel and start the spinner."""
        self._total_start = time.time()
        body = Text.from_markup(
            f"{self._repo} [bold]#{self._pr}[/] [dim]\u00b7[/] {self._workflows}\n"
            f"[dim]review:[/]  {self._review_model}\n"
            f"[dim]utility:[/] {self._utility_model}\n"
            f"[dim]models:[/]  [dim link=https://models.litellm.ai/]models.litellm.ai[/]"
        )
        self._console.print()
        self._console.print(
            Panel(
                body,
                title=f"[bold]Reviewate[/] [dim]v{self._version}[/]",
                title_align="left",
                border_style="cyan",
                expand=False,
                padding=(0, 1),
            )
        )
        self._status = Status(
            "  [bold cyan]Initializing...[/]", console=self._console, spinner="dots"
        )
        self._status.start()

    def finish(self) -> None:
        """Stop spinner, print last completed step, and show total duration."""
        if self._status is None:
            return
        self._status.stop()
        self._print_completed()
        elapsed = time.time() - self._total_start
        self._console.print(f"\n  [bold green]\u2713 Done in {elapsed:.1f}s[/]")
        self._console.print()
        self._status = None

    def fail(self, error: str) -> None:
        """Stop spinner and show current step as failed."""
        if self._status is None:
            return
        self._status.stop()
        self._console.print(f"  [red]\u2717[/] {self._current_step}")
        self._console.print(f"\n  [bold red]Error: {error}[/]")
        self._console.print()
        self._status = None

    # -- Internal --

    def _print_completed(self) -> None:
        if self._current_step is not None:
            elapsed = time.time() - self._step_start
            detail = f" [dim]{self._step_detail}[/]" if self._step_detail else ""
            self._console.print(
                f"  [green]\u2713[/] {self._current_step}{detail} [dim]({elapsed:.1f}s)[/]"
            )


def _timestamp() -> str:
    """Get current timestamp in log format."""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")


def _format_tokens(tokens: int) -> str:
    """Format token count with K/M suffix for readability."""
    if tokens >= 1_000_000:
        return f"{tokens / 1_000_000:.1f}M"
    if tokens >= 1_000:
        return f"{tokens / 1_000:.1f}K"
    return str(tokens)


def print_result_summary(data: dict[str, Any]) -> None:
    """Print a human-readable summary of the review result.

    Args:
        data: The result data dictionary containing status, token_usage, etc.
    """
    con = _stderr_console
    status = data.get("status", "unknown")
    workflows = data.get("workflows", [])
    token_usage = data.get("token_usage", {})
    per_agent = data.get("per_agent_usage", {})
    comments = data.get("review_comments", [])

    # Status and issues
    issues_found = sum(w.get("issues_found", 0) for w in workflows)
    if status == "success":
        con.print(f"\n[bold green]✓ Status: {status}[/]")
    else:
        con.print(f"\n[bold red]✗ Status: {status}[/]")
    con.print(f"  Issues found: {issues_found}")

    # Token usage summary
    total = token_usage.get("total_tokens", 0)
    cached = token_usage.get("cached_tokens", 0)
    cache_rate = (
        (cached / token_usage.get("input_tokens", 1)) * 100
        if token_usage.get("input_tokens")
        else 0
    )

    con.print("\n📊 [bold]Token Usage:[/]")
    token_table = Table(show_header=False, box=None, padding=(0, 1))
    token_table.add_column(style="dim", min_width=8)
    token_table.add_column()
    token_table.add_row("Total:", _format_tokens(total))
    token_table.add_row("Input:", _format_tokens(token_usage.get("input_tokens", 0)))
    token_table.add_row("Output:", _format_tokens(token_usage.get("output_tokens", 0)))
    token_table.add_row("Cached:", f"{_format_tokens(cached)} ({cache_rate:.0f}%)")
    con.print(token_table)

    # Per-agent breakdown
    if per_agent:
        con.print("\n📋 [bold]Per-Agent Breakdown:[/]")
        agent_table = Table(box=None, padding=(0, 1))
        agent_table.add_column("Agent", style="cyan")
        agent_table.add_column("Model", style="dim")
        agent_table.add_column("Tokens", justify="right")
        agent_table.add_column("Cached", justify="right")

        for agent, usage in per_agent.items():
            if isinstance(usage, dict):
                agent_total = usage.get("total_tokens", 0)
                agent_cached = usage.get("cached_tokens", 0)
                model = usage.get("model", "unknown")
                model_short = model.split("/")[-1] if "/" in model else model
                if len(model_short) > 28:
                    model_short = model_short[:25] + "..."

                agent_table.add_row(
                    agent, model_short, _format_tokens(agent_total), _format_tokens(agent_cached)
                )

                exploration = usage.get("exploration_cost")
                if exploration and exploration.get("total_tokens", 0) > 0:
                    exp_total = exploration.get("total_tokens", 0)
                    agent_table.add_row("  └─ exploration", "", _format_tokens(exp_total), "")

        con.print(agent_table)

    # Review comments preview
    if comments:
        con.print(f"\n💬 [bold]Review Comments ({len(comments)}):[/]")
        for i, comment in enumerate(comments, 1):
            lines = comment.strip().split("\n")
            title = lines[0]
            title_text = Text(f"  {i}. {title}")
            title_text.stylize("dim", 0, 5)
            con.print(title_text)
            for line in lines[1:]:
                if line.strip():
                    con.print(Text(f"     {line}"))

    con.print()


def emit_result(data: dict[str, Any], include_reviews: bool = False) -> None:
    """Emit structured result for watcher.

    Always prints to stdout regardless of log level.
    Format: [TIMESTAMP] [INFO] [output.output] output=output [REVIEWATE:RESULT] {...json...}

    Note: review_comments and review_objects are stripped by default because
    the backend doesn't use them (reviews are posted by the container directly)
    and including them makes the line too large for Docker log parsing.
    Set include_reviews=True for dry-run/benchmark mode.
    """
    if include_reviews:
        watcher_data = data
    else:
        watcher_data = {
            k: v for k, v in data.items() if k not in ("review_comments", "review_objects")
        }
    print(
        f"[{_timestamp()}] [INFO    ] [output.output] output=output [REVIEWATE:RESULT] {json.dumps(watcher_data)}",
        file=sys.stdout,
    )


def emit_error(error_type: str, message: str, details: dict[str, Any] | None = None) -> None:
    """Emit structured error for watcher.

    Always prints to stderr regardless of log level.
    Format: [TIMESTAMP] [ERROR] [output.output] output=output [REVIEWATE:ERROR] {...json...}
    """
    error_data = {"type": error_type, "message": message}
    if details:
        error_data.update(details)
    print(
        f"[{_timestamp()}] [ERROR   ] [output.output] output=output [REVIEWATE:ERROR] {json.dumps(error_data)}",
        file=sys.stderr,
    )


def emit_status(status: str) -> None:
    """Emit status update for watcher.

    Always prints to stdout regardless of log level.
    Format: [TIMESTAMP] [INFO] [output.output] output=output [REVIEWATE:STATUS] <status>
    """
    print(
        f"[{_timestamp()}] [INFO    ] [output.output] output=output [REVIEWATE:STATUS] {status}",
        file=sys.stdout,
    )
