"""
Test d'intégration end-to-end pour Web Sentinel avec modules OWASP Top 10 2021
Ce test vérifie le workflow complet: GUI → Scanner → Orchestrateur → Modules → Findings
"""

import sys
import threading
import time
from pathlib import Path
from unittest.mock import patch, Mock

# Ajouter le répertoire racine au path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from web_sentinel.model import ScanRequest
from web_sentinel.orchestrator import build_default_modules
from web_sentinel.scanner import SentinelScanner


def test_end_to_end_integration():
    """Test d'intégration end-to-end complet."""
    
    print("🔄 Test d'intégration end-to-end Web Sentinel...")
    
    # 1. Test de l'orchestrateur avec modules OWASP
    print("\n1️⃣ Test orchestrateur avec modules OWASP")
    modules = build_default_modules()
    owasp_modules = [m for m in modules if any(tag.startswith("owasp-") for tag in m.tags)]
    
    print(f"   📊 Modules OWASP chargés: {len(owasp_modules)}")
    for module in owasp_modules:
        print(f"      • {module.name}")
    
    # 2. Test de création d'une requête de scan
    print("\n2️⃣ Test de création d'une requête de scan")
    request = ScanRequest(
        domain="example.com",
        timeout=5.0,
        allow_invasive=True  # Test avec mode invasif
    )
    
    print(f"   🎯 Domain: {request.domain}")
    print(f"   ⏱️ Timeout: {request.timeout}s")
    print(f"   🔓 Invasive: {request.allow_invasive}")
    
    # 3. Test du scanner avec mocks
    print("\n3️⃣ Test du scanner avec modules OWASP")
    
    with patch('requests.get') as mock_get, \
         patch('requests.head') as mock_head, \
         patch('requests.post') as mock_post:
        
        # Configurer les mocks pour simuler des réponses HTTP réalistes
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {
            'Server': 'nginx/1.18.0',
            'Content-Type': 'text/html',
            'Set-Cookie': 'sessionid=abc123; Path=/'
        }
        mock_response.text = '''
        <html>
            <head>
                <title>Test Site</title>
                <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
            </head>
            <body>
                <h1>Test Application</h1>
                <form action="/login" method="post">
                    <input type="text" name="username" />
                    <input type="password" name="password" />
                    <button type="submit">Login</button>
                </form>
            </body>
        </html>
        '''
        
        mock_get.return_value = mock_response
        mock_head.return_value = mock_response
        mock_post.return_value = mock_response
        
        # Créer le scanner
        scanner = SentinelScanner()
        
        # Filtrer pour ne tester que les modules OWASP
        owasp_module_names = [m.name for m in owasp_modules]
        
        # Exécuter le scan
        print(f"   🚀 Exécution du scan avec {len(owasp_module_names)} modules OWASP...")
        
        try:
            scan_result = scanner.run(request, enabled_modules=owasp_module_names)
            scan_results = scan_result.findings
            
            print(f"   ✅ Scan terminé avec succès")
            print(f"   📊 Résultats: {len(scan_results)} findings au total")
            
            # 4. Analyser les résultats par module
            print("\n4️⃣ Analyse des résultats par module OWASP")
            
            findings_by_module = {}
            for finding in scan_results:
                module_name = finding.check
                if module_name not in findings_by_module:
                    findings_by_module[module_name] = []
                findings_by_module[module_name].append(finding)
            
            for module_name in owasp_module_names:
                # Convertir le nom du module pour correspondre aux findings
                finding_check_name = module_name.replace('-', '_')
                count = len(findings_by_module.get(finding_check_name, []))
                print(f"      • {module_name:<25} → {count} findings")
            
            # 5. Vérifier la qualité des findings
            print("\n5️⃣ Vérification de la qualité des findings")
            
            valid_severities = {"critical", "high", "medium", "low", "info"}
            issues = []
            
            for finding in scan_results:
                # Vérifier la structure basique
                if not finding.title:
                    issues.append(f"Finding sans title: {finding.check}")
                if not finding.description:
                    issues.append(f"Finding sans description: {finding.check}")
                if not finding.remediation:
                    issues.append(f"Finding sans remediation: {finding.check}")
                if finding.severity not in valid_severities:
                    issues.append(f"Severity invalide '{finding.severity}': {finding.check}")
            
            if issues:
                print(f"      ❌ {len(issues)} problèmes détectés:")
                for issue in issues[:5]:  # Limiter à 5 pour la lisibilité
                    print(f"         • {issue}")
                return False
            else:
                print(f"      ✅ Tous les findings ont une structure valide")
            
            return True
            
        except Exception as e:
            print(f"   ❌ Erreur lors du scan: {e}")
            return False


