"""Unified output system for the MCPBundles CLI.

Modes:
  - pretty: Rich tables, panels, syntax highlighting (default for discovery)
  - json: Raw JSON to stdout, pipe-friendly (default for execution)
  - raw: Full MCP response envelope (for debugging)

Respects NO_COLOR (https://no-color.org/) and --quiet mode.
"""

import json
import os
import sys
from typing import Any

from rich.console import Console
from rich.panel import Panel
from rich.syntax import Syntax
from rich.table import Table
from rich.text import Text
from mcp.types import CallToolResult, TextContent, ImageContent

_no_color = "NO_COLOR" in os.environ

console = Console(stderr=True, no_color=_no_color)
stdout_console = Console(file=sys.stdout, no_color=_no_color)

_quiet = False


def set_quiet(enabled: bool) -> None:
    global _quiet
    _quiet = enabled


def is_tty() -> bool:
    return sys.stdout.isatty()


def print_json(data: Any) -> None:
    if isinstance(data, str):
        try:
            parsed = json.loads(data)
            print(json.dumps(parsed, indent=2))
        except json.JSONDecodeError:
            print(data)
    else:
        print(json.dumps(data, indent=2, default=str))


def print_raw(data: Any) -> None:
    print(json.dumps(data, indent=2, default=str))


def render_tools_table(tools: list, filter_str: str | None = None) -> None:
    if filter_str:
        lower = filter_str.lower()
        tools = [t for t in tools if lower in t.name.lower() or (t.description and lower in t.description.lower())]

    table = Table(show_header=True, header_style="bold", box=None, pad_edge=False)
    table.add_column("Name", style="cyan", no_wrap=True)
    table.add_column("Description", style="dim")

    for tool in sorted(tools, key=lambda t: t.name):
        desc = (tool.description or "")[:80]
        table.add_row(tool.name, desc)

    panel = Panel(
        table,
        title=f"MCP Tools ({len(tools)} available)",
        border_style="blue",
        padding=(1, 2),
    )
    stdout_console.print(panel)
    stdout_console.print()
    stdout_console.print("  Use [cyan]mcpbundles tools <name>[/] for full schema", highlight=False)
    stdout_console.print("  Use [cyan]mcpbundles call <name> ...[/] to execute", highlight=False)


def render_tools_json(tools: list) -> None:
    data = [{"name": t.name, "description": t.description, "inputSchema": t.inputSchema} for t in tools]
    print_json(data)


def render_resources_table(resources: list) -> None:
    table = Table(show_header=True, header_style="bold", box=None, pad_edge=False)
    table.add_column("URI", style="cyan", no_wrap=True)
    table.add_column("Name", style="white")
    table.add_column("MIME Type", style="dim")

    for r in resources:
        table.add_row(str(r.uri), r.name or "", r.mimeType or "")

    panel = Panel(
        table,
        title=f"MCP Resources ({len(resources)} available)",
        border_style="blue",
        padding=(1, 2),
    )
    stdout_console.print(panel)
    stdout_console.print()
    stdout_console.print("  Use [cyan]mcpbundles read <uri>[/] to fetch", highlight=False)


def render_resources_json(resources: list) -> None:
    data = [{"uri": str(r.uri), "name": r.name, "description": r.description, "mimeType": r.mimeType} for r in resources]
    print_json(data)


def render_prompts_table(prompts: list) -> None:
    if not prompts:
        stdout_console.print(Panel("No prompts currently registered.", title="MCP Prompts (0 available)", border_style="blue", padding=(1, 2)))
        return

    table = Table(show_header=True, header_style="bold", box=None, pad_edge=False)
    table.add_column("Name", style="cyan", no_wrap=True)
    table.add_column("Description", style="dim")

    for p in prompts:
        table.add_row(p.name, (p.description or "")[:80])

    panel = Panel(
        table,
        title=f"MCP Prompts ({len(prompts)} available)",
        border_style="blue",
        padding=(1, 2),
    )
    stdout_console.print(panel)


def render_prompts_json(prompts: list) -> None:
    data = [{"name": p.name, "description": p.description, "arguments": [{"name": a.name, "description": a.description, "required": a.required} for a in (p.arguments or [])]} for p in prompts]
    print_json(data)


def render_call_result(result: CallToolResult, mode: str = "json") -> None:
    if mode == "raw":
        print_raw({"content": [_content_to_dict(c) for c in result.content], "isError": result.isError})
        return

    for block in result.content:
        if isinstance(block, TextContent):
            text = block.text
            if mode == "json":
                try:
                    parsed = json.loads(text)
                    print(json.dumps(parsed, indent=2))
                except json.JSONDecodeError:
                    print(text)
            elif mode == "stream":
                _render_stream_text(text)
            else:
                try:
                    parsed = json.loads(text)
                    syntax = Syntax(json.dumps(parsed, indent=2), "json", theme="monokai")
                    stdout_console.print(syntax)
                except json.JSONDecodeError:
                    stdout_console.print(text)
        elif isinstance(block, ImageContent):
            if mode == "json":
                print_json({"type": "image", "mimeType": block.mimeType, "data_length": len(block.data)})
            else:
                stdout_console.print(f"[dim]Image ({block.mimeType}, {len(block.data)} bytes)[/]")


def _render_stream_text(text: str) -> None:
    """Render text in streaming style — line by line with a gutter."""
    try:
        parsed = json.loads(text)
        if isinstance(parsed, dict):
            stdout_output = parsed.get("stdout", "")
            stderr_output = parsed.get("stderr", "")
            if stdout_output:
                for line in stdout_output.rstrip("\n").split("\n"):
                    stdout_console.print(f"  [dim]│[/] {line}")
            if stderr_output:
                for line in stderr_output.rstrip("\n").split("\n"):
                    console.print(f"  [dim]│[/] [yellow]{line}[/]")
            result_val = parsed.get("result")
            if result_val is not None:
                stdout_console.print(f"\n  [green]→[/] {result_val}")
            return
    except json.JSONDecodeError:
        pass
    for line in text.rstrip("\n").split("\n"):
        stdout_console.print(f"  [dim]│[/] {line}")


def render_error(message: str) -> None:
    console.print(f"[red]Error:[/] {message}")


def render_success(message: str) -> None:
    console.print(f"[green]✓[/] {message}")


def render_warning(message: str) -> None:
    console.print(f"[yellow]⚠[/]  {message}")


def _content_to_dict(content: Any) -> dict:
    if isinstance(content, TextContent):
        return {"type": "text", "text": content.text}
    if isinstance(content, ImageContent):
        return {"type": "image", "mimeType": content.mimeType, "data": content.data[:50] + "..."}
    return {"type": "unknown"}
