// ========================================
// FICHIER: ModeManager.js
// RESPONSABILITÉ: Gestionnaire modes exclusifs serveur
// MODES: MANUAL (interface client) | AUTO (traitement batch GSheets)
// ========================================

const { logSh } = require('../ErrorReporting');
const fs = require('fs');
const path = require('path');

/**
 * GESTIONNAIRE MODES EXCLUSIFS
 * Gère le basculement entre mode MANUAL et AUTO de façon exclusive
 */
class ModeManager {
  
  // ========================================
  // CONSTANTES ET ÉTAT
  // ========================================
  static MODES = {
    MANUAL: 'manual',  // Interface client + API + WebSocket
    AUTO: 'auto'       // Traitement batch Google Sheets
  };

  static currentMode = null;
  static isLocked = false;
  static lockReason = null;
  static modeStartTime = null;
  static activeServices = {
    manualServer: null,
    autoProcessor: null,
    websocketServer: null
  };

  // Stats par mode
  static stats = {
    manual: { sessions: 0, requests: 0, lastActivity: null },
    auto: { processed: 0, errors: 0, lastProcessing: null }
  };

  // ========================================
  // INITIALISATION ET DÉTECTION MODE
  // ========================================
  
  /**
   * Initialise le gestionnaire de modes
   * @param {string} initialMode - Mode initial (manual|auto|detect)
   */
  static async initialize(initialMode = 'detect') {
    const startTime = Date.now();
    logSh('🎛️ Initialisation ModeManager...', 'INFO');

    try {
      // Détecter mode selon arguments ou config
      logSh('⏱️ Détection mode...', 'INFO');
      const t1 = Date.now();
      const detectedMode = this.detectIntendedMode(initialMode);
      logSh(`✓ Mode détecté: ${detectedMode.toUpperCase()} en ${Date.now() - t1}ms`, 'INFO');

      // Nettoyer état précédent si nécessaire
      logSh('⏱️ Nettoyage état précédent...', 'INFO');
      const t2 = Date.now();
      await this.cleanupPreviousState();
      logSh(`✓ Nettoyage terminé en ${Date.now() - t2}ms`, 'INFO');

      // Basculer vers le mode détecté
      logSh(`⏱️ Basculement vers mode ${detectedMode.toUpperCase()}...`, 'INFO');
      const t3 = Date.now();
      await this.switchToMode(detectedMode);
      logSh(`✓ Basculement terminé en ${Date.now() - t3}ms`, 'INFO');

      // Sauvegarder état
      logSh('⏱️ Sauvegarde état...', 'INFO');
      const t4 = Date.now();
      this.saveModeState();
      logSh(`✓ État sauvegardé en ${Date.now() - t4}ms`, 'INFO');

      logSh(`✅ ModeManager initialisé en mode ${this.currentMode.toUpperCase()} (total: ${Date.now() - startTime}ms)`, 'INFO');

      return this.currentMode;
      
    } catch (error) {
      logSh(`❌ Erreur initialisation ModeManager: ${error.message}`, 'ERROR');
      throw new Error(`Échec initialisation ModeManager: ${error.message}`);
    }
  }

  /**
   * Détecte le mode souhaité selon arguments CLI et env
   */
  static detectIntendedMode(initialMode) {
    // 1. Argument explicite
    if (initialMode === this.MODES.MANUAL || initialMode === this.MODES.AUTO) {
      return initialMode;
    }
    
    // 2. Arguments de ligne de commande
    const args = process.argv.slice(2);
    const modeArg = args.find(arg => arg.startsWith('--mode='));
    if (modeArg) {
      const mode = modeArg.split('=')[1];
      if (Object.values(this.MODES).includes(mode)) {
        return mode;
      }
    }
    
    // 3. Variable d'environnement
    const envMode = process.env.SERVER_MODE?.toLowerCase();
    if (Object.values(this.MODES).includes(envMode)) {
      return envMode;
    }
    
    // 4. Script npm spécifique
    const npmScript = process.env.npm_lifecycle_event;
    if (npmScript === 'auto') return this.MODES.AUTO;
    
    // 5. Défaut = MANUAL
    return this.MODES.MANUAL;
  }

  // ========================================
  // CHANGEMENT DE MODES
  // ========================================
  
