"""Tests for output formatters."""

import json

from terminaluse.lib.utils.output import (
    FilterPipeline,
    ToolOutputFormatter,
    ToolRequestFormatter,
)


class TestToolRequestFormatter:
    """Tests for ToolRequestFormatter."""

    def test_formats_simple_request(self) -> None:
        """Formats a simple tool request."""
        formatter = ToolRequestFormatter()

        result = formatter.format("read_file", '{"path": "/foo/bar.txt"}')

        assert "[read_file]" in result
        assert "path:" in result
        assert "/foo/bar.txt" in result

    def test_task_tool_uses_default_format(self) -> None:
        """Task tool uses default formatting (no special treatment)."""
        formatter = ToolRequestFormatter()

        result = formatter.format(
            "Task",
            json.dumps(
                {
                    "subagent_type": "Explore",
                    "description": "Search for auth patterns",
                    "name": "auth-explorer",
                }
            ),
        )

        # Uses standard tool formatting
        assert "[Task]" in result
        assert "subagent_type:" in result
        assert "Explore" in result

    def test_task_tool_with_custom_handler(self) -> None:
        """Task tool can use custom handler when registered."""
        from terminaluse.lib.utils.output import TaskRequestHandler

        formatter = ToolRequestFormatter(request_handlers={"Task": TaskRequestHandler()})

        result = formatter.format(
            "Task",
            json.dumps(
                {
                    "subagent_type": "Explore",
                    "description": "Search for auth patterns",
                    "name": "auth-explorer",
                }
            ),
        )

        # Uses special subagent formatting
        assert "🤖" in result
        assert "[Explore]" in result
        assert "auth-explorer" in result

    def test_truncates_long_values(self) -> None:
        """Truncates long values in non-verbose mode."""
        formatter = ToolRequestFormatter(verbose=False, max_value_length=20)

        long_value = "x" * 50
        result = formatter.format("test", json.dumps({"key": long_value}))

        assert "..." in result
        assert long_value not in result

    def test_verbose_shows_full_values(self) -> None:
        """Verbose mode shows full values."""
        formatter = ToolRequestFormatter(verbose=True)

        long_value = "x" * 100
        result = formatter.format("test", json.dumps({"key": long_value}))

        assert long_value in result
        assert "..." not in result

    def test_multiline_values_collapsed(self) -> None:
        """Multiline values are collapsed to single line in non-verbose."""
        formatter = ToolRequestFormatter(verbose=False)

        result = formatter.format("test", json.dumps({"key": "line1\nline2\nline3"}))

        assert "\n" not in result.split("\n")[-1] or "line1 line2" in result

    def test_multiline_values_preserved_verbose(self) -> None:
        """Multiline values preserved in verbose mode."""
        formatter = ToolRequestFormatter(verbose=True)

        result = formatter.format("test", json.dumps({"code": "line1\nline2\nline3"}))

        assert "line1" in result
        assert "line2" in result
        assert "line3" in result

    def test_handles_invalid_json(self) -> None:
        """Handles invalid JSON gracefully."""
        formatter = ToolRequestFormatter()

        result = formatter.format("test", "not valid json")

        assert "not valid json" in result

    def test_non_string_values(self) -> None:
        """Handles non-string values (numbers, booleans, objects)."""
        formatter = ToolRequestFormatter()

        result = formatter.format("test", json.dumps({"count": 42, "enabled": True, "config": {"a": 1}}))

        assert "42" in result
        assert "true" in result.lower()
        assert '"a"' in result or "'a'" in result


