// ========================================
// FICHIER: StepExecutor.js
// RESPONSABILITÉ: Exécution des étapes modulaires
// ========================================

const { logSh } = require('./ErrorReporting');
const { validateElement, hasUnresolvedPlaceholders } = require('./ValidationGuards');

/**
 * EXECUTEUR D'ÉTAPES MODULAIRES
 * Execute les différents systèmes étape par étape avec stats détaillées
 */
class StepExecutor {
  constructor() {
    // Mapping des systèmes vers leurs exécuteurs
    this.systems = {
      'initial-generation': this.executeInitialGeneration.bind(this),
      'selective': this.executeSelective.bind(this),
      'adversarial': this.executeAdversarial.bind(this),
      'human-simulation': this.executeHumanSimulation.bind(this),
      'pattern-breaking': this.executePatternBreaking.bind(this)
    };
    
    logSh('🎯 StepExecutor initialisé', 'DEBUG');
  }

  // ========================================
  // INTERFACE PRINCIPALE
  // ========================================
  
  /**
   * Execute une étape spécifique
   */
  async executeStep(system, inputData, options = {}) {
    const startTime = Date.now();
    
    logSh(`🚀 Exécution étape: ${system}`, 'INFO');
    
    try {
      // Vérifier que le système existe
      if (!this.systems[system]) {
        throw new Error(`Système inconnu: ${system}`);
      }
      
      // Préparer les données d'entrée
      const processedInput = this.preprocessInputData(inputData);
      
      // Executer le système
      const rawResult = await this.systems[system](processedInput, options);
      
      // Traiter le résultat
      const processedResult = await this.postprocessResult(rawResult, system);
      
      const duration = Date.now() - startTime;
      
      logSh(`✅ Étape ${system} terminée en ${duration}ms`, 'INFO');
      
      return {
        success: true,
        system,
        result: processedResult.content,
        formatted: this.formatOutput(processedResult.content, 'tag'),
        xmlFormatted: this.formatOutput(processedResult.content, 'xml'),
        stats: {
          duration,
          tokensUsed: processedResult.tokensUsed || 0,
          cost: processedResult.cost || 0,
          llmCalls: processedResult.llmCalls || [],
          system: system,
          timestamp: Date.now()
        }
      };
    } catch (error) {
      const duration = Date.now() - startTime;
      
      logSh(`❌ Erreur étape ${system}: ${error.message}`, 'ERROR');
      
      return {
        success: false,
        system,
        error: error.message,
        stats: {
          duration,
          system: system,
          timestamp: Date.now(),
          error: true
        }
      };
    }
  }

  // ========================================
  // EXÉCUTEURS SPÉCIFIQUES
  // ========================================

