import pytest
from unittest.mock import patch, MagicMock
from ra_aid.tools.shell import run_shell_command
from ra_aid.tools.memory import _global_memory

@pytest.fixture
def mock_console():
    with patch('ra_aid.tools.shell.console') as mock:
        yield mock

@pytest.fixture
def mock_prompt():
    with patch('ra_aid.tools.shell.Prompt') as mock:
        yield mock

@pytest.fixture
def mock_run_interactive():
    with patch('ra_aid.tools.shell.run_interactive_command') as mock:
        mock.return_value = (b"test output", 0)
        yield mock

def test_shell_command_cowboy_mode(mock_console, mock_prompt, mock_run_interactive):
    """Test shell command execution in cowboy mode (no approval)"""
    _global_memory['config'] = {'cowboy_mode': True}
    
    result = run_shell_command("echo test")
    
    assert result['success'] is True
    assert result['return_code'] == 0
    assert "test output" in result['output']
    mock_prompt.ask.assert_not_called()

def test_shell_command_cowboy_message(mock_console, mock_prompt, mock_run_interactive):
    """Test that cowboy mode displays a properly formatted cowboy message with correct spacing"""
    _global_memory['config'] = {'cowboy_mode': True}
    
    with patch('ra_aid.tools.shell.get_cowboy_message') as mock_get_message:
        mock_get_message.return_value = '🤠 Test cowboy message!'
        result = run_shell_command("echo test")
    
    assert result['success'] is True
    mock_console.print.assert_any_call("")
    mock_console.print.assert_any_call(" 🤠 Test cowboy message!")
    mock_console.print.assert_any_call("")
    mock_get_message.assert_called_once()

def test_shell_command_interactive_approved(mock_console, mock_prompt, mock_run_interactive):
    """Test shell command execution with interactive approval"""
    _global_memory['config'] = {'cowboy_mode': False}
    mock_prompt.ask.return_value = 'y'
    
    result = run_shell_command("echo test")
    
    assert result['success'] is True
    assert result['return_code'] == 0
    assert "test output" in result['output']
    mock_prompt.ask.assert_called_once_with(
        "Execute this command? (y=yes, n=no, c=enable cowboy mode for session)",
        choices=["y", "n", "c"],
        default="y",
        show_choices=True,
        show_default=True
    )

def test_shell_command_interactive_rejected(mock_console, mock_prompt, mock_run_interactive):
    """Test shell command rejection in interactive mode"""
    _global_memory['config'] = {'cowboy_mode': False}
    mock_prompt.ask.return_value = 'n'
    
    result = run_shell_command("echo test")
    
    assert result['success'] is False
    assert result['return_code'] == 1
    assert "cancelled by user" in result['output']
    mock_prompt.ask.assert_called_once_with(
        "Execute this command? (y=yes, n=no, c=enable cowboy mode for session)",
        choices=["y", "n", "c"],
        default="y",
        show_choices=True,
        show_default=True
    )
    mock_run_interactive.assert_not_called()

def test_shell_command_execution_error(mock_console, mock_prompt, mock_run_interactive):
    """Test handling of shell command execution errors"""
    _global_memory['config'] = {'cowboy_mode': True}
    mock_run_interactive.side_effect = Exception("Command failed")
    
    result = run_shell_command("invalid command")
    
    assert result['success'] is False
    assert result['return_code'] == 1
    assert "Command failed" in result['output']
