"""Test CLI commands."""

import os
import pytest
from click.testing import CliRunner
from unittest.mock import Mock, patch, MagicMock
from mcpbundles_proxy.cli import cli


@pytest.fixture
def runner():
    """Click CLI test runner."""
    return CliRunner()


def test_cli_version(runner):
    """Test version command."""
    result = runner.invoke(cli, ['--version'])
    assert result.exit_code == 0
    assert 'mcpbundles-proxy' in result.output
    assert 'version' in result.output


def test_cli_help(runner):
    """Test help command."""
    result = runner.invoke(cli, ['--help'])
    assert result.exit_code == 0
    assert 'MCPBundles Desktop Proxy' in result.output
    assert 'login' in result.output
    assert 'start' in result.output


def test_login_success(runner):
    """Test successful login."""
    with patch('mcpbundles_proxy.cli.oauth_flow') as mock_oauth:
        mock_oauth.return_value = {"access_token": "test"}
        
        result = runner.invoke(cli, ['login'])
        assert result.exit_code == 0
        assert 'Successfully authenticated' in result.output


def test_login_failure(runner):
    """Test login failure."""
    with patch('mcpbundles_proxy.cli.oauth_flow') as mock_oauth:
        mock_oauth.side_effect = Exception("OAuth failed")
        
        result = runner.invoke(cli, ['login'])
        assert result.exit_code == 1
        assert 'Authentication failed' in result.output


def test_start_not_authenticated(runner):
    """Test start without authentication."""
    with patch('mcpbundles_proxy.cli.load_token', return_value=None):
        with patch('mcpbundles_proxy.cli.is_running', return_value=False):
            result = runner.invoke(cli, ['start'])
            assert result.exit_code == 1
            assert 'Not authenticated' in result.output


def test_start_already_running(runner):
    """Test start when already running."""
    with patch('mcpbundles_proxy.cli.load_token', return_value={"access_token": "test"}):
        with patch('mcpbundles_proxy.cli.is_running', return_value=True):
            result = runner.invoke(cli, ['start'])
            assert result.exit_code == 0
            assert 'already running' in result.output


def test_start_success(runner):
    """Test successful start."""
    with patch('mcpbundles_proxy.cli.load_token', return_value={"access_token": "test"}):
        with patch('mcpbundles_proxy.cli.is_running', return_value=False):
            with patch('mcpbundles_proxy.cli.start_daemon') as mock_start:
                result = runner.invoke(cli, ['start'])
                assert result.exit_code == 0
                assert 'Tunnel started' in result.output
                mock_start.assert_called_once()


def test_stop_not_running(runner):
    """Test stop when not running."""
    with patch('mcpbundles_proxy.cli.is_running', return_value=False):
        result = runner.invoke(cli, ['stop'])
        assert result.exit_code == 0
        assert 'not running' in result.output


def test_stop_success(runner):
    """Test successful stop."""
    with patch('mcpbundles_proxy.cli.is_running', return_value=True):
        with patch('mcpbundles_proxy.cli.stop_daemon') as mock_stop:
            result = runner.invoke(cli, ['stop'])
            assert result.exit_code == 0
            assert 'Tunnel stopped' in result.output
            mock_stop.assert_called_once()


def test_status_not_running(runner):
    """Test status when not running."""
    with patch('mcpbundles_proxy.cli.get_status', return_value={'running': False}):
        result = runner.invoke(cli, ['status'])
        assert result.exit_code == 0
        assert 'Not running' in result.output


def test_status_running(runner):
    """Test status when running."""
    status_data = {
        'running': True,
        'pid': 12345,
        'uptime': '1:23:45',
        'tunnel_status': 'connected'
    }
    
    with patch('mcpbundles_proxy.cli.get_status', return_value=status_data):
        result = runner.invoke(cli, ['status'])
        assert result.exit_code == 0
        assert 'Running' in result.output
        assert '12345' in result.output
        assert '1:23:45' in result.output


def test_logs_no_file(runner, tmp_path):
    """Test logs when log file doesn't exist."""
    with patch('mcpbundles_proxy.cli.CONFIG_DIR', tmp_path):
        result = runner.invoke(cli, ['logs'])
        assert result.exit_code == 0
        assert 'No logs found' in result.output


def test_logs_with_file(runner, tmp_path):
    """Test viewing logs."""
    log_file = tmp_path / 'tunnel.log'
    log_file.write_text("Log line 1\nLog line 2\nLog line 3\n")
    
    with patch('mcpbundles_proxy.cli.CONFIG_DIR', tmp_path):
        result = runner.invoke(cli, ['logs'])
        assert result.exit_code == 0
        assert 'Log line 1' in result.output
        assert 'Log line 2' in result.output


def test_logs_limit(runner, tmp_path):
    """Test logs with line limit."""
    log_file = tmp_path / 'tunnel.log'
    log_file.write_text('\n'.join([f"Log line {i}" for i in range(100)]))
    
    with patch('mcpbundles_proxy.cli.CONFIG_DIR', tmp_path):
        result = runner.invoke(cli, ['logs', '-n', '10'])
        assert result.exit_code == 0
        # Should only show last 10 lines
        assert 'Log line 99' in result.output
        assert 'Log line 0' not in result.output


def test_restart(runner):
    """Test restart command."""
    with patch('mcpbundles_proxy.cli.is_running', return_value=True):
        with patch('mcpbundles_proxy.cli.stop_daemon'):
            with patch('mcpbundles_proxy.cli.load_token', return_value={"access_token": "test"}):
                with patch('mcpbundles_proxy.cli.start_daemon'):
                    with patch('time.sleep'):  # Skip the sleep
                        result = runner.invoke(cli, ['restart'])
                        assert result.exit_code == 0
                        assert 'Tunnel restarted' in result.output


def test_logout(runner, tmp_path):
    """Test logout command."""
    with patch('mcpbundles_proxy.cli.is_running', return_value=False):
        with patch('mcpbundles_proxy.config.delete_token') as mock_delete:
            result = runner.invoke(cli, ['logout'])
            assert result.exit_code == 0
            assert 'Logged out' in result.output
            mock_delete.assert_called_once()


def test_logout_while_running(runner):
    """Test logout stops daemon first."""
    with patch('mcpbundles_proxy.cli.is_running', return_value=True):
        with patch('mcpbundles_proxy.cli.stop_daemon') as mock_stop:
            with patch('mcpbundles_proxy.config.delete_token'):
                result = runner.invoke(cli, ['logout'])
                assert result.exit_code == 0
                mock_stop.assert_called_once()


def test_is_running_with_valid_pid(tmp_path, monkeypatch):
    """Test is_running check with valid PID."""
    from mcpbundles_proxy.cli import is_running
    
    pid_file = tmp_path / "tunnel.pid"
    pid_file.write_text(str(os.getpid()))  # Current process PID
    
    with patch('mcpbundles_proxy.cli.get_pid_file', return_value=pid_file):
        assert is_running() is True


def test_is_running_with_invalid_pid(tmp_path):
    """Test is_running check with invalid PID."""
    from mcpbundles_proxy.cli import is_running
    
    pid_file = tmp_path / "tunnel.pid"
    pid_file.write_text("999999")  # Non-existent PID
    
    with patch('mcpbundles_proxy.cli.get_pid_file', return_value=pid_file):
        assert is_running() is False
        assert not pid_file.exists()  # Should clean up stale PID file

