"""Test service manager functionality."""

import pytest
import asyncio
from unittest.mock import Mock, patch, AsyncMock, MagicMock
from mcpbundles.service_manager import ServiceManager


@pytest.mark.asyncio
async def test_discover_services_success():
    """Test successful service discovery."""
    manager = ServiceManager()
    
    # Mock successful connections
    with patch('asyncio.open_connection') as mock_connect:
        mock_reader = AsyncMock()
        mock_writer = AsyncMock()
        mock_writer.close = Mock()  # close() is NOT async
        mock_writer.wait_closed = AsyncMock()  # wait_closed() IS async
        mock_connect.return_value = (mock_reader, mock_writer)
        
        result = await manager.discover_services([5432, 6379])
        
        assert '5432' in result
        assert '6379' in result
        assert result['5432']['available'] is True


@pytest.mark.asyncio
async def test_discover_services_some_unavailable():
    """Test discovery with some services unavailable."""
    manager = ServiceManager()
    
    async def mock_connection(host, port):
        if port == 5432:
            # Simulate successful connection
            reader = AsyncMock()
            writer = AsyncMock()
            writer.close = Mock()  # close() is NOT async
            writer.wait_closed = AsyncMock()  # wait_closed() IS async
            return (reader, writer)
        else:
            # Simulate connection refused
            raise ConnectionRefusedError()
    
    with patch('asyncio.open_connection', side_effect=mock_connection):
        result = await manager.discover_services([5432, 6379])
        
        assert result['5432']['available'] is True
        assert result['6379']['available'] is False


@pytest.mark.asyncio
async def test_verify_service_success():
    """Test successful service verification."""
    manager = ServiceManager()
    
    with patch('asyncio.open_connection') as mock_connect:
        mock_reader = AsyncMock()
        mock_writer = AsyncMock()
        mock_writer.close = Mock()  # close() is NOT async
        mock_writer.wait_closed = AsyncMock()  # wait_closed() IS async
        mock_connect.return_value = (mock_reader, mock_writer)
        
        result = await manager.verify_service('localhost:5432')
        
        assert result['verified'] is True
        assert result['target'] == 'localhost:5432'


@pytest.mark.asyncio
async def test_verify_service_connection_refused():
    """Test verification with connection refused."""
    manager = ServiceManager()
    
    with patch('asyncio.open_connection', side_effect=ConnectionRefusedError()):
        result = await manager.verify_service('localhost:5432')
        
        assert result['verified'] is False
        assert 'Connection refused' in result['error']


@pytest.mark.asyncio
async def test_verify_service_invalid_target():
    """Test verification with invalid target format."""
    manager = ServiceManager()
    
    result = await manager.verify_service('invalid_target')
    
    assert result['verified'] is False
    assert 'Invalid target format' in result['error']


@pytest.mark.asyncio
async def test_start_browser_service():
    """Test starting browser service."""
    manager = ServiceManager()
    
    with patch('mcpbundles.service_manager.BrowserService') as mock_browser_class:
        mock_browser = AsyncMock()
        mock_browser.start = AsyncMock()
        mock_browser.port = 9223
        mock_browser.headless = False
        mock_browser_class.return_value = mock_browser
        
        result = await manager.start_service('browser', {'headless': False})
        
        assert result['started'] is True
        assert result['service'] == 'browser'
        assert result['port'] == 9223
        assert result['mode'] == 'visible'


@pytest.mark.asyncio
async def test_start_browser_already_running():
    """Test starting browser when already running."""
    manager = ServiceManager()
    
    # Create a mock browser that's already running
    mock_browser = AsyncMock()
    mock_browser.running = True
    mock_browser.port = 9223
    mock_browser.headless = False
    manager.browser = mock_browser
    
    result = await manager.start_service('browser', {'headless': False})
    
    assert result['started'] is True
    assert result['already_running'] is True


@pytest.mark.asyncio
async def test_stop_browser_service():
    """Test stopping browser service."""
    manager = ServiceManager()
    
    # Create a mock running browser
    mock_browser = AsyncMock()
    mock_browser.running = True
    mock_browser.stop = AsyncMock()
    manager.browser = mock_browser
    manager.services['browser'] = mock_browser
    
    result = await manager.stop_service('browser')
    
    assert result['stopped'] is True
    assert result['service'] == 'browser'
    assert manager.browser is None


@pytest.mark.asyncio
async def test_stop_browser_not_running():
    """Test stopping browser when not running."""
    manager = ServiceManager()
    
    result = await manager.stop_service('browser')
    
    assert result['stopped'] is True
    assert result['was_running'] is False


@pytest.mark.asyncio
async def test_update_browser_config():
    """Test updating browser configuration."""
    manager = ServiceManager()
    
    # Create a mock running browser
    mock_browser = AsyncMock()
    mock_browser.running = True
    mock_browser.headless = False
    mock_browser.update_config = AsyncMock()
    manager.browser = mock_browser
    
    result = await manager.update_service('browser', {'headless': True})
    
    assert result['updated'] is True
    assert result['mode'] == 'hidden'
    mock_browser.update_config.assert_called_once_with(True)


@pytest.mark.asyncio
async def test_update_browser_not_running():
    """Test updating browser when not running starts it."""
    manager = ServiceManager()
    
    with patch('mcpbundles.service_manager.BrowserService') as mock_browser_class:
        mock_browser = AsyncMock()
        mock_browser.start = AsyncMock()
        mock_browser.port = 9223
        mock_browser.headless = True
        mock_browser_class.return_value = mock_browser
        
        result = await manager.update_service('browser', {'headless': True})
        
        assert result['started'] is True




@pytest.mark.asyncio
async def test_start_unknown_service():
    """Test starting unknown service type."""
    manager = ServiceManager()
    
    result = await manager.start_service('unknown_service', {})
    
    assert result['started'] is False
    assert 'Unknown service' in result['error']


@pytest.mark.asyncio
async def test_stop_unknown_service():
    """Test stopping unknown service type."""
    manager = ServiceManager()
    
    result = await manager.stop_service('unknown_service')
    
    assert result['stopped'] is False
    assert 'Unknown service' in result['error']


@pytest.mark.asyncio
async def test_get_status_browser_running():
    """Test getting status with browser running."""
    manager = ServiceManager()
    
    mock_browser = Mock()
    mock_browser.get_status.return_value = {
        'enabled': True,
        'headless': False,
        'port': 9223,
        'mode': 'visible'
    }
    manager.browser = mock_browser
    
    status = manager.get_status()
    
    assert status['browser']['enabled'] is True
    assert status['browser']['mode'] == 'visible'


@pytest.mark.asyncio
async def test_get_status_browser_not_running():
    """Test getting status with browser not running."""
    manager = ServiceManager()
    
    status = manager.get_status()
    
    assert status['browser']['enabled'] is False
    assert status['browser']['mode'] == 'disabled'


@pytest.mark.asyncio
async def test_stop_all_services():
    """Test stopping all services."""
    manager = ServiceManager()
    
    mock_browser = AsyncMock()
    mock_browser.stop = AsyncMock()
    manager.browser = mock_browser
    manager.services['browser'] = mock_browser
    
    await manager.stop_all()
    
    assert manager.browser is None
    assert len(manager.services) == 0
    mock_browser.stop.assert_called_once()