  /**
   * Construire la structure de contenu depuis la hiérarchie réelle
   */
  buildContentStructureFromHierarchy(inputData, hierarchy) {
    logSh(`🏗️ BUILD CONTENT STRUCTURE - Début`, 'INFO');
    logSh(`   📊 Input: mc0="${inputData.mc0}"`, 'DEBUG');
    logSh(`   📊 Hiérarchie: ${hierarchy ? Object.keys(hierarchy).length : 0} sections`, 'DEBUG');

    const contentStructure = {};

    // Si hiérarchie disponible, l'utiliser
    if (hierarchy && Object.keys(hierarchy).length > 0) {
      logSh(`🔍 Hiérarchie reçue: ${Object.keys(hierarchy).length} sections`, 'INFO');
      logSh(`🔍 Première section sample: ${JSON.stringify(Object.values(hierarchy)[0]).substring(0, 200)}`, 'DEBUG');

      let validationErrors = 0;
      let elementCount = 0;

      Object.entries(hierarchy).forEach(([path, section], sectionIndex) => {
        logSh(`📂 SECTION [${sectionIndex + 1}/${Object.keys(hierarchy).length}] path="${path}"`, 'DEBUG');

        // Générer pour le titre si présent
        if (section.title && section.title.originalElement) {
          elementCount++;

          // ✅ SOLUTION D: Validation guard avant utilisation
          try {
            validateElement(section.title.originalElement, {
              strict: true,
              checkInstructions: true,
              context: `StepExecutor buildContent - path: ${path} (title)`
            });
          } catch (validationError) {
            validationErrors++;
            logSh(`⚠️ Validation échouée pour titre [${section.title.originalElement.name}]: ${validationError.message}`, 'WARNING');
            // Ne pas bloquer, utiliser fallback
          }

          const tag = section.title.originalElement.name;
          const instruction = section.title.instructions || section.title.originalElement.instructions || `Rédige un titre pour ${inputData.mc0}`;

          // 📊 LOG: Détailler l'instruction extraite
          logSh(`   📌 TITRE [${elementCount}] tag="${tag}"`, 'DEBUG');
          logSh(`      🔹 section.title.instructions: "${section.title.instructions ? section.title.instructions.substring(0, 80) : 'NULL'}"`, 'DEBUG');
          logSh(`      🔹 section.title.originalElement.instructions: "${section.title.originalElement.instructions ? section.title.originalElement.instructions.substring(0, 80) : 'NULL'}"`, 'DEBUG');
          logSh(`      ➡️  INSTRUCTION FINALE: "${instruction.substring(0, 100)}"`, 'INFO');

          // ✅ Double-vérification des instructions avant ajout
          const instructionCheck = hasUnresolvedPlaceholders(instruction);
          if (instructionCheck.hasIssues) {
            logSh(`⚠️ Instruction pour [${tag}] contient des placeholders: ${instructionCheck.placeholders.join(', ')}`, 'WARNING');
          }

          contentStructure[tag] = instruction;
        }

        // Générer pour le texte si présent
        if (section.text && section.text.originalElement) {
          elementCount++;

          // ✅ SOLUTION D: Validation guard
          try {
            validateElement(section.text.originalElement, {
              strict: true,
              checkInstructions: true,
              context: `StepExecutor buildContent - path: ${path} (text)`
            });
          } catch (validationError) {
            validationErrors++;
            logSh(`⚠️ Validation échouée pour texte [${section.text.originalElement.name}]: ${validationError.message}`, 'WARNING');
          }

          const tag = section.text.originalElement.name;
          const instruction = section.text.instructions || section.text.originalElement.instructions || `Rédige du contenu sur ${inputData.mc0}`;

          // 📊 LOG: Détailler l'instruction extraite
          logSh(`   📌 TEXTE [${elementCount}] tag="${tag}"`, 'DEBUG');
          logSh(`      🔹 section.text.instructions: "${section.text.instructions ? section.text.instructions.substring(0, 80) : 'NULL'}"`, 'DEBUG');
          logSh(`      🔹 section.text.originalElement.instructions: "${section.text.originalElement.instructions ? section.text.originalElement.instructions.substring(0, 80) : 'NULL'}"`, 'DEBUG');
          logSh(`      ➡️  INSTRUCTION FINALE: "${instruction.substring(0, 100)}"`, 'INFO');

          const instructionCheck = hasUnresolvedPlaceholders(instruction);
          if (instructionCheck.hasIssues) {
            logSh(`⚠️ Instruction pour [${tag}] contient des placeholders: ${instructionCheck.placeholders.join(', ')}`, 'WARNING');
          }

          contentStructure[tag] = instruction;
        }

        // Générer pour les questions FAQ si présentes
        if (section.questions && section.questions.length > 0) {
          section.questions.forEach(q => {
            if (q.originalElement) {
              // ✅ SOLUTION D: Validation guard
              try {
                validateElement(q.originalElement, {
                  strict: true,
                  checkInstructions: true,
                  context: `StepExecutor buildContent - path: ${path} (question)`
                });
              } catch (validationError) {
                validationErrors++;
                logSh(`⚠️ Validation échouée pour question [${q.originalElement.name}]: ${validationError.message}`, 'WARNING');
              }

              const tag = q.originalElement.name;
              const instruction = q.instructions || q.originalElement.instructions || `Rédige une question/réponse FAQ sur ${inputData.mc0}`;

              const instructionCheck = hasUnresolvedPlaceholders(instruction);
              if (instructionCheck.hasIssues) {
                logSh(`⚠️ Instruction pour [${tag}] contient des placeholders: ${instructionCheck.placeholders.join(', ')}`, 'WARNING');
              }

              contentStructure[tag] = instruction;
            }
          });
        }
      });

      if (validationErrors > 0) {
        logSh(`⚠️ ${validationErrors} erreurs de validation détectées lors de la construction de la structure`, 'WARNING');
        logSh(`💡 Cela indique que MissingKeywords.js n'a pas correctement synchronisé resolvedContent et instructions`, 'WARNING');
      }

      logSh(`✅ STRUCTURE CONSTRUITE: ${Object.keys(contentStructure).length} éléments prêts pour génération`, 'INFO');
      logSh(`📊 RÉSUMÉ INSTRUCTIONS:`, 'INFO');

      // 📊 LOG: Afficher toutes les instructions finales
      Object.entries(contentStructure).forEach(([tag, instruction], idx) => {
        const shortInstr = instruction.length > 80 ? instruction.substring(0, 80) + '...' : instruction;
        logSh(`   [${idx + 1}] ${tag}: "${shortInstr}"`, 'INFO');
      });
    } else {
      // Fallback: structure générique si pas de hiérarchie
      logSh(`⚠️ Pas de hiérarchie, utilisation structure générique`, 'WARNING');
      contentStructure['Titre_H1'] = `Rédige un titre H1 accrocheur et optimisé SEO sur ${inputData.mc0}`;
      contentStructure['Introduction'] = `Rédige une introduction engageante qui présente ${inputData.mc0}`;
      contentStructure['Contenu_Principal'] = `Développe le contenu principal détaillé sur ${inputData.mc0} avec des informations utiles et techniques`;
      contentStructure['Conclusion'] = `Rédige une conclusion percutante qui encourage à l'action pour ${inputData.mc0}`;
    }

    return contentStructure;
  }

