// ========================================
// SERVEUR DASHBOARD TESTS - WebSocket + API
// Interface temps réel pour monitoring des tests systématiques
// ========================================

const WebSocket = require('ws');
const express = require('express');
const http = require('http');
const path = require('path');
const fs = require('fs').promises;
const { SystematicTestRunner } = require('../runners/SystematicTestRunner');
const { ModuleTestGenerator } = require('../systematic/ModuleTestGenerator');
const { logSh } = require('../../lib/ErrorReporting');

/**
 * Serveur dashboard avec WebSocket pour tests en temps réel
 */
class TestDashboardServer {
  
  constructor(options = {}) {
    this.port = options.port || 8082;
    this.httpPort = options.httpPort || 8083;
    
    this.server = null;
    this.wss = null;
    this.httpServer = null;
    this.app = null;
    
    this.clients = new Set();
    this.currentTestRun = null;
    this.systemStats = {
      modules: 0,
      tests: 0,
      coverage: 0,
      aiScore: 0,
      status: 'idle'
    };
    
    this.testHistory = [];
  }
  
  /**
   * Démarrage du serveur dashboard
   */
  async start() {
    try {
      logSh(`🚀 Démarrage dashboard tests (WebSocket: ${this.port}, HTTP: ${this.httpPort})`, 'INFO');
      
      // Serveur HTTP pour l'interface
      await this.setupHTTPServer();
      
      // Serveur WebSocket pour communication temps réel
      await this.setupWebSocketServer();
      
      logSh('✅ Dashboard tests opérationnel', 'INFO');
      logSh(`🌐 Interface: http://localhost:${this.httpPort}`, 'INFO');
      logSh(`📡 WebSocket: ws://localhost:${this.port}`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Erreur démarrage dashboard: ${error.message}`, 'ERROR');
      throw error;
    }
  }
  
  /**
   * Configuration du serveur HTTP
   */
  async setupHTTPServer() {
    this.app = express();
    
    // Middleware
    this.app.use(express.json());
    this.app.use(express.static(path.join(__dirname, '.')));
    
    // Routes API
    this.setupAPIRoutes();
    
    // Route principale - dashboard
    this.app.get('/', (req, res) => {
      res.sendFile(path.join(__dirname, 'TestDashboard.html'));
    });
    
    // Démarrage serveur HTTP
    this.httpServer = this.app.listen(this.httpPort, () => {
      logSh(`🌐 Serveur HTTP dashboard démarré sur port ${this.httpPort}`, 'DEBUG');
    });
  }
  
  /**
   * Configuration des routes API
   */
  setupAPIRoutes() {
    // Status système
    this.app.get('/api/status', (req, res) => {
      res.json({
        status: this.systemStats.status,
        stats: this.systemStats,
        clients: this.clients.size,
        currentRun: this.currentTestRun ? this.currentTestRun.id : null,
        timestamp: new Date().toISOString()
      });
    });
    
    // Historique des tests
    this.app.get('/api/history', (req, res) => {
      const limit = parseInt(req.query.limit) || 10;
      res.json({
        history: this.testHistory.slice(-limit),
        total: this.testHistory.length
      });
    });
    
    // Démarrage de tests via API
    this.app.post('/api/run-tests', async (req, res) => {
      const { mode = 'quick' } = req.body;
      
      try {
        await this.runTests(mode);
        res.json({ success: true, message: `Tests ${mode} démarrés` });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });
    
    // Génération de tests
    this.app.post('/api/generate-tests', async (req, res) => {
      try {
        await this.generateTests();
        res.json({ success: true, message: 'Génération de tests démarrée' });
      } catch (error) {
        res.status(500).json({ success: false, error: error.message });
      }
    });
    
    // Arrêt de tests
    this.app.post('/api/stop-tests', (req, res) => {
      this.stopCurrentTests();
      res.json({ success: true, message: 'Arrêt des tests demandé' });
    });
  }
  
  /**
   * Configuration du serveur WebSocket
   */
  async setupWebSocketServer() {
    this.server = http.createServer();
    this.wss = new WebSocket.Server({ server: this.server });
    
    this.wss.on('connection', (ws, req) => {
      this.handleClientConnection(ws, req);
    });
    
    this.server.listen(this.port, () => {
      logSh(`📡 Serveur WebSocket dashboard démarré sur port ${this.port}`, 'DEBUG');
    });
  }
  
  /**
   * Gestion des connexions WebSocket
   */
  handleClientConnection(ws, req) {
    const clientId = `client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    
    logSh(`🔌 Client connecté: ${clientId}`, 'DEBUG');
    this.clients.add(ws);
    
    // Envoi de l'état initial
    this.sendToClient(ws, {
      type: 'connection_established',
      clientId,
      timestamp: new Date().toISOString()
    });
    
    this.sendToClient(ws, {
      type: 'system_stats',
      stats: this.systemStats
    });
    
    // Gestion des messages clients
    ws.on('message', (message) => {
      try {
        const data = JSON.parse(message);
        this.handleClientMessage(ws, data);
      } catch (error) {
        logSh(`⚠️ Message client invalide: ${error.message}`, 'WARNING');
      }
    });
    
    // Déconnexion client
    ws.on('close', () => {
      this.clients.delete(ws);
      logSh(`🔌 Client déconnecté: ${clientId}`, 'DEBUG');
    });
    
    ws.on('error', (error) => {
      logSh(`❌ Erreur WebSocket client: ${error.message}`, 'ERROR');
      this.clients.delete(ws);
    });
  }
  
  /**
   * Gestion des messages des clients
   */
  async handleClientMessage(ws, data) {
    try {
      switch (data.action) {
        case 'run_tests':
          await this.runTests(data.mode || 'quick');
          break;
          
        case 'generate_tests':
          await this.generateTests();
          break;
          
        case 'stop_tests':
          this.stopCurrentTests();
          break;
          
        case 'get_status':
          this.sendToClient(ws, {
            type: 'system_stats',
            stats: this.systemStats
          });
          break;
          
        default:
          logSh(`⚠️ Action inconnue: ${data.action}`, 'WARNING');
      }
    } catch (error) {
      logSh(`❌ Erreur traitement message client: ${error.message}`, 'ERROR');
      this.sendToClient(ws, {
        type: 'error',
        message: error.message
      });
    }
  }
  
  /**
   * Exécution des tests avec monitoring
   */
  async runTests(mode) {
    if (this.currentTestRun && this.currentTestRun.active) {
      throw new Error('Des tests sont déjà en cours');
    }
    
    const runId = `run_${Date.now()}`;
    this.currentTestRun = {
      id: runId,
      mode,
      startTime: new Date(),
      active: true,
      progress: 0
    };
    
    this.systemStats.status = 'running';
    
    // Notification clients
    this.broadcast({
      type: 'test_started',
      runId,
      mode,
      timestamp: new Date().toISOString()
    });
    
    logSh(`🧪 Démarrage tests ${mode} (${runId})`, 'INFO');
    
    try {
      // Exécution avec callbacks de progression
      const results = await this.runTestsWithProgress(mode);
      
      // Finalisation
      this.currentTestRun.active = false;
      this.currentTestRun.endTime = new Date();
      this.currentTestRun.results = results;
      
      this.systemStats.status = 'idle';
      this.updateSystemStats(results);
      
      // Sauvegarde historique
      this.testHistory.push({
        ...this.currentTestRun,
        summary: {
          modules: results.overview.totalModules,
          passed: results.overview.successful,
          failed: results.overview.failed,
          duration: results.overview.duration
        }
      });
      
      // Notification clients
      this.broadcast({
        type: 'test_completed',
        runId,
        results: results.overview,
        timestamp: new Date().toISOString()
      });
      
      logSh(`✅ Tests terminés (${runId}): ${results.overview.successful}/${results.overview.totalModules}`, 'INFO');
      
    } catch (error) {
      this.currentTestRun.active = false;
      this.currentTestRun.error = error.message;
      this.systemStats.status = 'error';
      
      logSh(`❌ Erreur tests (${runId}): ${error.message}`, 'ERROR');
      
      this.broadcast({
        type: 'test_error',
        runId,
        error: error.message,
        timestamp: new Date().toISOString()
      });
      
      throw error;
    }
  }
  
  /**
   * Exécution avec callbacks de progression
   */
  async runTestsWithProgress(mode) {
    const progressCallback = (progress, message, moduleData) => {
      this.currentTestRun.progress = progress;
      
      this.broadcast({
        type: 'test_progress',
        runId: this.currentTestRun.id,
        progress,
        message,
        module: moduleData ? moduleData.name : null,
        status: moduleData ? moduleData.status : null,
        timestamp: new Date().toISOString()
      });
    };
    
    const validationCallback = (module, validation) => {
      this.broadcast({
        type: 'validation_result',
        runId: this.currentTestRun.id,
        module,
        validation,
        timestamp: new Date().toISOString()
      });
    };
    
    // Hooks personnalisés pour SystematicTestRunner
    const options = {
      progressCallback,
      validationCallback,
      mode
    };
    
    if (mode === 'quick') {
      return await SystematicTestRunner.runQuick(options);
    } else {
      return await SystematicTestRunner.runDetailed(options);
    }
  }
  
  /**
   * Génération de tests
   */
  async generateTests() {
    logSh('🔧 Génération des tests démarrée', 'INFO');
    
    this.broadcast({
      type: 'log',
      level: 'INFO',
      message: 'Génération automatique des tests démarrée',
      timestamp: new Date().toISOString()
    });
    
    try {
      const results = await ModuleTestGenerator.generateAllTests();
      
      this.systemStats.tests = results.modules.reduce((sum, m) => sum + m.testCount, 0);
      this.systemStats.modules = results.generated;
      
      this.broadcast({
        type: 'generation_completed',
        results: {
          generated: results.generated,
          errors: results.errors,
          totalTests: this.systemStats.tests
        },
        timestamp: new Date().toISOString()
      });
      
      logSh(`✅ Génération terminée: ${results.generated} modules, ${this.systemStats.tests} tests`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Erreur génération: ${error.message}`, 'ERROR');
      
      this.broadcast({
        type: 'generation_error',
        error: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Arrêt des tests en cours
   */
  stopCurrentTests() {
    if (this.currentTestRun && this.currentTestRun.active) {
      this.currentTestRun.active = false;
      this.currentTestRun.stopped = true;
      this.systemStats.status = 'stopping';
      
      logSh(`🛑 Arrêt des tests demandé (${this.currentTestRun.id})`, 'INFO');
      
      this.broadcast({
        type: 'test_stopped',
        runId: this.currentTestRun.id,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Mise à jour des statistiques système
   */
  updateSystemStats(results) {
    if (results && results.overview) {
      this.systemStats.modules = results.overview.totalModules || 0;
      this.systemStats.coverage = results.overview.coverage || 0;
      
      // Calcul score IA moyen
      if (results.phases && results.phases.aiValidation && results.phases.aiValidation.validations) {
        const validations = Object.values(results.phases.aiValidation.validations);
        const scores = validations.filter(v => v.overall).map(v => v.overall);
        this.systemStats.aiScore = scores.length > 0 
          ? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length) 
          : 0;
      }
    }
    
    this.broadcast({
      type: 'system_stats',
      stats: this.systemStats
    });
  }
  
  /**
   * Communication WebSocket
   */
  sendToClient(ws, data) {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify(data));
    }
  }
  
  broadcast(data) {
    this.clients.forEach(client => {
      this.sendToClient(client, data);
    });
  }
  
  /**
   * Arrêt du serveur
   */
  async stop() {
    logSh('🛑 Arrêt du serveur dashboard', 'INFO');
    
    // Arrêt des tests en cours
    this.stopCurrentTests();
    
    // Fermeture connexions WebSocket
    this.clients.forEach(client => {
      client.close();
    });
    
    // Arrêt serveurs
    if (this.wss) {
      this.wss.close();
    }
    
    if (this.server) {
      this.server.close();
    }
    
    if (this.httpServer) {
      this.httpServer.close();
    }
    
    logSh('✅ Dashboard arrêté', 'INFO');
  }
  
  /**
   * État du serveur
   */
  getStatus() {
    return {
      running: !!this.server && !!this.httpServer,
      clients: this.clients.size,
      ports: {
        websocket: this.port,
        http: this.httpPort
      },
      currentRun: this.currentTestRun,
      stats: this.systemStats,
      uptime: process.uptime()
    };
  }
}

// Exécution directe pour tests
if (require.main === module) {
  const dashboard = new TestDashboardServer();
  
  dashboard.start()
    .then(() => {
      console.log('🎯 Dashboard de tests démarré avec succès!');
      console.log(`🌐 Interface: http://localhost:${dashboard.httpPort}`);
      
      // Gestion arrêt propre
      process.on('SIGINT', async () => {
        console.log('\n🛑 Arrêt du dashboard...');
        await dashboard.stop();
        process.exit(0);
      });
    })
    .catch(error => {
      console.error('💥 Erreur démarrage dashboard:', error.message);
      process.exit(1);
    });
}

module.exports = { TestDashboardServer };