def test_scanner_performance():
    """Test de performance basique du scanner."""
    
    print("\n🏁 Test de performance basique...")
    
    request = ScanRequest(domain="example.com", timeout=2.0)
    modules = build_default_modules()
    owasp_modules = [m.name for m in modules if any(tag.startswith("owasp-") for tag in m.tags)]
    
    with patch('requests.get') as mock_get:
        # Mock simple pour la performance
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.headers = {}
        mock_response.text = '<html><body>Test</body></html>'
        mock_get.return_value = mock_response
        
        start_time = time.time()
        
        scanner = SentinelScanner()
        result = scanner.run(request, enabled_modules=owasp_modules)
        results = result.findings
        
        execution_time = time.time() - start_time
        
        print(f"   ⏱️ Temps d'exécution: {execution_time:.2f}s")
        print(f"   📊 Findings générés: {len(results)}")
        print(f"   🎯 Modules testés: {len(owasp_modules)}")
        
        # Le scan ne devrait pas prendre plus de 10 secondes avec des mocks
        if execution_time < 10:
            print(f"   ✅ Performance acceptable")
            return True
        else:
            print(f"   ❌ Performance trop lente")
            return False


def test_gui_scanner_integration():
    """Test de l'intégration GUI-Scanner (simulation)."""
    
    print("\n🖥️ Test d'intégration GUI-Scanner (simulation)...")
    
    try:
        from web_sentinel.gui.modern_tabbed_window import ModernWebSentinelGUI
        import tkinter as tk
        
        # Créer une instance GUI de test (interface moderne avec onglets)
        root = tk.Tk()
        root.withdraw()  # Cacher la fenêtre pour les tests
        
        app = ModernWebSentinelGUI(root)
        
        # Vérifier que les modules OWASP sont disponibles
        owasp_modules = [
            'access-control',
            'crypto-failures', 
            'vulnerable-components',
            'insecure-design',
            'security-misconfiguration',
            'broken-authentication'
        ]
        
        all_present = True
        for module in owasp_modules:
            if module not in app.module_vars:
                print(f"      ❌ Module manquant dans GUI: {module}")
                all_present = False
        
        if all_present:
            print(f"      ✅ Tous les modules OWASP disponibles dans la GUI")
            
            # Test de sélection de modules
            enabled_modules = []
            for module in owasp_modules:
                if app.module_vars[module].get():
                    enabled_modules.append(module)
            
            print(f"      🔧 Modules activés par défaut: {len(enabled_modules)}")
            
        root.destroy()
        return all_present
        
    except Exception as e:
        print(f"      ❌ Erreur GUI: {e}")
        return False


if __name__ == "__main__":
    
    print("=" * 80)
    print("🔐 WEB SENTINEL - TEST D'INTÉGRATION END-TO-END COMPLET")
    print("=" * 80)
    
    # Tests d'intégration
    tests = [
        ("End-to-End Integration", test_end_to_end_integration),
        ("Scanner Performance", test_scanner_performance),
        ("GUI-Scanner Integration", test_gui_scanner_integration)
    ]
    
    results = {}
    
    for test_name, test_func in tests:
        print(f"\n🧪 {test_name}...")
        try:
            success = test_func()
            results[test_name] = "✅ RÉUSSI" if success else "❌ ÉCHEC"
        except Exception as e:
            results[test_name] = f"❌ ERREUR: {e}"
    
    # Résumé final
    print("\n" + "=" * 80)
    print("📋 RÉSUMÉ DES TESTS D'INTÉGRATION")
    print("=" * 80)
    
    all_passed = True
    for test_name, result in results.items():
        print(f"{result:<20} {test_name}")
        if not result.startswith("✅"):
            all_passed = False
    
    print("\n" + "=" * 80)
    
    if all_passed:
        print("🎉 INTÉGRATION COMPLÈTE RÉUSSIE !")
        print("🔐 Web Sentinel avec modules OWASP Top 10 2021 est prêt à l'utilisation")
        print("\n✨ Fonctionnalités validées:")
        print("   • 6 nouveaux modules de sécurité OWASP Top 10 2021")
        print("   • Intégration orchestrateur fonctionnelle") 
        print("   • Interface GUI mise à jour")
        print("   • Pipeline de scan end-to-end opérationnel")
        print("   • Génération de findings structurés")
        print("   • Performance acceptable")
        exit(0)
    else:
        print("❌ CERTAINS TESTS D'INTÉGRATION ONT ÉCHOUÉ")
        print("🔧 Vérifiez les erreurs ci-dessus")
        exit(1)