"""
Module: repl.formatter
Description: Output formatting for REPL responses using rich for syntax highlighting.

Implements:
    - docs/cli/reference.md#interactive-repl
    - docs/cli/reference.md#huitzo-pack-dev

See Also:
    - docs/cli/reference.md#repl-features
"""

from __future__ import annotations

import json
from typing import Any

from rich.console import Console
from rich.syntax import Syntax
from rich.table import Table


class OutputFormatter:
    """Formats REPL output with syntax-highlighted JSON and rich tables.

    Uses the rich library to produce colorized, readable output in the terminal.
    """

    def __init__(self, console: Console | None = None) -> None:
        """Initialize the output formatter.

        Args:
            console: Rich Console instance. Creates one if not provided.
        """
        self.console = console or Console()

    def format_json(self, data: Any) -> None:
        """Print data as syntax-highlighted JSON.

        Args:
            data: Any JSON-serializable data
        """
        text = json.dumps(data, indent=2, default=str, ensure_ascii=False)
        syntax = Syntax(text, "json", theme="monokai", padding=0, word_wrap=True)
        self.console.print(syntax)

    def format_command_list(self, commands: list[dict[str, Any]]) -> None:
        """Print a table of available commands.

        Args:
            commands: List of command metadata dicts with name, namespace, description
        """
        if not commands:
            self.console.print("[yellow]No commands available.[/yellow]")
            return

        table = Table(title="Available Commands")
        table.add_column("Command", style="bold cyan")
        table.add_column("Namespace", style="green")
        table.add_column("Description")

        for cmd in commands:
            table.add_row(
                cmd.get("name", ""),
                cmd.get("namespace", ""),
                (cmd.get("description", "") or "")[:60],
            )

        self.console.print(table)

    def format_command_detail(self, cmd: dict[str, Any]) -> None:
        """Print detailed info for a single command.

        Args:
            cmd: Command metadata dict
        """
        self.console.print(f"\n[bold cyan]{cmd.get('name', 'unknown')}[/bold cyan]")
        self.console.print(f"  Namespace: [green]{cmd.get('namespace', 'N/A')}[/green]")
        self.console.print(f"  Timeout:   {cmd.get('timeout', 'default')}s")
        self.console.print(f"  Queue:     {cmd.get('queue', 'auto')}")
        if cmd.get("description"):
            self.console.print(f"  Description: {cmd['description']}")

        # Show args schema if available
        schema = cmd.get("args_schema")
        if schema:
            self.format_args_schema(schema)

        self.console.print()

    def format_args_schema(self, schema: dict[str, Any]) -> None:
        """Render argument schema as a rich table.

        Args:
            schema: JSON Schema dict from Pydantic model_json_schema()
        """
        properties = schema.get("properties", {})
        if not properties:
            return

        required_fields = set(schema.get("required", []))

        table = Table(title="Arguments")
        table.add_column("Field", style="bold cyan")
        table.add_column("Type", style="green")
        table.add_column("Required", style="yellow")
        table.add_column("Description")

        for field_name, field_info in properties.items():
            field_type = field_info.get("type", "any")
            is_required = "yes" if field_name in required_fields else "no"
            description = field_info.get("description", "")
            table.add_row(field_name, field_type, is_required, description)

        self.console.print(table)

    def format_validation_error(
        self, detail: str, args_schema: dict[str, Any] | None = None
    ) -> None:
        """Print a validation error with optional argument schema.

        Args:
            detail: Validation error detail text
            args_schema: Optional JSON Schema to display alongside the error
        """
        self.console.print("[yellow]Error: Validation failed[/yellow]")
        self.console.print(f"  {detail}")
        if args_schema:
            self.console.print()
            self.format_args_schema(args_schema)
        self.console.print(
            "\n[dim]Hint: Use 'describe <command>' to see the full argument schema.[/dim]"
        )

    def format_command_not_found(self, name: str, available: list[str] | None = None) -> None:
        """Print a command-not-found error with suggestions.

        Args:
            name: The command name that was not found
            available: List of available command names for suggestions
        """
        self.console.print(f"[cyan]Error: Command not found: {name}[/cyan]")

        # Simple substring match for suggestions
        if available:
            suggestions = [cmd for cmd in available if name in cmd or cmd in name]
            if suggestions:
                self.console.print(f"  Did you mean: {', '.join(suggestions)}?")

        self.console.print("\n[dim]Hint: Use 'list' to see available commands.[/dim]")

    def format_file_list(self, files: list[dict[str, Any]]) -> None:
        """Print a table of uploaded files.

        Args:
            files: List of file metadata dicts with name, size, path
        """
        if not files:
            self.console.print("[yellow]No files uploaded.[/yellow]")
            return

        table = Table(title="Uploaded Files")
        table.add_column("Name", style="bold cyan")
        table.add_column("Size", justify="right", style="green")
        table.add_column("Sandbox Path")

        for f in files:
            size = f.get("size", 0)
            if size >= 1024 * 1024:
                size_str = f"{size / (1024 * 1024):.1f} MB"
            elif size >= 1024:
                size_str = f"{size / 1024:.1f} KB"
            else:
                size_str = f"{size} B"
            table.add_row(
                f.get("name", ""),
                size_str,
                f.get("path", ""),
            )

        self.console.print(table)

    def format_command_error(self, error_type: str, message: str, command: str) -> None:
        """Print a structured command error with type and actionable message.

        Args:
            error_type: Exception class name (e.g. StorageError)
            message: Human-readable error message
            command: Command name that failed
        """
        self.console.print(f"[red]Error [{error_type}]: {command} — {message}[/red]")

    def format_error(self, message: str) -> None:
        """Print an error message.

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

    def format_success(self, message: str) -> None:
        """Print a success message.

        Args:
            message: Success text to display
        """
        self.console.print(f"[green]{message}[/green]")

    def format_info(self, message: str) -> None:
        """Print an informational message.

        Args:
            message: Info text to display
        """
        self.console.print(f"[dim]{message}[/dim]")