  /**
   * Execute Initial Generation
   */
  async executeInitialGeneration(inputData, options = {}) {
    try {
      const { InitialGenerationLayer } = require('./generation/InitialGeneration');
      
      logSh('🎯 Démarrage Génération Initiale', 'DEBUG');

      const config = {
        temperature: options.temperature || 0.7,
        maxTokens: options.maxTokens || 4000
      };

      // Créer la structure de contenu à générer depuis la hiérarchie réelle
      // La hiérarchie peut être dans inputData.hierarchy OU options.hierarchy
      const hierarchy = options.hierarchy || inputData.hierarchy;
      const contentStructure = this.buildContentStructureFromHierarchy(inputData, hierarchy);

      logSh(`📊 Structure construite: ${Object.keys(contentStructure).length} éléments depuis hiérarchie`, 'DEBUG');
      
      const initialGenerator = new InitialGenerationLayer();
      const result = await initialGenerator.apply(contentStructure, {
        ...config,
        csvData: inputData,
        llmProvider: 'claude'
      });
      
      return {
        content: result.content || result,
        tokensUsed: result.stats?.tokensUsed || 200,
        cost: (result.stats?.tokensUsed || 200) * 0.00002,
        llmCalls: [
          { provider: 'claude', tokens: result.stats?.tokensUsed || 200, cost: 0.004, phase: 'initial_generation' }
        ],
        phases: {
          initialGeneration: result.stats
        },
        beforeAfter: {
          before: contentStructure,
          after: result.content
        }
      };
    } catch (error) {
      logSh(`❌ Erreur Initial Generation: ${error.message}`, 'ERROR');
      
      return this.createFallbackContent('initial-generation', inputData, error);
    }
  }

