"""Output formatter for Teams Phone CLI.

This module provides rich terminal output formatting including tables,
JSON output mode, progress bars, and styled messages with remediation guidance.
"""

from __future__ import annotations

import json
import os
import sys
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any

from rich.console import Console
from rich.progress import (
    Progress,
    SpinnerColumn,
    TextColumn,
    BarColumn,
    TaskProgressColumn,
)
from rich.table import Table

if TYPE_CHECKING:
    from collections.abc import Iterator


def _can_encode_unicode() -> bool:
    """Check if stdout can encode Unicode characters.

    Tests by attempting to encode a Unicode checkmark. On Windows with
    legacy console (cp1252), this will fail.

    Returns:
        True if Unicode is supported, False if ASCII-only mode is needed.
    """
    try:
        # Test with checkmark - if this fails, we need ASCII mode
        encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
        "✓".encode(encoding)
        return True
    except (UnicodeEncodeError, LookupError):
        return False


# ASCII-safe placeholder for "no value" display
# Em-dash (—) works in most encodings but we provide a fallback
PLACEHOLDER_UNICODE = "—"
PLACEHOLDER_ASCII = "-"


class OutputFormatter:
    """Format and display output for the CLI.

    Provides methods for displaying data as tables, JSON, or styled messages.
    Supports color control via constructor flag and NO_COLOR environment variable.

    Attributes:
        console: Rich Console instance for output.
        json_mode: Whether to output JSON instead of Rich formatting.
        no_color: Whether color output is disabled.
    """

    def __init__(
        self,
        console: Console | None = None,
        *,
        json_mode: bool = False,
        no_color: bool = False,
    ) -> None:
        """Initialize the OutputFormatter.

        Args:
            console: Optional Rich Console instance. If not provided, creates one.
            json_mode: If True, output JSON to stdout instead of Rich formatting.
            no_color: If True, disable color output. Also respects NO_COLOR env var.
        """
        self.json_mode = json_mode
        # Respect both the flag and the NO_COLOR environment variable
        self.no_color = no_color or os.environ.get("NO_COLOR") is not None
        # Detect Unicode support for Windows compatibility
        self._use_ascii = not _can_encode_unicode()

        if console is not None:
            self.console = console
        else:
            self.console = Console(
                force_terminal=not json_mode,
                no_color=self.no_color,
            )

    def table(
        self,
        data: list[dict[str, Any]],
        columns: list[str],
        *,
        title: str | None = None,
    ) -> None:
        """Display data as a formatted table.

        Args:
            data: List of dictionaries containing row data.
            columns: List of column names to display.
            title: Optional title for the table.
        """
        if self.json_mode:
            self.json(data)
            return

        table = Table(title=title)

        for column in columns:
            table.add_column(column, style="cyan")

        for row in data:
            table.add_row(*[str(row.get(col, "")) for col in columns])

        self.console.print(table)

    def json(self, data: Any) -> None:
        """Output data as JSON to stdout.

        Args:
            data: Data to serialize as JSON.
        """
        # Use plain print to stdout for JSON mode (no Rich formatting)
        print(json.dumps(data, indent=2, default=str), file=sys.stdout)

    def success(self, message: str) -> None:
        """Display a success message in green.

        Args:
            message: The success message to display.
        """
        if self.json_mode:
            return
        # Use ASCII-safe marker on Windows legacy console
        marker = "OK:" if self._use_ascii else "✓"
        self.console.print(f"[green]{marker}[/green] {message}")

    def error(self, message: str, *, remediation: str | None = None) -> None:
        """Display an error message in red with optional remediation guidance.

        Args:
            message: The error message to display.
            remediation: Optional guidance on how to fix the issue.
        """
        if self.json_mode:
            return

        self.console.print(f"[red]Error:[/red] {message}")

        if remediation:
            self.console.print()
            self.console.print("[yellow]To fix:[/yellow]")
            self.console.print(f"  {remediation}")

    def warning(self, message: str) -> None:
        """Display a warning message in yellow.

        Args:
            message: The warning message to display.
        """
        if self.json_mode:
            return
        self.console.print(f"[yellow]Warning:[/yellow] {message}")

    def info(self, message: str) -> None:
        """Display an informational message.

        Args:
            message: The info message to display.
        """
        if self.json_mode:
            return
        self.console.print(message)

    def get_spinner_name(self) -> str:
        """Get the appropriate spinner name based on Unicode support.

        Returns:
            'line' for ASCII-only mode (Windows legacy console),
            'dots' for Unicode-capable terminals.
        """
        return "line" if self._use_ascii else "dots"

    @property
    def placeholder(self) -> str:
        """Get the appropriate placeholder for 'no value' display.

        Returns:
            '-' for ASCII-only mode, '—' (em-dash) for Unicode terminals.
        """
        return PLACEHOLDER_ASCII if self._use_ascii else PLACEHOLDER_UNICODE

    @contextmanager
    def progress(
        self,
        total: int,
        description: str = "Processing",
    ) -> Iterator[Progress]:
        """Return a Progress context manager for displaying progress bars.

        Args:
            total: Total number of items to process.
            description: Description text for the progress bar.

        Yields:
            Progress instance for tracking progress.
        """
        if self.json_mode:
            # Return a minimal progress that does nothing in JSON mode
            progress = Progress(
                console=Console(force_terminal=False, quiet=True),
                disable=True,
            )
            with progress:
                progress.add_task(description, total=total)
                yield progress
        else:
            # Use ASCII-safe spinner on Windows legacy console
            spinner_name = self.get_spinner_name()
            progress = Progress(
                SpinnerColumn(spinner_name=spinner_name),
                TextColumn("[progress.description]{task.description}"),
                BarColumn(),
                TaskProgressColumn(),
                console=self.console,
            )
            with progress:
                progress.add_task(description, total=total)
                yield progress
