"""T-04: CLI entry point tests — argument parsing, error output, exit codes."""
import sys
from unittest.mock import MagicMock, patch

import pytest

from horn.cli import main


class TestNormalExitCodes:
    def test_bare_command_exits_zero(self):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 0

    def test_start_exits_zero(self):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn", "--start"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 0

    def test_done_exits_zero(self):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn", "--done"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 0

    def test_confirm_exits_zero(self):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn", "--confirm"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 0


class TestErrorExitCodes:
    def test_unknown_arg_exits_one(self, capsys):
        with patch("sys.argv", ["horn", "--xxx"]), patch("horn.cli.TTSEngine"):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 1

    def test_multiple_types_exits_one(self, capsys):
        with patch("sys.argv", ["horn", "--start", "--done"]), patch("horn.cli.TTSEngine"):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 1

    def test_tts_unavailable_exits_one(self, capsys):
        from horn.tts.base import TTSUnavailableError
        mock_tts = MagicMock()
        mock_tts.speak.side_effect = TTSUnavailableError("SAPI")
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 1

    def test_tts_timeout_exits_one(self):
        from horn.tts.base import TTSTimeoutError
        mock_tts = MagicMock()
        mock_tts.speak.side_effect = TTSTimeoutError("timeout")
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit) as exc_info:
                main()
        assert exc_info.value.code == 1


class TestStderrMessages:
    def test_unknown_arg_outputs_to_stderr(self, capsys):
        with patch("sys.argv", ["horn", "--xxx"]), patch("horn.cli.TTSEngine"):
            with pytest.raises(SystemExit):
                main()
        captured = capsys.readouterr()
        assert "[Horn]" in captured.err
        assert captured.out == ""

    def test_multiple_types_outputs_to_stderr(self, capsys):
        with patch("sys.argv", ["horn", "--start", "--done"]), patch("horn.cli.TTSEngine"):
            with pytest.raises(SystemExit):
                main()
        captured = capsys.readouterr()
        assert "[Horn]" in captured.err
        assert "多个通知类型" in captured.err
        assert captured.out == ""

    def test_tts_unavailable_outputs_to_stderr(self, capsys):
        from horn.tts.base import TTSUnavailableError
        mock_tts = MagicMock()
        mock_tts.speak.side_effect = TTSUnavailableError("SAPI")
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit):
                main()
        captured = capsys.readouterr()
        assert "[Horn]" in captured.err
        assert captured.out == ""

    def test_tts_timeout_outputs_to_stderr(self, capsys):
        from horn.tts.base import TTSTimeoutError
        mock_tts = MagicMock()
        mock_tts.speak.side_effect = TTSTimeoutError("timeout")
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit):
                main()
        captured = capsys.readouterr()
        assert "[Horn]" in captured.err
        assert captured.out == ""


class TestNoStdout:
    """Successful runs must produce no stdout output."""

    def test_bare_command_no_stdout(self, capsys):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit):
                main()
        assert capsys.readouterr().out == ""

    def test_start_no_stdout(self, capsys):
        mock_tts = MagicMock()
        with patch("sys.argv", ["horn", "--start"]), patch(
            "horn.cli.TTSEngine", return_value=mock_tts
        ):
            with pytest.raises(SystemExit):
                main()
        assert capsys.readouterr().out == ""
