"""Tests for command-line interface."""

import sys
from io import StringIO
from unittest.mock import Mock, patch

import pytest

from agentcenter.cli import main


def test_main_with_message():
    """Test main with a single message."""
    with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
        exit_code = main(["Test message"])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Processed: Test message" in output


def test_main_with_message_and_name():
    """Test main with custom agent name."""
    with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
        exit_code = main(["--name", "CustomAgent", "Hello"])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Processed: Hello" in output


def test_main_with_debug_flag():
    """Test main with debug flag."""
    with patch("sys.stdout", new_callable=StringIO):
        with patch("agentcenter.cli.setup_logging") as mock_setup:
            exit_code = main(["--debug", "Test"])

    assert exit_code == 0
    mock_setup.assert_called_once_with("DEBUG")


def test_main_without_debug_flag():
    """Test main without debug flag."""
    with patch("sys.stdout", new_callable=StringIO):
        with patch("agentcenter.cli.setup_logging") as mock_setup:
            with patch("agentcenter.cli.get_settings") as mock_settings:
                mock_settings.return_value.log_level = "INFO"
                exit_code = main(["Test"])

    assert exit_code == 0
    mock_setup.assert_called_once_with("INFO")


def test_main_version():
    """Test --version flag."""
    with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
        with pytest.raises(SystemExit) as exc_info:
            main(["--version"])

    assert exc_info.value.code == 0


def test_main_interactive_quit():
    """Test interactive mode with quit command."""
    user_inputs = ["quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Welcome to AgentCenter!" in output
    assert "Goodbye!" in output


def test_main_interactive_exit():
    """Test interactive mode with exit command."""
    user_inputs = ["exit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Goodbye!" in output


def test_main_interactive_q():
    """Test interactive mode with 'q' command."""
    user_inputs = ["q"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Goodbye!" in output


def test_main_interactive_with_messages():
    """Test interactive mode with actual messages."""
    user_inputs = ["Hello agent", "How are you?", "quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Processed: Hello agent" in output
    assert "Processed: How are you?" in output


def test_main_interactive_keyboard_interrupt():
    """Test interactive mode with KeyboardInterrupt."""
    with patch("builtins.input", side_effect=KeyboardInterrupt()):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Goodbye!" in output


def test_main_interactive_exception():
    """Test interactive mode with exception during processing."""

    def raise_exception(*args, **kwargs):
        raise ValueError("Test error")

    user_inputs = ["test message"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("agentcenter.cli.AgentCenter") as mock_agent_class:
            mock_agent = Mock()
            mock_agent.name = "AgentCenter"
            mock_agent.process = raise_exception
            mock_agent_class.return_value = mock_agent

            with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
                exit_code = main([])

    assert exit_code == 1
    output = mock_stdout.getvalue()
    assert "Error: Test error" in output


def test_main_custom_agent_name():
    """Test main with custom agent name in interactive mode."""
    user_inputs = ["quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main(["--name", "MyCustomAgent"])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Welcome to MyCustomAgent!" in output


def test_main_help():
    """Test --help flag."""
    with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
        with pytest.raises(SystemExit) as exc_info:
            main(["--help"])

    assert exc_info.value.code == 0
    output = mock_stdout.getvalue()
    assert "Agent Center" in output or "usage:" in output


def test_main_with_empty_args():
    """Test main with empty args list."""
    user_inputs = ["quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO):
            exit_code = main([])

    assert exit_code == 0


def test_main_with_none_args():
    """Test main with None args (uses sys.argv)."""
    user_inputs = ["quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO):
            with patch.object(sys, "argv", ["agentcenter"]):
                exit_code = main(None)

    assert exit_code == 0


def test_main_single_message_short_name():
    """Test main with short name flag."""
    with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
        exit_code = main(["-n", "ShortNameAgent", "Test message"])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Processed: Test message" in output


def test_main_interactive_case_insensitive_quit():
    """Test that quit commands are case insensitive."""
    test_cases = ["QUIT", "Quit", "EXIT", "Exit", "Q"]

    for quit_cmd in test_cases:
        with patch("builtins.input", side_effect=[quit_cmd]):
            with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
                exit_code = main([])

        assert exit_code == 0
        output = mock_stdout.getvalue()
        assert "Goodbye!" in output


def test_main_interactive_multiple_messages_before_quit():
    """Test multiple messages in interactive mode."""
    user_inputs = ["Message 1", "Message 2", "Message 3", "quit"]

    with patch("builtins.input", side_effect=user_inputs):
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            exit_code = main([])

    assert exit_code == 0
    output = mock_stdout.getvalue()
    assert "Processed: Message 1" in output
    assert "Processed: Message 2" in output
    assert "Processed: Message 3" in output


def test_main_uses_settings_log_level():
    """Test that main uses log level from settings when debug is False."""
    with patch("sys.stdout", new_callable=StringIO):
        with patch("agentcenter.cli.get_settings") as mock_get_settings:
            with patch("agentcenter.cli.setup_logging") as mock_setup_logging:
                mock_settings = Mock()
                mock_settings.log_level = "WARNING"
                mock_get_settings.return_value = mock_settings

                exit_code = main(["test"])

    assert exit_code == 0
    mock_setup_logging.assert_called_once_with("WARNING")


def test_main_debug_overrides_settings_log_level():
    """Test that --debug flag overrides settings log level."""
    with patch("sys.stdout", new_callable=StringIO):
        with patch("agentcenter.cli.get_settings") as mock_get_settings:
            with patch("agentcenter.cli.setup_logging") as mock_setup_logging:
                mock_settings = Mock()
                mock_settings.log_level = "INFO"
                mock_get_settings.return_value = mock_settings

                exit_code = main(["--debug", "test"])

    assert exit_code == 0
    mock_setup_logging.assert_called_once_with("DEBUG")
