#!/usr/bin/env python3
"""
🌐 Interface Web moderne pour l'environnement de test Web Sentinel
FastAPI + HTML moderne avec WebSockets pour temps réel
"""

import sys
import json
import asyncio
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional

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

try:
    from fastapi import FastAPI, Request, Form, WebSocket, WebSocketDisconnect
    from fastapi.responses import HTMLResponse, JSONResponse
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates
    import uvicorn
    FASTAPI_AVAILABLE = True
except ImportError:
    FASTAPI_AVAILABLE = False

class WebTestInterface:
    """Interface web moderne pour l'environnement de test"""
    
    def __init__(self):
        if not FASTAPI_AVAILABLE:
            raise ImportError("FastAPI non disponible")
        
        self.app = FastAPI(title="Web Sentinel Test Environment", version="1.0.0")
        self.base_dir = Path(__file__).parent
        
        # Créer dossiers statiques
        self.static_dir = self.base_dir / "web_static"
        self.templates_dir = self.base_dir / "web_templates"
        self.static_dir.mkdir(exist_ok=True)
        self.templates_dir.mkdir(exist_ok=True)
        
        # WebSocket connections for real-time updates
        self.websocket_connections: List[WebSocket] = []
        
        # Initialiser gestionnaires
        self.setup_managers()
        
        # Créer fichiers statiques et templates
        self.create_static_files()
        self.create_templates()
        
        # Configurer routes
        self.setup_routes()
    
    def setup_managers(self):
        """Initialiser les gestionnaires"""
        from test_accounts import TestAccountManager
        from generate_test_license import TestLicenseGenerator
        from test_scenarios import TestScenarios
        from database_setup import TestDatabaseSetup
        from metrics_simulator import MetricsSimulator
        from test_orchestrator import TestOrchestrator
        
        self.account_manager = TestAccountManager()
        self.license_generator = TestLicenseGenerator()
        self.scenarios = TestScenarios()
        self.database = TestDatabaseSetup()
        self.metrics = MetricsSimulator()
        self.orchestrator = TestOrchestrator()
    
    def create_static_files(self):
        """Créer les fichiers CSS et JS"""
        
        # CSS moderne
        css_content = """
/* Web Sentinel Test Environment - Styles modernes */
:root {
    --primary-color: #3b82f6;
    --secondary-color: #64748b;
    --success-color: #10b981;
    --warning-color: #f59e0b;
    --error-color: #ef4444;
    --bg-primary: #ffffff;
    --bg-secondary: #f8fafc;
    --bg-dark: #1e293b;
    --text-primary: #1e293b;
    --text-secondary: #64748b;
    --border-color: #e2e8f0;
    --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
    background-color: var(--bg-secondary);
    color: var(--text-primary);
    line-height: 1.6;
}

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 1rem;
}

/* Header */
.header {
    background: var(--bg-primary);
    border-bottom: 1px solid var(--border-color);
    padding: 1rem 0;
    position: sticky;
    top: 0;
    z-index: 100;
    box-shadow: var(--shadow);
}

.header-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.logo {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--primary-color);
}

.nav-buttons {
    display: flex;
    gap: 0.5rem;
}

/* Buttons */
.btn {
    padding: 0.5rem 1rem;
    border: none;
    border-radius: 0.375rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.btn-primary {
    background: var(--primary-color);
    color: white;
}

.btn-primary:hover {
    background: #2563eb;
}

.btn-secondary {
    background: var(--bg-secondary);
    color: var(--text-primary);
    border: 1px solid var(--border-color);
}

.btn-secondary:hover {
    background: #e2e8f0;
}

.btn-success {
    background: var(--success-color);
    color: white;
}

.btn-warning {
    background: var(--warning-color);
    color: white;
}

.btn-error {
    background: var(--error-color);
    color: white;
}

/* Cards */
.card {
    background: var(--bg-primary);
    border-radius: 0.5rem;
    border: 1px solid var(--border-color);
    box-shadow: var(--shadow);
    overflow: hidden;
}

.card-header {
    padding: 1rem;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-secondary);
    font-weight: 600;
}

.card-body {
    padding: 1rem;
}

/* Dashboard grid */
.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin: 2rem 0;
}

.stat-card {
    text-align: center;
    padding: 2rem;
}

.stat-number {
    font-size: 2.5rem;
    font-weight: 700;
    color: var(--primary-color);
}

.stat-label {
    color: var(--text-secondary);
    margin-top: 0.5rem;
}

/* Tabs */
.tab-container {
    margin: 2rem 0;
}

.tab-buttons {
    display: flex;
    border-bottom: 1px solid var(--border-color);
    background: var(--bg-primary);
    border-radius: 0.5rem 0.5rem 0 0;
}

.tab-button {
    padding: 1rem 1.5rem;
    border: none;
    background: none;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    transition: all 0.2s;
    font-weight: 500;
}

.tab-button.active {
    color: var(--primary-color);
    border-bottom-color: var(--primary-color);
}

.tab-button:hover:not(.active) {
    background: var(--bg-secondary);
}

.tab-content {
    background: var(--bg-primary);
    border-radius: 0 0 0.5rem 0.5rem;
    border: 1px solid var(--border-color);
    border-top: none;
}

.tab-pane {
    display: none;
    padding: 2rem;
}

.tab-pane.active {
    display: block;
}

/* Tables */
.table-container {
    overflow-x: auto;
}

.table {
    width: 100%;
    border-collapse: collapse;
}

.table th,
.table td {
    padding: 0.75rem;
    text-align: left;
    border-bottom: 1px solid var(--border-color);
}

.table th {
    background: var(--bg-secondary);
    font-weight: 600;
}

.table tbody tr:hover {
    background: var(--bg-secondary);
}

/* Forms */
.form-group {
    margin-bottom: 1rem;
}

.form-label {
    display: block;
    margin-bottom: 0.25rem;
    font-weight: 500;
}

.form-input {
    width: 100%;
    padding: 0.5rem;
    border: 1px solid var(--border-color);
    border-radius: 0.375rem;
    transition: border-color 0.2s;
}

.form-input:focus {
    outline: none;
    border-color: var(--primary-color);
}

/* Status indicators */
.status {
    padding: 0.25rem 0.5rem;
    border-radius: 9999px;
    font-size: 0.875rem;
    font-weight: 500;
}

.status-success {
    background: #dcfce7;
    color: #166534;
}

.status-warning {
    background: #fef3c7;
    color: #92400e;
}

.status-error {
    background: #fecaca;
    color: #991b1b;
}

/* Activity log */
.activity-log {
    background: var(--bg-dark);
    color: #e2e8f0;
    padding: 1rem;
    border-radius: 0.375rem;
    font-family: 'Fira Code', monospace;
    font-size: 0.875rem;
    height: 300px;
    overflow-y: auto;
}

.log-entry {
    margin-bottom: 0.25rem;
}

.log-timestamp {
    color: #64748b;
}

/* Responsive */
@media (max-width: 768px) {
    .header-content {
        flex-direction: column;
        gap: 1rem;
    }
    
    .nav-buttons {
        flex-wrap: wrap;
        justify-content: center;
    }
    
    .dashboard-grid {
        grid-template-columns: 1fr;
    }
    
    .tab-buttons {
        flex-wrap: wrap;
    }
}

/* Animations */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(1rem); }
    to { opacity: 1; transform: translateY(0); }
}

.fade-in {
    animation: fadeIn 0.3s ease-out;
}

/* Loading spinner */
.spinner {
    border: 2px solid var(--border-color);
    border-top: 2px solid var(--primary-color);
    border-radius: 50%;
    width: 1rem;
    height: 1rem;
    animation: spin 1s linear infinite;
    display: inline-block;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
"""
        
        # JavaScript pour interactivité
        js_content = """
// Web Sentinel Test Environment - JavaScript
class TestEnvironmentUI {
    constructor() {
        this.websocket = null;
        this.init();
    }
    
    init() {
        this.setupTabs();
        this.setupWebSocket();
        this.loadDashboard();
    }
    
    setupTabs() {
        document.querySelectorAll('.tab-button').forEach(button => {
            button.addEventListener('click', (e) => {
                const targetTab = e.target.dataset.tab;
                this.switchTab(targetTab);
            });
        });
    }
    
    switchTab(tabId) {
        // Remove active class from all buttons and panes
        document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active'));
        document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.remove('active'));
        
        // Add active class to clicked button and corresponding pane
        document.querySelector(`[data-tab="${tabId}"]`).classList.add('active');
        document.getElementById(tabId).classList.add('active');
        
        // Load tab content
        this.loadTabContent(tabId);
    }
    
    setupWebSocket() {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const wsUrl = `${protocol}//${window.location.host}/ws`;
        
        this.websocket = new WebSocket(wsUrl);
        
        this.websocket.onopen = () => {
            this.log('WebSocket connecté');
        };
        
        this.websocket.onmessage = (event) => {
            const data = JSON.parse(event.data);
            this.handleWebSocketMessage(data);
        };
        
        this.websocket.onclose = () => {
            this.log('WebSocket déconnecté');
            // Reconnect after 5 seconds
            setTimeout(() => this.setupWebSocket(), 5000);
        };
    }
    
    handleWebSocketMessage(data) {
        switch (data.type) {
            case 'log':
                this.log(data.message);
                break;
            case 'stats_update':
                this.updateStats(data.stats);
                break;
            case 'test_result':
                this.handleTestResult(data.result);
                break;
        }
    }
    
    log(message) {
        const logContainer = document.getElementById('activity-log');
        if (logContainer) {
            const timestamp = new Date().toLocaleTimeString();
            const entry = document.createElement('div');
            entry.className = 'log-entry fade-in';
            entry.innerHTML = `<span class="log-timestamp">[${timestamp}]</span> ${message}`;
            logContainer.appendChild(entry);
            logContainer.scrollTop = logContainer.scrollHeight;
        }
    }
    
    updateStats(stats) {
        Object.entries(stats).forEach(([key, value]) => {
            const element = document.getElementById(`stat-${key}`);
            if (element) {
                element.textContent = value;
            }
        });
    }
    
    async loadDashboard() {
        try {
            const response = await fetch('/api/dashboard');
            const data = await response.json();
            this.updateStats(data.stats);
        } catch (error) {
            this.log(`Erreur chargement dashboard: ${error.message}`);
        }
    }
    
    async loadTabContent(tabId) {
        const loader = document.querySelector(`#${tabId} .content-loader`);
        if (loader) {
            loader.innerHTML = '<div class="spinner"></div> Chargement...';
        }
        
        try {
            const response = await fetch(`/api/${tabId}`);
            const data = await response.json();
            
            switch (tabId) {
                case 'accounts':
                    this.renderAccounts(data.accounts);
                    break;
                case 'licenses':
                    this.renderLicenses(data.licenses);
                    break;
                case 'metrics':
                    this.renderMetrics(data.metrics);
                    break;
            }
        } catch (error) {
            this.log(`Erreur chargement ${tabId}: ${error.message}`);
        }
    }
    
    renderAccounts(accounts) {
        const container = document.getElementById('accounts-table');
        if (!container) return;
        
        let html = `
            <table class="table">
                <thead>
                    <tr>
                        <th>Email</th>
                        <th>Tier</th>
                        <th>Statut</th>
                        <th>Expire</th>
                        <th>Domaines</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
        `;
        
        accounts.forEach(account => {
            const statusClass = account.status === 'active' ? 'status-success' : 'status-warning';
            html += `
                <tr>
                    <td>${account.email}</td>
                    <td><span class="status status-${account.tier.toLowerCase()}">${account.tier}</span></td>
                    <td><span class="status ${statusClass}">${account.status}</span></td>
                    <td>${account.license_expires || 'N/A'}</td>
                    <td>${account.domains_used || 0}/${account.domain_limit || 'N/A'}</td>
                    <td>
                        <button class="btn btn-secondary" onclick="ui.editAccount('${account.email}')">✏️</button>
                    </td>
                </tr>
            `;
        });
        
        html += '</tbody></table>';
        container.innerHTML = html;
    }
    
    renderLicenses(licenses) {
        const container = document.getElementById('licenses-table');
        if (!container) return;
        
        let html = `
            <table class="table">
                <thead>
                    <tr>
                        <th>Fichier</th>
                        <th>Utilisateur</th>
                        <th>Tier</th>
                        <th>Créé</th>
                        <th>Statut</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
        `;
        
        licenses.forEach(license => {
            html += `
                <tr>
                    <td>${license.filename}</td>
                    <td>${license.user}</td>
                    <td><span class="status status-${license.tier.toLowerCase()}">${license.tier}</span></td>
                    <td>${license.created}</td>
                    <td><span class="status status-success">✅ Valid</span></td>
                    <td>
                        <button class="btn btn-secondary" onclick="ui.validateLicense('${license.filename}')">🔍</button>
                    </td>
                </tr>
            `;
        });
        
        html += '</tbody></table>';
        container.innerHTML = html;
    }
    
    async executeAction(action, params = {}) {
        this.log(`Exécution: ${action}`);
        
        try {
            const response = await fetch('/api/action', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ action, params })
            });
            
            const result = await response.json();
            
            if (result.success) {
                this.log(`✅ ${action} réussi`);
            } else {
                this.log(`❌ ${action} échoué: ${result.error}`);
            }
            
            return result;
        } catch (error) {
            this.log(`❌ Erreur ${action}: ${error.message}`);
            return { success: false, error: error.message };
        }
    }
    
    // Actions spécifiques
    async quickSetup() {
        return this.executeAction('quick_setup');
    }
    
    async generateBrunoLicense() {
        return this.executeAction('generate_bruno_license');
    }
    
    async runUnitTests() {
        return this.executeAction('run_unit_tests');
    }
    
    async startMetrics() {
        return this.executeAction('start_metrics');
    }
    
    async checkDocker() {
        return this.executeAction('check_docker');
    }
    
    async runScenario(scenarioId) {
        return this.executeAction('run_scenario', { scenario_id: scenarioId });
    }
    
    async runTestSuite(suiteId) {
        return this.executeAction('run_test_suite', { suite_id: suiteId });
    }
}

// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    window.ui = new TestEnvironmentUI();
});
"""
        
        # Sauvegarder fichiers
        (self.static_dir / "style.css").write_text(css_content, encoding='utf-8')
        (self.static_dir / "script.js").write_text(js_content, encoding='utf-8')
    
    def create_templates(self):
        """Créer les templates HTML"""
        
        # Template de base
        base_template = """
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Sentinel Test Environment</title>
    <link rel="stylesheet" href="/static/style.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Fira+Code:wght@400&display=swap" rel="stylesheet">
</head>
<body>
    <header class="header">
        <div class="container">
            <div class="header-content">
                <div class="logo">🧪 Web Sentinel Test Environment</div>
                <div class="nav-buttons">
                    <button class="btn btn-primary" onclick="ui.quickSetup()">🔧 Setup</button>
                    <button class="btn btn-secondary" onclick="ui.generateBrunoLicense()">📝 Licence Bruno</button>
                    <button class="btn btn-secondary" onclick="ui.runUnitTests()">🧪 Tests</button>
                    <button class="btn btn-secondary" onclick="ui.startMetrics()">📊 Métriques</button>
                    <button class="btn btn-secondary" onclick="ui.checkDocker()">🐳 Docker</button>
                </div>
            </div>
        </div>
    </header>

    <main class="container">
        <div class="dashboard-grid">
            <div class="card stat-card">
                <div class="stat-number" id="stat-accounts">0</div>
                <div class="stat-label">👥 Comptes de test</div>
            </div>
            <div class="card stat-card">
                <div class="stat-number" id="stat-licenses">0</div>
                <div class="stat-label">📄 Licences générées</div>
            </div>
            <div class="card stat-card">
                <div class="stat-number" id="stat-scenarios">6</div>
                <div class="stat-label">🎯 Scénarios disponibles</div>
            </div>
            <div class="card stat-card">
                <div class="stat-number" id="stat-tests">--</div>
                <div class="stat-label">🧪 Tests réussis</div>
            </div>
        </div>

        <div class="tab-container">
            <div class="tab-buttons">
                <button class="tab-button active" data-tab="dashboard">📊 Dashboard</button>
                <button class="tab-button" data-tab="accounts">👥 Comptes</button>
                <button class="tab-button" data-tab="licenses">📄 Licences</button>
                <button class="tab-button" data-tab="scenarios">🎯 Scénarios</button>
                <button class="tab-button" data-tab="tests">🧪 Tests</button>
                <button class="tab-button" data-tab="docker">🐳 Docker</button>
            </div>
            
            <div class="tab-content">
                <div id="dashboard" class="tab-pane active">
                    <div class="card">
                        <div class="card-header">📋 Activité récente</div>
                        <div class="card-body">
                            <div id="activity-log" class="activity-log"></div>
                        </div>
                    </div>
                </div>
                
                <div id="accounts" class="tab-pane">
                    <div class="card">
                        <div class="card-header">👥 Gestion des comptes</div>
                        <div class="card-body">
                            <div class="content-loader">Chargement...</div>
                            <div id="accounts-table"></div>
                        </div>
                    </div>
                </div>
                
                <div id="licenses" class="tab-pane">
                    <div class="card">
                        <div class="card-header">📄 Gestion des licences</div>
                        <div class="card-body">
                            <div class="content-loader">Chargement...</div>
                            <div id="licenses-table"></div>
                        </div>
                    </div>
                </div>
                
                <div id="scenarios" class="tab-pane">
                    <div class="card">
                        <div class="card-header">🎯 Scénarios de test</div>
                        <div class="card-body">
                            <div class="scenario-grid">
                                <div class="card">
                                    <div class="card-header">🎯 Test expiration licence</div>
                                    <div class="card-body">
                                        <p>Teste le comportement à l'expiration</p>
                                        <button class="btn btn-primary" onclick="ui.runScenario('license_expiry')">▶️ Exécuter</button>
                                    </div>
                                </div>
                                <div class="card">
                                    <div class="card-header">🎯 Montée en gamme</div>
                                    <div class="card-body">
                                        <p>Test passage FREE → PRO</p>
                                        <button class="btn btn-primary" onclick="ui.runScenario('premium_upgrade')">▶️ Exécuter</button>
                                    </div>
                                </div>
                                <div class="card">
                                    <div class="card-header">🎯 Fonctionnalités Enterprise</div>
                                    <div class="card-body">
                                        <p>Test fonctions avancées</p>
                                        <button class="btn btn-primary" onclick="ui.runScenario('enterprise_features')">▶️ Exécuter</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div id="tests" class="tab-pane">
                    <div class="card">
                        <div class="card-header">🧪 Orchestrateur de tests</div>
                        <div class="card-body">
                            <div class="test-suites">
                                <button class="btn btn-success" onclick="ui.runTestSuite('unit')">🧪 Tests unitaires</button>
                                <button class="btn btn-success" onclick="ui.runTestSuite('integration')">🔗 Tests d'intégration</button>
                                <button class="btn btn-success" onclick="ui.runTestSuite('license')">📄 Tests de licence</button>
                                <button class="btn btn-warning" onclick="ui.runTestSuite('performance')">⚡ Tests de performance</button>
                                <button class="btn btn-error" onclick="ui.runTestSuite('security')">🔒 Tests de sécurité</button>
                            </div>
                        </div>
                    </div>
                </div>
                
                <div id="docker" class="tab-pane">
                    <div class="card">
                        <div class="card-header">🐳 Gestion Docker</div>
                        <div class="card-body">
                            <div class="docker-controls">
                                <button class="btn btn-success" onclick="ui.executeAction('start_docker')">▶️ Démarrer services</button>
                                <button class="btn btn-error" onclick="ui.executeAction('stop_docker')">⏹️ Arrêter services</button>
                                <button class="btn btn-secondary" onclick="ui.executeAction('restart_docker')">🔄 Redémarrer</button>
                                <button class="btn btn-secondary" onclick="ui.executeAction('docker_status')">📊 Statut</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </main>

    <script src="/static/script.js"></script>
</body>
</html>
"""
        
        (self.templates_dir / "index.html").write_text(base_template, encoding='utf-8')
    
    def setup_routes(self):
        """Configurer les routes FastAPI"""
        
        # Monter les fichiers statiques
        self.app.mount("/static", StaticFiles(directory=self.static_dir), name="static")
        
        # Templates
        templates = Jinja2Templates(directory=self.templates_dir)
        
        @self.app.get("/", response_class=HTMLResponse)
        async def home(request: Request):
            return templates.TemplateResponse("index.html", {"request": request})
        
        @self.app.get("/api/dashboard")
        async def get_dashboard():
            try:
                accounts = self.account_manager.list_accounts()
                licenses_dir = self.base_dir / "licenses"
                license_count = len(list(licenses_dir.glob("*.lic"))) if licenses_dir.exists() else 0
                
                stats = {
                    "accounts": len(accounts),
                    "licenses": license_count,
                    "scenarios": 6,
                    "tests": "--"
                }
                
                return {"stats": stats}
            except Exception as e:
                return {"error": str(e)}
        
        @self.app.get("/api/accounts")
        async def get_accounts():
            try:
                accounts = self.account_manager.list_accounts()
                return {"accounts": accounts}
            except Exception as e:
                return {"error": str(e)}
        
        @self.app.get("/api/licenses")
        async def get_licenses():
            try:
                licenses = []
                licenses_dir = self.base_dir / "licenses"
                
                if licenses_dir.exists():
                    for license_file in licenses_dir.glob("*.lic"):
                        parts = license_file.stem.split("_")
                        if len(parts) >= 3:
                            user = parts[0] + "@" + parts[1] + "." + parts[2]
                            tier = parts[3] if len(parts) > 3 else "Unknown"
                        else:
                            user = "Unknown"
                            tier = "Unknown"
                        
                        stat = license_file.stat()
                        created = datetime.fromtimestamp(stat.st_ctime).strftime("%Y-%m-%d")
                        
                        licenses.append({
                            "filename": license_file.name,
                            "user": user,
                            "tier": tier,
                            "created": created
                        })
                
                return {"licenses": licenses}
            except Exception as e:
                return {"error": str(e)}
        
        @self.app.post("/api/action")
        async def execute_action(request: Request):
            try:
                data = await request.json()
                action = data.get("action")
                params = data.get("params", {})
                
                result = await self.handle_action(action, params)
                return result
                
            except Exception as e:
                return {"success": False, "error": str(e)}
        
        @self.app.websocket("/ws")
        async def websocket_endpoint(websocket: WebSocket):
            await websocket.accept()
            self.websocket_connections.append(websocket)
            
            try:
                while True:
                    await websocket.receive_text()
            except WebSocketDisconnect:
                self.websocket_connections.remove(websocket)
    
    async def handle_action(self, action: str, params: Dict) -> Dict:
        """Gérer les actions de l'interface"""
        try:
            if action == "quick_setup":
                # Setup environnement
                from config_generator import ConfigGenerator
                generator = ConfigGenerator()
                generator.create_all_configs()
                self.database.setup_complete_test_environment()
                
                await self.broadcast_log("✅ Setup environnement terminé")
                return {"success": True, "message": "Setup terminé"}
            
            elif action == "generate_bruno_license":
                # Générer licence Bruno
                result = self.license_generator.generate_test_license("bruno@taaazzz-prog.fr", "PRO")
                
                if result.get("success"):
                    await self.broadcast_log("✅ Licence PRO générée pour bruno@taaazzz-prog.fr")
                    return {"success": True, "message": "Licence générée"}
                else:
                    await self.broadcast_log(f"❌ Échec génération licence: {result.get('error', 'Unknown')}")
                    return {"success": False, "error": result.get("error", "Unknown")}
            
            elif action == "run_unit_tests":
                # Tests unitaires
                result = self.orchestrator.run_test_suite("unit")
                success_rate = result.get("success_rate", 0)
                
                await self.broadcast_log(f"🧪 Tests unitaires: {success_rate}% réussis")
                return {"success": True, "result": result}
            
            elif action == "start_metrics":
                # Démarrer métriques
                await self.broadcast_log("📊 Simulation métriques démarrée")
                return {"success": True, "message": "Métriques démarrées"}
            
            elif action == "check_docker":
                # Vérifier Docker
                compose_file = self.base_dir / "docker-compose.yml"
                if compose_file.exists():
                    await self.broadcast_log("✅ docker-compose.yml trouvé")
                    return {"success": True, "message": "Docker configuré"}
                else:
                    await self.broadcast_log("❌ docker-compose.yml non trouvé")
                    return {"success": False, "error": "Docker non configuré"}
            
            elif action == "run_scenario":
                # Exécuter scénario
                scenario_id = params.get("scenario_id")
                await self.broadcast_log(f"🎯 Exécution scénario: {scenario_id}")
                
                if hasattr(self.scenarios, f"run_{scenario_id}_test"):
                    method = getattr(self.scenarios, f"run_{scenario_id}_test")
                    result = method()
                    
                    if result.get("success"):
                        await self.broadcast_log(f"✅ Scénario {scenario_id} réussi")
                        return {"success": True, "result": result}
                    else:
                        await self.broadcast_log(f"❌ Scénario {scenario_id} échoué")
                        return {"success": False, "error": result.get("error", "Unknown")}
                else:
                    await self.broadcast_log(f"❌ Scénario {scenario_id} non trouvé")
                    return {"success": False, "error": "Scénario non trouvé"}
            
            elif action == "run_test_suite":
                # Exécuter suite de tests
                suite_id = params.get("suite_id")
                await self.broadcast_log(f"🧪 Exécution suite: {suite_id}")
                
                result = self.orchestrator.run_test_suite(suite_id)
                success_rate = result.get("success_rate", 0)
                
                await self.broadcast_log(f"🧪 Suite {suite_id}: {success_rate}% réussis")
                return {"success": True, "result": result}
            
            else:
                return {"success": False, "error": f"Action inconnue: {action}"}
                
        except Exception as e:
            await self.broadcast_log(f"❌ Erreur action {action}: {e}")
            return {"success": False, "error": str(e)}
    
    async def broadcast_log(self, message: str):
        """Diffuser un log à tous les clients connectés"""
        if self.websocket_connections:
            data = {
                "type": "log",
                "message": message,
                "timestamp": datetime.now().isoformat()
            }
            
            # Envoyer à tous les clients connectés
            disconnected = []
            for websocket in self.websocket_connections:
                try:
                    await websocket.send_text(json.dumps(data))
                except:
                    disconnected.append(websocket)
            
            # Nettoyer les connexions fermées
            for ws in disconnected:
                self.websocket_connections.remove(ws)
    
    def run(self, host: str = "127.0.0.1", port: int = 8000):
        """Lancer le serveur web"""
        print(f"🌐 Interface web disponible sur: http://{host}:{port}")
        uvicorn.run(self.app, host=host, port=port, log_level="info")


def main():
    """Point d'entrée principal"""
    if not FASTAPI_AVAILABLE:
        print("❌ FastAPI non disponible")
        print("💡 Installation: pip install fastapi uvicorn jinja2")
        return
    
    try:
        web_interface = WebTestInterface()
        web_interface.run()
        
    except Exception as e:
        print(f"❌ Erreur inattendue: {e}")


if __name__ == "__main__":
    main()