"""
Tests for Proactive Assistant System

Tests all four modules:
1. Auto-Detection & Analysis
2. Proactive Information Display
3. Intelligent Error Resolution
4. AI Copilot Integration
"""

import pytest
import json
import tempfile
from pathlib import Path
from datetime import datetime, timedelta
from unittest.mock import Mock, MagicMock, patch

from navig.config import ConfigManager
from navig.proactive_assistant import ProactiveAssistant
from navig.assistant_utils import ensure_navig_directory, get_navig_directory
from navig.modules.auto_detection import AutoDetection
from navig.modules.proactive_display import ProactiveDisplay
from navig.modules.error_resolution import ErrorResolution, Solution
from navig.modules.context_generator import ContextGenerator


class TestAssistantUtils:
    """Test assistant utility functions."""
    
    def test_get_navig_directory(self):
        """Test getting NAVIG directory path."""
        navig_dir = get_navig_directory()
        assert navig_dir is not None
        assert isinstance(navig_dir, Path)
    
    def test_ensure_navig_directory(self):
        """Test directory creation."""
        navig_dir = ensure_navig_directory()
        assert navig_dir.exists()
        assert (navig_dir / 'ai_context').exists()
        assert (navig_dir / 'baselines').exists()
    
    def test_json_files_initialized(self):
        """Test that JSON files are initialized."""
        navig_dir = ensure_navig_directory()
        ai_context_dir = navig_dir / 'ai_context'
        
        required_files = [
            'command_history.json',
            'error_log.json',
            'error_patterns.json',
            'solutions.json',
            'performance_baselines.json',
            'workflow_patterns.json',
            'detected_issues.json',
            'config_rules.json'
        ]
        
        for filename in required_files:
            file_path = ai_context_dir / filename
            assert file_path.exists(), f"{filename} should exist"


class TestAutoDetection:
    """Test Module 1: Auto-Detection & Analysis."""
    
    @pytest.fixture
    def assistant(self):
        """Create mock assistant."""
        config = Mock()
        config.global_config = {'proactive_assistant': {'enabled': True}}
        assistant = ProactiveAssistant(config)
        return assistant
    
    def test_log_command_execution(self, assistant):
        """Test command execution logging."""
        auto_detect = assistant.auto_detection
        
        auto_detect.log_command_execution(
            command="navig sql 'SELECT 1'",
            exit_code=0,
            stderr="",
            stdout="1",
            duration=0.5,
            context={'server': 'test-server'}
        )
        
        # Check history file
        history_file = assistant.ai_context_dir / 'command_history.json'
        assert history_file.exists()
        
        with open(history_file, 'r') as f:
            history = json.load(f)
        
        assert len(history) > 0
        assert history[-1]['command'] == "navig sql 'SELECT 1'"
        assert history[-1]['exit_code'] == 0
    
    def test_categorize_error(self, assistant):
        """Test error categorization."""
        auto_detect = assistant.auto_detection
        
        assert auto_detect._categorize_error("Permission denied") == 'permission'
        assert auto_detect._categorize_error("Connection refused") == 'network'
        assert auto_detect._categorize_error("Disk full") == 'resource_exhaustion'
        assert auto_detect._categorize_error("No such file") == 'dependency_missing'
        assert auto_detect._categorize_error("Syntax error") == 'syntax'
    
    def test_collect_performance_metrics(self, assistant):
        """Test performance metrics collection."""
        auto_detect = assistant.auto_detection

        # Mock remote operations
        remote_ops = Mock()
        remote_ops.execute_command = Mock(side_effect=[
            Mock(returncode=0, stdout="25.5"),  # CPU
            Mock(returncode=0, stdout="60.2"),  # Memory
            Mock(returncode=0, stdout="75")     # Disk
        ])

        # Mock server config
        server_config = {'name': 'test', 'host': 'localhost', 'user': 'test'}

        metrics = auto_detect.collect_performance_metrics(remote_ops, server_config)

        assert 'cpu_percent' in metrics
        assert 'memory_percent' in metrics
        assert 'disk_percent' in metrics
        assert metrics['status'] in ['normal', 'warning', 'critical']