  /**
   * Execute Selective Enhancement
   */
  async executeSelective(inputData, options = {}) {
    try {
      // Import dynamique pour éviter les dépendances circulaires
      const { applyPredefinedStack } = require('./selective-enhancement/SelectiveLayers');
      
      logSh('🎯 Démarrage Selective Enhancement seulement', 'DEBUG');
      
      const config = {
        selectiveStack: options.selectiveStack || 'standardEnhancement',
        temperature: options.temperature || 0.7,
        maxTokens: options.maxTokens || 3000
      };
      
      // Vérifier si on a du contenu à améliorer
      let contentToEnhance = null;
      
      if (options.inputContent && Object.keys(options.inputContent).length > 0) {
        // Utiliser le contenu fourni
        contentToEnhance = options.inputContent;
      } else {
        // Fallback: créer un contenu basique pour le test
        logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING');
        contentToEnhance = {
          'Titre_H1': inputData.t0 || 'Titre principal',
          'Introduction': `Contenu sur ${inputData.mc0}`,
          'Contenu_Principal': `Développement du sujet ${inputData.mc0}`,
          'Conclusion': `Conclusion sur ${inputData.mc0}`
        };
      }
      
      const beforeContent = JSON.parse(JSON.stringify(contentToEnhance)); // Deep copy
      
      // ÉTAPE ENHANCEMENT - Améliorer le contenu fourni avec la stack spécifiée
      logSh(`🎯 Enhancement sélectif du contenu avec stack: ${config.selectiveStack}`, 'DEBUG');
      const result = await applyPredefinedStack(contentToEnhance, config.selectiveStack, {
        csvData: inputData,
        analysisMode: false
      });
      
      return {
        content: result.content || result,
        tokensUsed: result.tokensUsed || 300,
        cost: (result.tokensUsed || 300) * 0.00002,
        llmCalls: result.llmCalls || [
          { provider: 'gpt4', tokens: 100, cost: 0.002, phase: 'technical_enhancement' },
          { provider: 'gemini', tokens: 100, cost: 0.001, phase: 'transition_enhancement' },
          { provider: 'mistral', tokens: 100, cost: 0.0005, phase: 'style_enhancement' }
        ],
        phases: {
          selectiveEnhancement: result.stats
        },
        beforeAfter: {
          before: beforeContent,
          after: result.content || result
        }
      };
    } catch (error) {
      logSh(`❌ Erreur Selective: ${error.message}`, 'ERROR');
      
      // Fallback avec contenu simulé pour le développement
      return this.createFallbackContent('selective', inputData, error);
    }
  }
  
  /**
   * Execute Adversarial Generation
   */
  async executeAdversarial(inputData, options = {}) {
    try {
      const { applyPredefinedStack: applyAdversarialStack } = require('./adversarial-generation/AdversarialLayers');
      
      logSh('🎯 Démarrage Adversarial Generation', 'DEBUG');
      
      const config = {
        adversarialMode: options.adversarialMode || 'standard',
        temperature: options.temperature || 1.0,
        antiDetectionLevel: options.antiDetectionLevel || 'medium'
      };
      
      // Vérifier si on a du contenu à transformer
      let contentToTransform = null;
      
      if (options.inputContent && Object.keys(options.inputContent).length > 0) {
        contentToTransform = options.inputContent;
      } else {
        // Fallback: créer un contenu basique pour le test
        logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING');
        contentToTransform = {
          'Titre_H1': inputData.t0 || 'Titre principal',
          'Introduction': `Contenu sur ${inputData.mc0}`,
          'Contenu_Principal': `Développement du sujet ${inputData.mc0}`,
          'Conclusion': `Conclusion sur ${inputData.mc0}`
        };
      }
      
      const beforeContent = JSON.parse(JSON.stringify(contentToTransform)); // Deep copy
      
      // Mapping des modes vers les stacks prédéfinies
      const modeToStack = {
        'light': 'lightDefense',
        'standard': 'standardDefense',
        'heavy': 'heavyDefense',
        'none': 'none',
        'adaptive': 'adaptive'
      };

      const stackName = modeToStack[config.adversarialMode] || 'standardDefense';
      logSh(`🎯 Adversarial avec stack: ${stackName} (mode: ${config.adversarialMode})`, 'DEBUG');

      const result = await applyAdversarialStack(contentToTransform, stackName, {
        csvData: inputData,
        detectorTarget: config.detectorTarget || 'general',
        intensity: config.intensity || 1.0
      });
      
      return {
        content: result.content || result,
        tokensUsed: result.tokensUsed || 200,
        cost: (result.tokensUsed || 200) * 0.00002,
        llmCalls: result.llmCalls || [
          { provider: 'claude', tokens: 100, cost: 0.002, phase: 'adversarial_generation' },
          { provider: 'mistral', tokens: 100, cost: 0.0005, phase: 'adversarial_enhancement' }
        ],
        phases: {
          adversarialGeneration: result.stats
        },
        beforeAfter: {
          before: beforeContent,
          after: result.content || result
        }
      };
    } catch (error) {
      logSh(`❌ Erreur Adversarial: ${error.message}`, 'ERROR');
      
      return this.createFallbackContent('adversarial', inputData, error);
    }
  }
  