  /**
   * Bascule vers un mode spécifique
   */
  static async switchToMode(targetMode, force = false) {
    if (!Object.values(this.MODES).includes(targetMode)) {
      throw new Error(`Mode invalide: ${targetMode}`);
    }
    
    if (this.currentMode === targetMode) {
      logSh(`Mode ${targetMode} déjà actif`, 'DEBUG');
      return true;
    }
    
    // Vérifier si changement possible
    if (!force && !await this.canSwitchToMode(targetMode)) {
      throw new Error(`Impossible de basculer vers ${targetMode}: ${this.lockReason}`);
    }
    
    logSh(`🔄 Basculement ${this.currentMode || 'NONE'} → ${targetMode}...`, 'INFO');
    
    try {
      // Arrêter mode actuel
      await this.stopCurrentMode();
      
      // Démarrer nouveau mode
      await this.startMode(targetMode);
      
      // Mettre à jour état
      this.currentMode = targetMode;
      this.modeStartTime = Date.now();
      this.lockReason = null;
      
      logSh(`✅ Basculement terminé: Mode ${targetMode.toUpperCase()} actif`, 'INFO');
      
      return true;
      
    } catch (error) {
      logSh(`❌ Échec basculement vers ${targetMode}: ${error.message}`, 'ERROR');
      
      // Tentative de récupération
      try {
        await this.emergencyRecovery();
      } catch (recoveryError) {
        logSh(`❌ Échec récupération d'urgence: ${recoveryError.message}`, 'ERROR');
      }
      
      throw error;
    }
  }

  /**
   * Vérifie si le basculement est possible
   */
  static async canSwitchToMode(targetMode) {
    // Mode verrouillé
    if (this.isLocked) {
      this.lockReason = 'Mode verrouillé pour opération critique';
      return false;
    }
    
    // Vérifications spécifiques par mode
    switch (targetMode) {
      case this.MODES.MANUAL:
        return await this.canSwitchToManual();
        
      case this.MODES.AUTO:
        return await this.canSwitchToAuto();
        
      default:
        return false;
    }
  }

  /**
   * Peut-on basculer vers MANUAL ?
   */
  static async canSwitchToManual() {
    // Si mode AUTO actif, vérifier processus
    if (this.currentMode === this.MODES.AUTO) {
      const autoProcessor = this.activeServices.autoProcessor;
      
      if (autoProcessor && autoProcessor.isProcessing()) {
        this.lockReason = 'Traitement automatique en cours, arrêt requis';
        return false;
      }
    }
    
    return true;
  }

  /**
   * Peut-on basculer vers AUTO ?
   */
  static async canSwitchToAuto() {
    // Si mode MANUAL actif, vérifier clients
    if (this.currentMode === this.MODES.MANUAL) {
      const manualServer = this.activeServices.manualServer;
      
      if (manualServer && manualServer.hasActiveClients()) {
        this.lockReason = 'Clients actifs en mode MANUAL, déconnexion requise';
        return false;
      }
    }
    
    return true;
  }

  // ========================================
  // DÉMARRAGE ET ARRÊT SERVICES
  // ========================================
  
  /**
   * Démarre un mode spécifique
   */
  static async startMode(mode) {
    logSh(`🚀 Démarrage mode ${mode.toUpperCase()}...`, 'DEBUG');
    
    switch (mode) {
      case this.MODES.MANUAL:
        await this.startManualMode();
        break;
        
      case this.MODES.AUTO:
        await this.startAutoMode();
        break;
        
      default:
        throw new Error(`Mode de démarrage inconnu: ${mode}`);
    }
  }

  /**
   * Démarre le mode MANUAL
   */
  static async startManualMode() {
    const t1 = Date.now();
    logSh('⏱️ Chargement module ManualServer...', 'INFO');
    const { ManualServer } = require('./ManualServer');
    logSh(`✓ ManualServer chargé en ${Date.now() - t1}ms`, 'INFO');

    const t2 = Date.now();
    logSh('⏱️ Instanciation ManualServer...', 'INFO');
    this.activeServices.manualServer = new ManualServer();
    logSh(`✓ ManualServer instancié en ${Date.now() - t2}ms`, 'INFO');

    const t3 = Date.now();
    logSh('⏱️ Démarrage ManualServer.start()...', 'INFO');
    await this.activeServices.manualServer.start();
    logSh(`✓ ManualServer.start() terminé en ${Date.now() - t3}ms`, 'INFO');

    logSh('✅ Mode MANUAL démarré', 'INFO');
  }

  /**
   * Démarre le mode AUTO
   */
  static async startAutoMode() {
    const { AutoProcessor } = require('./AutoProcessor');
    
    logSh('🤖 Démarrage AutoProcessor...', 'DEBUG');
    
    this.activeServices.autoProcessor = new AutoProcessor();
    await this.activeServices.autoProcessor.start();
    
    logSh('✅ Mode AUTO démarré', 'DEBUG');
  }

  /**
   * Arrête le mode actuel
   */
  static async stopCurrentMode() {
    if (!this.currentMode) return;
    
    logSh(`🛑 Arrêt mode ${this.currentMode.toUpperCase()}...`, 'DEBUG');
    
    try {
      switch (this.currentMode) {
        case this.MODES.MANUAL:
          await this.stopManualMode();
          break;
          
        case this.MODES.AUTO:
          await this.stopAutoMode();
          break;
      }
      
      logSh(`✅ Mode ${this.currentMode.toUpperCase()} arrêté`, 'DEBUG');
      
    } catch (error) {
      logSh(`⚠️ Erreur arrêt mode ${this.currentMode}: ${error.message}`, 'WARNING');
      // Continue malgré l'erreur pour permettre le changement
    }
  }

