"""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 mcpbundles.mcp_client 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)