  /**
   * Execute Human Simulation
   */
  async executeHumanSimulation(inputData, options = {}) {
    try {
      const { applyPredefinedSimulation } = require('./human-simulation/HumanSimulationLayers');
      
      logSh('🎯 Démarrage Human Simulation', 'DEBUG');
      
      const config = {
        humanSimulationMode: options.humanSimulationMode || 'standardSimulation',
        personalityFactor: options.personalityFactor || 0.7,
        fatigueLevel: options.fatigueLevel || 'medium'
      };
      
      // Vérifier si on a du contenu à humaniser
      let contentToHumanize = null;
      
      if (options.inputContent && Object.keys(options.inputContent).length > 0) {
        contentToHumanize = options.inputContent;
      } else {
        // Fallback: créer un contenu basique pour le test
        logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING');
        contentToHumanize = {
          'Titre_H1': inputData.t0 || 'Titre principal',
          'Introduction': `Contenu sur ${inputData.mc0}`,
          'Contenu_Principal': `Développement du sujet ${inputData.mc0}`,
          'Conclusion': `Conclusion sur ${inputData.mc0}`
        };
      }
      
      const beforeContent = JSON.parse(JSON.stringify(contentToHumanize)); // Deep copy
      
      const simulationMode = config.humanSimulationMode || 'standardSimulation';
      logSh(`🎯 Human Simulation avec mode: ${simulationMode}`, 'DEBUG');

      const result = await applyPredefinedSimulation(contentToHumanize, simulationMode, {
        csvData: inputData,
        ...config
      });
      
      return {
        content: result.content || result,
        tokensUsed: result.tokensUsed || 180,
        cost: (result.tokensUsed || 180) * 0.00002,
        llmCalls: result.llmCalls || [
          { provider: 'gemini', tokens: 90, cost: 0.0009, phase: 'human_simulation' },
          { provider: 'claude', tokens: 90, cost: 0.0018, phase: 'personality_application' }
        ],
        phases: {
          humanSimulation: result.stats
        },
        beforeAfter: {
          before: beforeContent,
          after: result.content || result
        }
      };
    } catch (error) {
      logSh(`❌ Erreur Human Simulation: ${error.message}`, 'ERROR');
      
      return this.createFallbackContent('human-simulation', inputData, error);
    }
  }
  
  /**
   * Execute Pattern Breaking
   */
  async executePatternBreaking(inputData, options = {}) {
    try {
      const { applyPatternBreakingStack } = require('./pattern-breaking/PatternBreakingLayers');
      
      logSh('🎯 Démarrage Pattern Breaking', 'DEBUG');
      
      const config = {
        patternBreakingMode: options.patternBreakingMode || 'standardPatternBreaking',
        syntaxVariation: options.syntaxVariation || 0.6,
        connectorDiversity: options.connectorDiversity || 0.8
      };
      
      // Vérifier si on a du contenu à transformer
      let contentToTransform = null;
      
      if (options.inputContent && Object.keys(options.inputContent).length > 0) {
        contentToTransform = options.inputContent;
      } else {
        // Fallback: créer un contenu basique pour le test
        logSh('⚠️ Pas de contenu d\'entrée, création d\'un contenu basique pour test', 'WARNING');
        contentToTransform = {
          'Titre_H1': inputData.t0 || 'Titre principal',
          'Introduction': `Contenu sur ${inputData.mc0}`,
          'Contenu_Principal': `Développement du sujet ${inputData.mc0}`,
          'Conclusion': `Conclusion sur ${inputData.mc0}`
        };
      }
      
      const beforeContent = JSON.parse(JSON.stringify(contentToTransform)); // Deep copy
      
      const patternMode = config.patternBreakingMode || 'standardPatternBreaking';
      logSh(`🎯 Pattern Breaking avec mode: ${patternMode}`, 'DEBUG');

      const result = await applyPatternBreakingStack(contentToTransform, patternMode, {
        csvData: inputData,
        ...config
      });
      
      return {
        content: result.content || result,
        tokensUsed: result.tokensUsed || 120,
        cost: (result.tokensUsed || 120) * 0.00002,
        llmCalls: result.llmCalls || [
          { provider: 'gpt4', tokens: 60, cost: 0.0012, phase: 'pattern_analysis' },
          { provider: 'mistral', tokens: 60, cost: 0.0003, phase: 'pattern_breaking' }
        ],
        phases: {
          patternBreaking: result.stats
        },
        beforeAfter: {
          before: beforeContent,
          after: result.content || result
        }
      };
    } catch (error) {
      logSh(`❌ Erreur Pattern Breaking: ${error.message}`, 'ERROR');
      
      return this.createFallbackContent('pattern-breaking', inputData, error);
    }
  }

