#!/usr/bin/env python3
"""
Tests for the Magic Assistant
"""

import os
import sys
import pytest
import asyncio
import tempfile
from pathlib import Path
from unittest.mock import Mock, patch, AsyncMock
from typing import Dict, Any
from datetime import datetime

# Add the parent directory to the Python path
sys.path.append(str(Path(__file__).parent.parent))

from tools.magic_assistant import (
    MagicAssistant, 
    WorkMode, 
    TriggerType,
    CodeAnalyzer,
    CodeVisualizer,
    Context,
    Pattern,
    ErrorContext,
    AutoLearner
)

@pytest.fixture
def workspace_root(tmp_path):
    """Create a temporary workspace root directory."""
    return tmp_path

@pytest.fixture
def magic_assistant(workspace_root):
    """Create a MagicAssistant instance with a temporary workspace."""
    assistant = MagicAssistant(workspace_root=str(workspace_root))
    return assistant

@pytest.fixture
def mock_context():
    return Context(
        mode=WorkMode.PLAN,
        current_file="test.py",
        current_task="Test task",
        checkpoints=[],
        learned_patterns={},
        code_insights={},
        visualization_cache={},
        error_history={},
        active_triggers=set(),
        task_queue=[],
        research_cache={}
    )

@pytest.fixture
def mock_pattern():
    """Create a mock pattern for testing."""
    return Pattern(
        id="test_pattern",
        type="code_style",
        description="Test pattern",
        code_snippet="def test(): pass",
        success_count=5,
        failure_count=1,
        last_used=datetime.now(),
        contexts=["test"],
        confidence=0.8
    )

@pytest.mark.asyncio
async def test_initialization(magic_assistant):
    """Test initialization of MagicAssistant."""
    assert isinstance(magic_assistant.analyzer, CodeAnalyzer)
    assert isinstance(magic_assistant.learner, AutoLearner)
    assert isinstance(magic_assistant.context, Context)
    assert magic_assistant.context.mode == WorkMode.PLAN

@pytest.mark.asyncio
async def test_error_handling(magic_assistant):
    """Test error handling functionality."""
    error_type = "ValueError"
    message = "Test error"
    stack_trace = "test.py:10"
    
    # Handle new error
    magic_assistant.handle_error(error_type, message, stack_trace)
    error_key = f"{error_type}:{message}"
    
    assert error_key in magic_assistant.context.error_history
    error = magic_assistant.context.error_history[error_key]
    assert error.frequency == 1
    assert error.error_type == error_type
    assert error.message == message
    assert error.stack_trace == stack_trace
    assert not error.resolved
    
    # Handle same error again
    magic_assistant.handle_error(error_type, message, stack_trace)
    assert magic_assistant.context.error_history[error_key].frequency == 2

@pytest.mark.asyncio
async def test_context_persistence(magic_assistant, workspace_root):
    """Test context saving and loading."""
    # Save context
    magic_assistant.context.current_task = "Test task"
    magic_assistant._save_context()
    
    # Modify context
    magic_assistant.context.current_task = "Modified task"
    
    # Create new instance with same workspace
    new_assistant = MagicAssistant(workspace_root)
    assert new_assistant.context.current_task == "Test task"

@pytest.mark.asyncio
async def test_task_queue(magic_assistant):
    """Test task queue functionality."""
    task = {
        "type": "analyze",
        "data": {"file": "test.py"}
    }
    
    # Queue task
    magic_assistant.queue_task(task)
    
    # Wait for task processing
    await asyncio.sleep(0.1)
    
    # Verify task was processed
    assert magic_assistant.task_queue.empty()

@pytest.mark.asyncio
async def test_trigger_monitoring(magic_assistant):
    """Test trigger monitoring functionality."""
    # Create an error that should trigger monitoring
    for _ in range(3):  # Trigger threshold is 2
        magic_assistant.handle_error("TestError", "test", "test.py:1")
    
    # Wait for trigger processing
    await asyncio.sleep(0.1)
    
    # Verify trigger was activated
    assert TriggerType.ERROR_REPEAT in magic_assistant.context.active_triggers

@pytest.mark.asyncio
async def test_code_analysis(magic_assistant):
    """Test code analysis functionality."""
    test_code = """
def test_function():
    print("Hello")
    return None
"""
    
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as tf:
        tf.write(test_code)
        tf.flush()
        
        # Test code complexity analysis
        complexity = await magic_assistant.analyzer.analyze_complexity(tf.name)
        assert isinstance(complexity, dict)
        assert complexity["cyclomatic_complexity"] == 1
        assert complexity["functions"] == 1
        
        # Test pattern detection
        patterns = await magic_assistant.analyzer.detect_patterns(tf.name)
        assert len(patterns) > 0
        assert any(p["type"] == "function" and p["name"] == "test_function" for p in patterns)
        
        # Test issue detection
        issues = await magic_assistant.analyzer.detect_issues(tf.name)
        assert isinstance(issues, list)

@pytest.mark.asyncio
async def test_learning_functionality(magic_assistant, mock_pattern):
    """Test learning functionality."""
    # Test pattern learning
    await magic_assistant.learner.learn_from_interaction(
        "success",
        {"pattern": mock_pattern}
    )
    
    # Verify pattern was learned
    assert len(magic_assistant.context.learned_patterns) > 0

@pytest.mark.asyncio
async def test_autonomous_operation(magic_assistant):
    """Test autonomous operation functionality."""
    # Start autonomous operation
    magic_assistant.start()
    
    # Wait for some processing
    await asyncio.sleep(0.1)
    
    # Stop operation
    magic_assistant.stop()
    
    # Verify assistant stopped
    assert not magic_assistant.running

@pytest.mark.asyncio
async def test_llm_integration(magic_assistant):
    """Test LLM integration."""
    with patch('openai.ChatCompletion.acreate') as mock_openai:
        mock_openai.return_value.choices = [Mock(message=Mock(content="Test response"))]
        
        response = await magic_assistant.query_llm("Test prompt")
        assert response == "Test response"
        mock_openai.assert_called_once()

def test_performance_monitoring(magic_assistant):
    """Test performance monitoring functionality."""
    assert hasattr(magic_assistant, 'analyzer')
    assert hasattr(magic_assistant.analyzer, 'complexity_cache')
    assert hasattr(magic_assistant.analyzer, 'pattern_cache')
    assert hasattr(magic_assistant.analyzer, 'issue_cache')

if __name__ == "__main__":
    pytest.main([__file__]) 