class TestToolOutputFormatter:
    """Tests for ToolOutputFormatter."""

    def test_formats_simple_output(self) -> None:
        """Formats a simple string output."""
        formatter = ToolOutputFormatter()

        result = formatter.format("Hello World")

        assert "'-->" in result
        assert "Hello World" in result

    def test_formats_none_as_empty(self) -> None:
        """None output shows empty marker."""
        formatter = ToolOutputFormatter()

        result = formatter.format(None)

        assert "(empty)" in result

    def test_truncates_long_output(self) -> None:
        """Truncates output beyond max_lines."""
        formatter = ToolOutputFormatter(max_lines=3, verbose=False)

        lines = "\n".join([f"line{i}" for i in range(10)])
        result = formatter.format(lines)

        assert "line0" in result
        assert "line1" in result
        assert "line2" in result
        assert "more lines" in result
        assert "line9" not in result

    def test_verbose_shows_all_lines(self) -> None:
        """Verbose mode shows all lines."""
        formatter = ToolOutputFormatter(max_lines=3, verbose=True)

        lines = "\n".join([f"line{i}" for i in range(10)])
        result = formatter.format(lines)

        assert "line0" in result
        assert "line9" in result
        assert "more lines" not in result

    def test_extracts_text_from_list(self) -> None:
        """Extracts text from list of parts."""
        formatter = ToolOutputFormatter()

        output = [
            {"type": "text", "text": "Hello"},
            {"type": "text", "text": "World"},
        ]
        result = formatter.format(output)

        assert "Hello" in result
        assert "World" in result

    def test_filters_metadata(self) -> None:
        """Filters out metadata lines."""
        formatter = ToolOutputFormatter()

        output = "Content here\nagentId: abc123\nMore content"
        result = formatter.format(output)

        assert "Content here" in result
        assert "agentId:" not in result
        assert "More content" in result

    def test_filters_usage_blocks(self) -> None:
        """Filters out <usage> blocks."""
        formatter = ToolOutputFormatter()

        output = "Content\n<usage>total_tokens: 100</usage>\nMore"
        result = formatter.format(output)

        assert "Content" in result
        assert "total_tokens" not in result
        assert "More" in result

    def test_filters_system_reminder(self) -> None:
        """Filters out <system-reminder> blocks."""
        formatter = ToolOutputFormatter()

        output = "Before\n<system-reminder>hidden</system-reminder>\nAfter"
        result = formatter.format(output)

        assert "Before" in result
        assert "hidden" not in result
        assert "After" in result

    def test_custom_filter_pipeline(self) -> None:
        """Can use custom filter pipeline."""
        # Empty pipeline - no filtering
        formatter = ToolOutputFormatter(filter_pipeline=FilterPipeline([]))

        output = "agentId: should-remain"
        result = formatter.format(output)

        assert "agentId:" in result

    def test_strips_line_number_prefixes(self) -> None:
        """Strips line number prefixes from file read output."""
        formatter = ToolOutputFormatter()

        output = "  42→content here\n  43→more content"
        result = formatter.format(output)

        assert "42→" not in result
        assert "content here" in result

    def test_cleans_whitespace(self) -> None:
        """Cleans up leading/trailing whitespace."""
        formatter = ToolOutputFormatter()

        output = "\n\n  content  \n\n"
        result = formatter.format(output)

        # Should have content but cleaned up
        assert "content" in result

    def test_single_line_formatting(self) -> None:
        """Single line output formatted differently."""
        formatter = ToolOutputFormatter()

        result = formatter.format("single line")

        # Single line should have the arrow on same line as content
        assert "'--> single line" in result

    def test_real_world_agent_output(self) -> None:
        """Tests with real-world agent output format."""
        output = [
            {
                "type": "text",
                "text": "Hey there! Welcome to Claude Code!\n\nI'm here to help.",
            },
            {
                "type": "text",
                "text": "agentId: a280d3b (for resuming to continue this agent's work if needed)\n<usage>total_tokens: 11428\ntool_uses: 0\nduration_ms: 2663</usage>",
            },
        ]

        formatter = ToolOutputFormatter()
        result = formatter.format(output)

        # Content should be present
        assert "Hey there!" in result
        assert "Welcome to Claude Code" in result

        # Metadata should be filtered
        assert "agentId:" not in result
        assert "total_tokens" not in result
        assert "tool_uses" not in result
        assert "duration_ms" not in result

    def test_task_tool_output_uses_default_format(self) -> None:
        """Task tool output uses default formatting (no special treatment)."""
        formatter = ToolOutputFormatter()

        result = formatter.format("Found 5 matching files", tool_name="Task")

        # Uses standard arrow prefix
        assert "'-->" in result
        assert "Found 5 matching files" in result

    def test_task_tool_output_with_custom_handler(self) -> None:
        """Task tool output can use custom handler when registered."""
        from terminaluse.lib.utils.output import TaskOutputHandler

        formatter = ToolOutputFormatter()
        formatter.output_handlers["Task"] = TaskOutputHandler()

        result = formatter.format("Found 5 matching files", tool_name="Task")

        # Uses special tree-style prefix
        assert "└─" in result
        assert "Found 5 matching files" in result

    def test_tool_name_none_uses_default(self) -> None:
        """tool_name=None uses default formatting."""
        formatter = ToolOutputFormatter()

        result = formatter.format("some output", tool_name=None)

        # Should use default green arrow
        assert "'-->" in result
        assert "some output" in result

    def test_unknown_tool_uses_default(self) -> None:
        """Unknown tool name uses default formatting."""
        formatter = ToolOutputFormatter()

        result = formatter.format("output", tool_name="UnknownTool")

        # Should use default green arrow
        assert "'-->" in result
