"""Test output rendering, NO_COLOR, quiet mode, and stream renderer."""

import json
import os
import sys
from io import StringIO
from unittest.mock import patch

import pytest
from rich.console import Console
from mcp.types import CallToolResult, TextContent, ImageContent

from mcpbundles.output import (
    render_call_result,
    render_error,
    render_success,
    render_warning,
    print_json,
    _render_stream_text,
    _content_to_dict,
    set_quiet,
    is_tty,
)


def _capture_rich_output(fn, *args, **kwargs):
    """Capture output from Rich consoles by temporarily replacing them."""
    import mcpbundles.output as m
    out_buf = StringIO()
    err_buf = StringIO()
    orig_stdout = m.stdout_console
    orig_stderr = m.console
    m.stdout_console = Console(file=out_buf, no_color=True)
    m.console = Console(file=err_buf, no_color=True)
    try:
        fn(*args, **kwargs)
    finally:
        m.stdout_console = orig_stdout
        m.console = orig_stderr
    return out_buf.getvalue(), err_buf.getvalue()


class TestRenderCallResult:
    def _make_result(self, text: str, is_error: bool = False) -> CallToolResult:
        return CallToolResult(
            content=[TextContent(type="text", text=text)],
            isError=is_error,
        )

    def test_json_mode_valid_json(self, capsys):
        result = self._make_result('{"key": "value"}')
        render_call_result(result, mode="json")
        out = capsys.readouterr().out
        parsed = json.loads(out)
        assert parsed == {"key": "value"}

    def test_json_mode_plain_text(self, capsys):
        result = self._make_result("just text")
        render_call_result(result, mode="json")
        out = capsys.readouterr().out
        assert "just text" in out

    def test_raw_mode(self, capsys):
        result = self._make_result("hello")
        render_call_result(result, mode="raw")
        out = capsys.readouterr().out
        parsed = json.loads(out)
        assert parsed["content"][0]["type"] == "text"
        assert parsed["content"][0]["text"] == "hello"
        assert parsed["isError"] is False

    def test_image_content_json(self, capsys):
        result = CallToolResult(
            content=[ImageContent(type="image", data="base64data", mimeType="image/png")],
            isError=False,
        )
        render_call_result(result, mode="json")
        out = capsys.readouterr().out
        parsed = json.loads(out)
        assert parsed["type"] == "image"
        assert parsed["data_length"] == 10

    def test_stream_mode_delegates(self):
        result = self._make_result('{"stdout": "hello\\n", "result": 42}')
        out, _ = _capture_rich_output(render_call_result, result, mode="stream")
        assert "hello" in out
        assert "42" in out


class TestStreamRenderer:
    def test_json_with_stdout(self):
        out, _ = _capture_rich_output(_render_stream_text, json.dumps({"stdout": "line1\nline2\n"}))
        assert "line1" in out
        assert "line2" in out

    def test_json_with_result(self):
        out, _ = _capture_rich_output(_render_stream_text, json.dumps({"result": "done"}))
        assert "done" in out
        assert "→" in out

    def test_json_with_stderr(self):
        _, err = _capture_rich_output(_render_stream_text, json.dumps({"stderr": "warning\n"}))
        assert "warning" in err

    def test_plain_text(self):
        out, _ = _capture_rich_output(_render_stream_text, "line1\nline2\nline3")
        assert "line1" in out
        assert "line2" in out
        assert "line3" in out

    def test_empty_stdout(self):
        out, _ = _capture_rich_output(_render_stream_text, json.dumps({"stdout": "", "result": None}))
        assert "│" not in out


class TestContentToDict:
    def test_text_content(self):
        d = _content_to_dict(TextContent(type="text", text="hello"))
        assert d == {"type": "text", "text": "hello"}

    def test_image_content_truncated(self):
        d = _content_to_dict(ImageContent(type="image", data="x" * 100, mimeType="image/png"))
        assert d["type"] == "image"
        assert d["data"].endswith("...")
        assert len(d["data"]) < 100

    def test_unknown_content(self):
        d = _content_to_dict("something else")
        assert d == {"type": "unknown"}


class TestPrintJson:
    def test_dict(self, capsys):
        print_json({"a": 1})
        out = capsys.readouterr().out
        assert json.loads(out) == {"a": 1}

    def test_json_string(self, capsys):
        print_json('{"a": 1}')
        out = capsys.readouterr().out
        assert json.loads(out) == {"a": 1}

    def test_plain_string(self, capsys):
        print_json("not json")
        out = capsys.readouterr().out
        assert "not json" in out


class TestQuietMode:
    def test_set_quiet(self):
        import mcpbundles.output as m
        original = m._quiet
        set_quiet(True)
        assert m._quiet is True
        set_quiet(False)
        assert m._quiet is False
        set_quiet(original)
