"""Tests for CLI output formatter (cli_output.py)."""

import json
import os
from unittest.mock import patch

from autodebug.cli_output import OutputFormatter, _NoOpProgress, _NoOpStatus


class TestOutputFormatterInit:
    """Test OutputFormatter initialization."""

    def test_default_init(self):
        fmt = OutputFormatter()
        assert fmt.json_mode is False
        assert fmt._json_buffer == []

    def test_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        assert fmt.json_mode is True
        # Console should be quiet in JSON mode
        assert fmt.console.quiet is True

    def test_no_color_mode(self):
        fmt = OutputFormatter(no_color=True)
        assert fmt.console.no_color is True

    def test_no_color_env_var(self):
        with patch.dict(os.environ, {"NO_COLOR": "1"}):
            fmt = OutputFormatter()
            assert fmt.console.no_color is True


class TestOutputFormatterMessages:
    """Test message output methods."""

    def test_success_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.success("All good")
        assert len(fmt._json_buffer) == 1
        assert fmt._json_buffer[0] == {"type": "success", "message": "All good"}

    def test_error_json_mode(self, capsys):
        fmt = OutputFormatter(json_mode=True)
        fmt.error("Something broke", "Try fixing it")
        # error() auto-flushes in json_mode, so buffer is empty
        assert len(fmt._json_buffer) == 0
        captured = capsys.readouterr()
        import json
        output = json.loads(captured.out)
        assert output == [{"type": "error", "message": "Something broke", "detail": "Try fixing it"}]

    def test_error_json_mode_no_detail(self, capsys):
        fmt = OutputFormatter(json_mode=True)
        fmt.error("Oops")
        assert len(fmt._json_buffer) == 0
        captured = capsys.readouterr()
        import json
        output = json.loads(captured.out)
        assert output == [{"type": "error", "message": "Oops"}]

    def test_warning_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.warning("Careful")
        assert fmt._json_buffer[0] == {"type": "warning", "message": "Careful"}

    def test_info_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.info("FYI")
        assert fmt._json_buffer[0] == {"type": "info", "message": "FYI"}

    def test_dim_json_mode_is_noop(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.dim("This is dim text")
        assert len(fmt._json_buffer) == 0

    def test_success_rich_mode(self, capsys):
        fmt = OutputFormatter(no_color=True)
        fmt.success("Done!")
        # Rich outputs to its own console, not captured by capsys
        # Just verify no exceptions raised and no JSON buffer
        assert len(fmt._json_buffer) == 0

    def test_error_rich_mode(self, capsys):
        fmt = OutputFormatter(no_color=True)
        fmt.error("Failed", "Try again")
        assert len(fmt._json_buffer) == 0


class TestOutputFormatterTable:
    """Test table output."""

    def test_table_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        columns = [
            {"name": "Name", "style": "cyan"},
            {"name": "Value", "justify": "right"},
        ]
        rows = [["foo", "bar"], ["baz", "qux"]]
        fmt.table("My Table", columns, rows)

        assert len(fmt._json_buffer) == 1
        entry = fmt._json_buffer[0]
        assert entry["type"] == "table"
        assert entry["title"] == "My Table"
        assert entry["columns"] == ["Name", "Value"]
        assert entry["rows"] == [
            {"Name": "foo", "Value": "bar"},
            {"Name": "baz", "Value": "qux"},
        ]

    def test_table_rich_mode(self):
        fmt = OutputFormatter(no_color=True)
        columns = [{"name": "Col1"}, {"name": "Col2"}]
        rows = [["a", "b"]]
        # Should not raise
        fmt.table("Test", columns, rows)
        assert len(fmt._json_buffer) == 0


class TestOutputFormatterPanel:
    """Test panel output."""

    def test_panel_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.panel("Hello world", title="Greeting", border_style="green")
        assert len(fmt._json_buffer) == 1
        assert fmt._json_buffer[0] == {
            "type": "panel",
            "title": "Greeting",
            "content": "Hello world",
        }

    def test_panel_rich_mode(self):
        fmt = OutputFormatter(no_color=True)
        fmt.panel("Content here", title="Title")
        assert len(fmt._json_buffer) == 0


class TestOutputFormatterJSON:
    """Test JSON output and flushing."""

    def test_json_out_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        fmt.json_out({"key": "value"})
        assert len(fmt._json_buffer) == 1
        assert fmt._json_buffer[0] == {"type": "data", "data": {"key": "value"}}

    def test_flush_json_single_data(self, capsys):
        fmt = OutputFormatter(json_mode=True)
        fmt.json_out({"status": "ok"})
        fmt.flush_json()
        captured = capsys.readouterr()
        parsed = json.loads(captured.out)
        assert parsed == {"status": "ok"}
        assert fmt._json_buffer == []

    def test_flush_json_multiple_entries(self, capsys):
        fmt = OutputFormatter(json_mode=True)
        fmt.success("Step 1")
        fmt.success("Step 2")
        fmt.flush_json()
        captured = capsys.readouterr()
        parsed = json.loads(captured.out)
        assert len(parsed) == 2
        assert parsed[0]["type"] == "success"
        assert parsed[1]["type"] == "success"

    def test_flush_json_empty_noop(self, capsys):
        fmt = OutputFormatter(json_mode=True)
        fmt.flush_json()
        captured = capsys.readouterr()
        assert captured.out == ""

    def test_json_out_rich_mode(self):
        fmt = OutputFormatter(no_color=True)
        # Should not raise in Rich mode
        fmt.json_out({"key": "value"})
        assert len(fmt._json_buffer) == 0


class TestProgressHelpers:
    """Test progress spinner and bar in JSON mode (no-op)."""

    def test_spinner_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        with fmt.progress_spinner("Working...") as status:
            assert isinstance(status, _NoOpStatus)
            status.update("Still working...")  # Should not raise

    def test_progress_bar_json_mode(self):
        fmt = OutputFormatter(json_mode=True)
        with fmt.progress_bar("Processing", total=10) as progress:
            assert isinstance(progress, _NoOpProgress)
            progress.advance(1)  # Should not raise
            progress.update("New description")  # Should not raise


class TestNoOpClasses:
    """Test no-op helper classes."""

    def test_noop_status_update(self):
        status = _NoOpStatus()
        status.update("anything")  # Should be no-op

    def test_noop_progress_advance(self):
        progress = _NoOpProgress()
        progress.advance(5)  # Should be no-op

    def test_noop_progress_update(self):
        progress = _NoOpProgress()
        progress.update("anything")  # Should be no-op