class TestProactiveDisplay:
    """Test Module 2: Proactive Information Display."""
    
    @pytest.fixture
    def assistant(self):
        """Create mock assistant."""
        config = Mock()
        config.global_config = {'proactive_assistant': {'enabled': True}}
        assistant = ProactiveAssistant(config)
        return assistant
    
    def test_is_destructive_operation(self, assistant):
        """Test destructive operation detection."""
        display = assistant.proactive_display
        
        assert display._is_destructive_operation('delete', {'recursive': True})
        assert display._is_destructive_operation('sql', {'query': 'DROP TABLE users'})
        assert not display._is_destructive_operation('list', {})
    
    def test_check_pre_execution_warnings(self, assistant):
        """Test pre-execution warnings."""
        display = assistant.proactive_display
        
        should_proceed, warnings = display.check_pre_execution_warnings(
            command='delete',
            args={'remote': '/var/www/html', 'recursive': True},
            context={'yes': False}
        )
        
        assert len(warnings) > 0
        assert not should_proceed  # Should require confirmation


class TestErrorResolution:
    """Test Module 3: Intelligent Error Resolution."""
    
    @pytest.fixture
    def assistant(self):
        """Create mock assistant."""
        config = Mock()
        config.global_config = {'proactive_assistant': {'enabled': True}}
        assistant = ProactiveAssistant(config)
        return assistant
    
    def test_solution_creation(self):
        """Test Solution object creation."""
        solution = Solution(
            description="Fix permissions",
            command="chmod 755 /var/www",
            success_rate=0.85,
            risk_level='medium'
        )
        
        assert solution.description == "Fix permissions"
        assert solution.success_rate == 0.85
        
        # Test serialization
        sol_dict = solution.to_dict()
        assert sol_dict['command'] == "chmod 755 /var/www"
        
        # Test deserialization
        solution2 = Solution.from_dict(sol_dict)
        assert solution2.description == solution.description
    
    def test_analyze_error(self, assistant):
        """Test error analysis."""
        error_res = assistant.error_resolution
        
        solutions = error_res.analyze_error(
            command="navig upload file.txt",
            exit_code=1,
            error_message="Permission denied",
            context={'server': 'test'}
        )
        
        # Should return list of solutions (may be empty if no matches)
        assert isinstance(solutions, list)
    
    def test_record_solution_feedback(self, assistant):
        """Test solution feedback recording."""
        error_res = assistant.error_resolution
        
        error_res.record_solution_feedback(
            error_pattern="Permission denied",
            solution_command="chmod 755 /path",
            success=True,
            category='permission'
        )
        
        # Check solutions file
        solutions_file = assistant.ai_context_dir / 'solutions.json'
        assert solutions_file.exists()


class TestContextGenerator:
    """Test Module 4: AI Copilot Integration."""
    
    @pytest.fixture
    def assistant(self):
        """Create mock assistant."""
        config = Mock()
        config.global_config = {'proactive_assistant': {'enabled': True}}
        config.get_active_server = Mock(return_value={
            'name': 'test-server',
            'host': '10.0.0.10',
            'user': 'admin'
        })
        assistant = ProactiveAssistant(config)
        return assistant
    
    def test_generate_context_summary(self, assistant):
        """Test context summary generation."""
        ctx_gen = assistant.context_generator

        config = Mock()
        config.get_active_server = Mock(return_value='test-server')
        config.load_server_config = Mock(return_value={
            'name': 'test-server',
            'host': '10.0.0.10',
            'user': 'admin'
        })

        context = ctx_gen.generate_context_summary(config, remote_ops=None)

        assert 'generated_at' in context
        assert 'server' in context
        assert 'recent_operations' in context
        assert 'context_summary' in context
    
    def test_context_summary_format(self, assistant):
        """Test that context summary is properly formatted."""
        ctx_gen = assistant.context_generator

        config = Mock()
        config.get_active_server = Mock(return_value='test-server')
        config.load_server_config = Mock(return_value={
            'name': 'test-server',
            'host': '10.0.0.10',
            'user': 'admin'
        })

        context = ctx_gen.generate_context_summary(config)

        # Should be JSON serializable
        json_str = json.dumps(context)
        assert json_str is not None