  // ========================================
  // HELPERS ET FORMATAGE
  // ========================================
  
  /**
   * Préprocesse les données d'entrée
   */
  preprocessInputData(inputData) {
    return {
      mc0: inputData.mc0 || 'mot-clé principal',
      t0: inputData.t0 || 'titre principal',
      mcPlus1: inputData.mcPlus1 || '',
      tPlus1: inputData.tPlus1 || '',
      personality: inputData.personality || { nom: 'Test', style: 'neutre' },
      xmlTemplate: inputData.xmlTemplate || this.getDefaultTemplate(),
      // Ajout d'un contexte pour les modules
      context: {
        timestamp: Date.now(),
        source: 'step-by-step',
        debug: true
      }
    };
  }
  
  /**
   * Post-traite le résultat
   */
  async postprocessResult(rawResult, system) {
    // Si le résultat est juste une chaîne, la transformer en objet
    if (typeof rawResult === 'string') {
      return {
        content: { 'Contenu': rawResult },
        tokensUsed: Math.floor(rawResult.length / 4), // Estimation
        cost: 0.001,
        llmCalls: [{ provider: 'unknown', tokens: 50, cost: 0.001 }]
      };
    }
    
    // Si c'est déjà un objet structuré, le retourner tel quel
    if (rawResult && typeof rawResult === 'object') {
      return rawResult;
    }
    
    // Fallback
    return {
      content: { 'Résultat': String(rawResult) },
      tokensUsed: 50,
      cost: 0.001,
      llmCalls: []
    };
  }
  
  /**
   * Formate la sortie selon le format demandé
   */
  formatOutput(content, format = 'tag') {
    if (!content || typeof content !== 'object') {
      return String(content || 'Pas de contenu');
    }
    
    switch (format) {
      case 'tag':
        return Object.entries(content)
          .map(([tag, text]) => `[${tag}]\n${text}`)
          .join('\n\n');
          
      case 'xml':
        return Object.entries(content)
          .map(([tag, text]) => `<${tag.toLowerCase()}>${text}</${tag.toLowerCase()}>`)
          .join('\n');
          
      case 'json':
        return JSON.stringify(content, null, 2);
        
      default:
        return this.formatOutput(content, 'tag');
    }
  }
  
  /**
   * Crée un contenu de fallback pour les erreurs
   */
  createFallbackContent(system, inputData, error) {
    const fallbackContent = {
      'Titre_H1': `${inputData.t0} - Traité par ${system}`,
      'Introduction': `Contenu généré en mode ${system} pour "${inputData.mc0}".`,
      'Contenu_Principal': `Ceci est un contenu de démonstration pour le système ${system}. 
        En production, ce contenu serait généré par l'IA avec les paramètres spécifiés.`,
      'Note_Technique': `⚠️ Mode fallback activé - Erreur: ${error.message}`
    };
    
    return {
      content: fallbackContent,
      tokensUsed: 100,
      cost: 0.002,
      llmCalls: [
        { provider: 'fallback', tokens: 100, cost: 0.002, error: error.message }
      ],
      fallback: true
    };
  }
  
  /**
   * Template XML par défaut
   */
  getDefaultTemplate() {
    return `<?xml version="1.0" encoding="UTF-8"?>
<article>
  <h1>|Titre_H1{{T0}}{Titre principal optimisé}|</h1>
  <intro>|Introduction{{MC0}}{Introduction engageante}|</intro>
  <content>|Contenu_Principal{{MC0,T0}}{Contenu principal détaillé}|</content>
  <conclusion>|Conclusion{{T0}}{Conclusion percutante}|</conclusion>
</article>`;
  }
}

module.exports = {
  StepExecutor
};