  /**
   * Arrête le mode MANUAL
   */
  static async stopManualMode() {
    if (this.activeServices.manualServer) {
      await this.activeServices.manualServer.stop();
      this.activeServices.manualServer = null;
    }
  }

  /**
   * Arrête le mode AUTO
   */
  static async stopAutoMode() {
    if (this.activeServices.autoProcessor) {
      await this.activeServices.autoProcessor.stop();
      this.activeServices.autoProcessor = null;
    }
  }

  // ========================================
  // ÉTAT ET MONITORING
  // ========================================
  
  /**
   * État actuel du gestionnaire
   */
  static getStatus() {
    return {
      currentMode: this.currentMode,
      isLocked: this.isLocked,
      lockReason: this.lockReason,
      modeStartTime: this.modeStartTime,
      uptime: this.modeStartTime ? Date.now() - this.modeStartTime : 0,
      stats: { ...this.stats },
      activeServices: {
        manualServer: !!this.activeServices.manualServer,
        autoProcessor: !!this.activeServices.autoProcessor
      }
    };
  }

  /**
   * Vérifie si mode MANUAL actif
   */
  static isManualMode() {
    return this.currentMode === this.MODES.MANUAL;
  }

  /**
   * Vérifie si mode AUTO actif  
   */
  static isAutoMode() {
    return this.currentMode === this.MODES.AUTO;
  }

  /**
   * Verrouille le mode actuel
   */
  static lockMode(reason = 'Opération critique') {
    this.isLocked = true;
    this.lockReason = reason;
    logSh(`🔒 Mode ${this.currentMode} verrouillé: ${reason}`, 'INFO');
  }

  /**
   * Déverrouille le mode
   */
  static unlockMode() {
    this.isLocked = false;
    this.lockReason = null;
    logSh(`🔓 Mode ${this.currentMode} déverrouillé`, 'INFO');
  }

  // ========================================
  // GESTION ERREURS ET RÉCUPÉRATION
  // ========================================
  
  /**
   * Nettoyage état précédent
   */
  static async cleanupPreviousState() {
    logSh('🧹 Nettoyage état précédent...', 'DEBUG');
    
    // Arrêter tous les services actifs
    await this.stopCurrentMode();
    
    // Reset état
    this.isLocked = false;
    this.lockReason = null;
    
    logSh('✅ Nettoyage terminé', 'DEBUG');
  }

  /**
   * Récupération d'urgence
   */
  static async emergencyRecovery() {
    logSh('🚨 Récupération d\'urgence...', 'WARNING');
    
    try {
      // Forcer arrêt de tous les services
      await this.forceStopAllServices();
      
      // Reset état complet
      this.currentMode = null;
      this.isLocked = false;
      this.lockReason = null;
      this.modeStartTime = null;
      
      logSh('✅ Récupération d\'urgence terminée', 'INFO');
      
    } catch (error) {
      logSh(`❌ Échec récupération d'urgence: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Arrêt forcé de tous les services
   */
  static async forceStopAllServices() {
    const services = Object.keys(this.activeServices);
    
    for (const serviceKey of services) {
      const service = this.activeServices[serviceKey];
      if (service) {
        try {
          if (typeof service.stop === 'function') {
            await service.stop();
          }
        } catch (error) {
          logSh(`⚠️ Erreur arrêt forcé ${serviceKey}: ${error.message}`, 'WARNING');
        }
        this.activeServices[serviceKey] = null;
      }
    }
  }

  // ========================================
  // PERSISTANCE ET CONFIGURATION
  // ========================================
  
  /**
   * Sauvegarde l'état du mode
   */
  static saveModeState() {
    try {
      const stateFile = path.join(__dirname, '../..', 'mode-state.json');
      const state = {
        currentMode: this.currentMode,
        modeStartTime: this.modeStartTime,
        stats: this.stats,
        timestamp: new Date().toISOString()
      };
      
      fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
      
    } catch (error) {
      logSh(`⚠️ Erreur sauvegarde état mode: ${error.message}`, 'WARNING');
    }
  }

  /**
   * Restaure l'état du mode
   */
  static loadModeState() {
    try {
      const stateFile = path.join(__dirname, '../..', 'mode-state.json');
      
      if (fs.existsSync(stateFile)) {
        const state = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
        this.stats = state.stats || this.stats;
        return state;
      }
      
    } catch (error) {
      logSh(`⚠️ Erreur chargement état mode: ${error.message}`, 'WARNING');
    }
    
    return null;
  }
}

// ============= EXPORTS =============
module.exports = { ModeManager };