// ========================================
// SELECTIVE LAYERS - COUCHES COMPOSABLES
// Responsabilité: Stacks prédéfinis et couches adaptatives pour selective enhancement
// Architecture: Composable layers avec orchestration intelligente
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { applySelectiveLayer } = require('./SelectiveCore');

/**
 * STACKS PRÉDÉFINIS SELECTIVE ENHANCEMENT
 */
const PREDEFINED_STACKS = {
  // Stack léger - Amélioration technique uniquement
  lightEnhancement: {
    name: 'lightEnhancement',
    description: 'Amélioration technique légère avec OpenAI',
    layers: [
      { type: 'technical', llm: 'gpt-4o-mini', intensity: 0.7 }
    ],
    layersCount: 1
  },

  // Stack standard - Technique + Transitions
  standardEnhancement: {
    name: 'standardEnhancement',
    description: 'Amélioration technique et style (OpenAI + Mistral)',
    layers: [
      { type: 'technical', llm: 'gpt-4o-mini', intensity: 0.9 },
      { type: 'style', llm: 'mistral-small', intensity: 0.8 }
    ],
    layersCount: 2
  },

  // Stack complet - Toutes couches séquentielles
  fullEnhancement: {
    name: 'fullEnhancement',
    description: 'Enhancement complet multi-LLM (OpenAI + Mistral) - modéré pour éviter sur-stylisation',
    layers: [
      { type: 'technical', llm: 'gpt-4o-mini', intensity: 0.7 },  // ✅ MODÉRÉ: Réduit de 1.0 à 0.7
      { type: 'style', llm: 'mistral-small', intensity: 0.5 }      // ✅ MODÉRÉ: Réduit de 0.8 à 0.5 pour éviter familiarité excessive
    ],
    layersCount: 2
  },

  // Stack personnalité - Style prioritaire
  personalityFocus: {
    name: 'personalityFocus',
    description: 'Focus personnalité et style avec Mistral + technique légère',
    layers: [
      { type: 'style', llm: 'mistral-small', intensity: 1.2 },
      { type: 'technical', llm: 'gpt-4o-mini', intensity: 0.6 }
    ],
    layersCount: 2
  },

  // Stack fluidité - Style prioritaire
  fluidityFocus: {
    name: 'fluidityFocus',
    description: 'Focus style et technique avec Mistral + OpenAI',
    layers: [
      { type: 'style', llm: 'mistral-small', intensity: 1.1 },
      { type: 'technical', llm: 'gpt-4o-mini', intensity: 0.7 }
    ],
    layersCount: 2
  }
};

/**
 * APPLIQUER STACK PRÉDÉFINI
 */
async function applyPredefinedStack(content, stackName, config = {}) {
  return await tracer.run('SelectiveLayers.applyPredefinedStack()', async () => {
    const stack = PREDEFINED_STACKS[stackName];

    if (!stack) {
      throw new Error(`Stack selective prédéfini inconnu: ${stackName}. Disponibles: ${Object.keys(PREDEFINED_STACKS).join(', ')}`);
    }

    await tracer.annotate({
      selectivePredefinedStack: true,
      stackName,
      layersCount: stack.layersCount,
      elementsCount: Object.keys(content).length
    });

    const startTime = Date.now();
    logSh(`📦 APPLICATION STACK SELECTIVE: ${stack.name} (${stack.layersCount} couches)`, 'INFO');
    logSh(`   📊 ${Object.keys(content).length} éléments | Description: ${stack.description}`, 'INFO');

    // 🆕 LOG: Détail des couches configurées dans ce stack
    logSh(`   🔍 Configuration du stack:`, 'INFO');
    stack.layers.forEach((layer, idx) => {
      logSh(`      Couche ${idx + 1}: ${layer.type} | LLM: ${layer.llm} | Intensité: ${layer.intensity}`, 'INFO');
    });

    try {
      let currentContent = content;
      const stackStats = {
        stackName,
        layers: [],
        totalModifications: 0,
        totalDuration: 0,
        success: true
      };

      // Appliquer chaque couche séquentiellement
      for (let i = 0; i < stack.layers.length; i++) {
        const layer = stack.layers[i];

        try {
          logSh(`\n   🔧 === COUCHE ${i + 1}/${stack.layersCount} ===`, 'INFO');
          logSh(`      Type: ${layer.type} | LLM: ${layer.llm} | Intensité: ${layer.intensity}`, 'INFO');
          logSh(`      Éléments en entrée: ${Object.keys(currentContent).length}`, 'DEBUG');

          // 🆕 LOG: Échantillon du contenu avant transformation
          const sampleKey = Object.keys(currentContent)[0];
          const sampleBefore = currentContent[sampleKey]?.substring(0, 100) || 'N/A';
          logSh(`      📝 Échantillon AVANT (${sampleKey}): ${sampleBefore}...`, 'DEBUG');

          // Préparer configuration avec support tendances
          const layerConfig = {
            ...config,
            layerType: layer.type,
            llmProvider: layer.llm,
            intensity: config.intensity ? config.intensity * layer.intensity : layer.intensity,
            analysisMode: true
          };

          // Ajouter tendance si présente
          if (config.trendManager) {
            layerConfig.trendManager = config.trendManager;
            logSh(`      🎯 Tendance active: ${config.trendManager.currentTrendId || 'none'}`, 'DEBUG');
          }

          const layerStartTime = Date.now();
          const layerResult = await applySelectiveLayer(currentContent, layerConfig);
          const layerDuration = Date.now() - layerStartTime;

          currentContent = layerResult.content;

          // 🆕 LOG: Échantillon après transformation
          const sampleAfter = currentContent[sampleKey]?.substring(0, 100) || 'N/A';
          logSh(`      📝 Échantillon APRÈS (${sampleKey}): ${sampleAfter}...`, 'DEBUG');

          // 🆕 LOG: Résultats détaillés de la couche
          const modifications = layerResult.stats.elementsEnhanced;
          const modificationRate = ((modifications / Object.keys(currentContent).length) * 100).toFixed(1);

          stackStats.layers.push({
            order: i + 1,
            type: layer.type,
            llm: layer.llm,
            intensity: layer.intensity,
            elementsEnhanced: modifications,
            duration: layerDuration,
            success: !layerResult.stats.fallback
          });

          stackStats.totalModifications += modifications;
          stackStats.totalDuration += layerDuration;

          logSh(`      ✅ RÉSULTAT: ${modifications} éléments modifiés (${modificationRate}% du total)`, 'INFO');
          logSh(`      ⏱️  Durée: ${layerDuration}ms`, 'DEBUG');
          
        } catch (layerError) {
          logSh(`   ❌ Couche ${layer.type} échouée: ${layerError.message}`, 'ERROR');
          
          stackStats.layers.push({
            order: i + 1,
            type: layer.type,
            llm: layer.llm,
            error: layerError.message,
            duration: 0,
            success: false
          });
          
          // Continuer avec les autres couches
        }
      }
      
      const duration = Date.now() - startTime;
      const successfulLayers = stackStats.layers.filter(l => l.success).length;

      logSh(`\n✅ === STACK SELECTIVE ${stackName} TERMINÉ ===`, 'INFO');
      logSh(`   📊 Couches réussies: ${successfulLayers}/${stack.layersCount}`, 'INFO');
      logSh(`   🔄 Modifications totales: ${stackStats.totalModifications}`, 'INFO');
      logSh(`   ⏱️  Durée totale: ${duration}ms`, 'INFO');

      // 🆕 LOG: Tableau récapitulatif par couche
      logSh(`\n   📋 RÉCAPITULATIF PAR COUCHE:`, 'INFO');
      stackStats.layers.forEach(layer => {
        const status = layer.success ? '✅' : '❌';
        logSh(`      ${status} Couche ${layer.order}: ${layer.type} (${layer.llm}) - ${layer.elementsEnhanced || 0} modifs en ${layer.duration}ms`, 'INFO');
      });

      await tracer.event('Stack selective appliqué', { ...stackStats, totalDuration: duration });
      
      return {
        content: currentContent,
        stats: { ...stackStats, totalDuration: duration },
        modifications: stackStats.totalModifications,  // ✅ AJOUTÉ: Mapping pour PipelineExecutor
        original: content,
        stackApplied: stackName
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ STACK SELECTIVE ${stackName} ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
      
      return {
        content,
        stats: { stackName, error: error.message, duration, success: false },
        original: content,
        fallback: true
      };
    }
  }, { content: Object.keys(content), stackName, config });
}

/**
 * APPLIQUER COUCHES ADAPTATIVES
 */
async function applyAdaptiveLayers(content, config = {}) {
  return await tracer.run('SelectiveLayers.applyAdaptiveLayers()', async () => {
    const {
      maxIntensity = 1.0,
      analysisThreshold = 0.4,
      csvData = null
    } = config;

    await tracer.annotate({
      selectiveAdaptiveLayers: true,
      maxIntensity,
      analysisThreshold,
      elementsCount: Object.keys(content).length
    });

    const startTime = Date.now();
    logSh(`🧠 APPLICATION COUCHES ADAPTATIVES SELECTIVE`, 'INFO');
    logSh(`   📊 ${Object.keys(content).length} éléments | Seuil: ${analysisThreshold}`, 'INFO');

    try {
      // 1. Analyser besoins de chaque type de couche
      const needsAnalysis = await analyzeSelectiveNeeds(content, csvData);
      
      logSh(`   📋 Analyse besoins: Tech=${needsAnalysis.technical.score.toFixed(2)} | Trans=${needsAnalysis.transitions.score.toFixed(2)} | Style=${needsAnalysis.style.score.toFixed(2)}`, 'DEBUG');
      
      // 2. Déterminer couches à appliquer selon scores
      const layersToApply = [];
      
      if (needsAnalysis.technical.needed && needsAnalysis.technical.score > analysisThreshold) {
        layersToApply.push({
          type: 'technical',
          llm: 'gpt-4o-mini',
          intensity: Math.min(maxIntensity, needsAnalysis.technical.score * 1.2),
          priority: 1
        });
      }
      
      // Transitions layer removed - Gemini disabled
      
      if (needsAnalysis.style.needed && needsAnalysis.style.score > analysisThreshold) {
        layersToApply.push({
          type: 'style',
          llm: 'mistral-small', 
          intensity: Math.min(maxIntensity, needsAnalysis.style.score),
          priority: 3
        });
      }
      
      if (layersToApply.length === 0) {
        logSh(`✅ COUCHES ADAPTATIVES: Aucune amélioration nécessaire`, 'INFO');
        return {
          content,
          stats: {
            adaptive: true,
            layersApplied: 0,
            analysisOnly: true,
            duration: Date.now() - startTime
          },
          modifications: 0  // ✅ AJOUTÉ: Mapping pour PipelineExecutor (pas de modifications)
        };
      }
      
      // 3. Appliquer couches par ordre de priorité
      layersToApply.sort((a, b) => a.priority - b.priority);
      logSh(`   🎯 Couches sélectionnées: ${layersToApply.map(l => `${l.type}(${l.intensity.toFixed(1)})`).join(' → ')}`, 'INFO');
      
      let currentContent = content;
      const adaptiveStats = {
        layersAnalyzed: 3,
        layersApplied: layersToApply.length,
        layers: [],
        totalModifications: 0,
        adaptive: true
      };
      
      for (const layer of layersToApply) {
        try {
          logSh(`   🔧 Couche adaptative: ${layer.type} (intensité: ${layer.intensity.toFixed(1)})`, 'DEBUG');
          
          const layerResult = await applySelectiveLayer(currentContent, {
            ...config,
            layerType: layer.type,
            llmProvider: layer.llm,
            intensity: layer.intensity,
            analysisMode: true
          });
          
          currentContent = layerResult.content;
          
          adaptiveStats.layers.push({
            type: layer.type,
            llm: layer.llm,
            intensity: layer.intensity,
            elementsEnhanced: layerResult.stats.elementsEnhanced,
            duration: layerResult.stats.duration,
            success: !layerResult.stats.fallback
          });
          
          adaptiveStats.totalModifications += layerResult.stats.elementsEnhanced;
          
        } catch (layerError) {
          logSh(`   ❌ Couche adaptative ${layer.type} échouée: ${layerError.message}`, 'ERROR');
          
          adaptiveStats.layers.push({
            type: layer.type,
            error: layerError.message,
            success: false
          });
        }
      }
      
      const duration = Date.now() - startTime;
      const successfulLayers = adaptiveStats.layers.filter(l => l.success).length;
      
      logSh(`✅ COUCHES ADAPTATIVES: ${successfulLayers}/${layersToApply.length} appliquées | ${adaptiveStats.totalModifications} modifications (${duration}ms)`, 'INFO');
      
      await tracer.event('Couches adaptatives appliquées', { ...adaptiveStats, totalDuration: duration });
      
      return {
        content: currentContent,
        stats: { ...adaptiveStats, totalDuration: duration },
        modifications: adaptiveStats.totalModifications,  // ✅ AJOUTÉ: Mapping pour PipelineExecutor
        original: content
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ COUCHES ADAPTATIVES ÉCHOUÉES après ${duration}ms: ${error.message}`, 'ERROR');
      
      return {
        content,
        stats: { adaptive: true, error: error.message, duration },
        original: content,
        fallback: true
      };
    }
  }, { content: Object.keys(content), config });
}

/**
 * PIPELINE COUCHES PERSONNALISÉ
 */
async function applyLayerPipeline(content, layerSequence, config = {}) {
  return await tracer.run('SelectiveLayers.applyLayerPipeline()', async () => {
    if (!Array.isArray(layerSequence) || layerSequence.length === 0) {
      throw new Error('Séquence de couches invalide ou vide');
    }

    await tracer.annotate({
      selectiveLayerPipeline: true,
      pipelineLength: layerSequence.length,
      elementsCount: Object.keys(content).length
    });

    const startTime = Date.now();
    logSh(`🔄 PIPELINE COUCHES SELECTIVE PERSONNALISÉ: ${layerSequence.length} étapes`, 'INFO');

    try {
      let currentContent = content;
      const pipelineStats = {
        pipelineLength: layerSequence.length,
        steps: [],
        totalModifications: 0,
        success: true
      };

      for (let i = 0; i < layerSequence.length; i++) {
        const step = layerSequence[i];
        
        try {
          logSh(`   📍 Étape ${i + 1}/${layerSequence.length}: ${step.type} (${step.llm || 'auto'})`, 'DEBUG');
          
          const stepResult = await applySelectiveLayer(currentContent, {
            ...config,
            ...step
          });
          
          currentContent = stepResult.content;
          
          pipelineStats.steps.push({
            order: i + 1,
            ...step,
            elementsEnhanced: stepResult.stats.elementsEnhanced,
            duration: stepResult.stats.duration,
            success: !stepResult.stats.fallback
          });
          
          pipelineStats.totalModifications += stepResult.stats.elementsEnhanced;
          
        } catch (stepError) {
          logSh(`   ❌ Étape ${i + 1} échouée: ${stepError.message}`, 'ERROR');
          
          pipelineStats.steps.push({
            order: i + 1,
            ...step,
            error: stepError.message,
            success: false
          });
        }
      }
      
      const duration = Date.now() - startTime;
      const successfulSteps = pipelineStats.steps.filter(s => s.success).length;
      
      logSh(`✅ PIPELINE SELECTIVE: ${successfulSteps}/${layerSequence.length} étapes | ${pipelineStats.totalModifications} modifications (${duration}ms)`, 'INFO');
      
      await tracer.event('Pipeline selective appliqué', { ...pipelineStats, totalDuration: duration });
      
      return {
        content: currentContent,
        stats: { ...pipelineStats, totalDuration: duration },
        modifications: pipelineStats.totalModifications,  // ✅ AJOUTÉ: Mapping pour PipelineExecutor
        original: content
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ PIPELINE SELECTIVE ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
      
      return {
        content,
        stats: { error: error.message, duration, success: false },
        original: content,
        fallback: true
      };
    }
  }, { content: Object.keys(content), layerSequence, config });
}

// ============= HELPER FUNCTIONS =============

/**
 * Analyser besoins selective enhancement
 */
async function analyzeSelectiveNeeds(content, csvData) {
  const analysis = {
    technical: { needed: false, score: 0, elements: [] },
    transitions: { needed: false, score: 0, elements: [] },
    style: { needed: false, score: 0, elements: [] }
  };
  
  // Analyser chaque élément pour tous types de besoins
  Object.entries(content).forEach(([tag, text]) => {
    // Analyse technique (import depuis SelectiveCore logic)
    const technicalNeed = assessTechnicalNeed(text, csvData);
    if (technicalNeed.score > 0.3) {
      analysis.technical.needed = true;
      analysis.technical.score += technicalNeed.score;
      analysis.technical.elements.push({ tag, score: technicalNeed.score });
    }
    
    // Analyse transitions
    const transitionNeed = assessTransitionNeed(text);
    if (transitionNeed.score > 0.3) {
      analysis.transitions.needed = true;
      analysis.transitions.score += transitionNeed.score;
      analysis.transitions.elements.push({ tag, score: transitionNeed.score });
    }
    
    // Analyse style
    const styleNeed = assessStyleNeed(text, csvData?.personality);
    if (styleNeed.score > 0.3) {
      analysis.style.needed = true;
      analysis.style.score += styleNeed.score;
      analysis.style.elements.push({ tag, score: styleNeed.score });
    }
  });
  
  // Normaliser scores
  const elementCount = Object.keys(content).length;
  analysis.technical.score = analysis.technical.score / elementCount;
  analysis.transitions.score = analysis.transitions.score / elementCount;
  analysis.style.score = analysis.style.score / elementCount;
  
  return analysis;
}

/**
 * Évaluer besoin technique (simplifié de SelectiveCore)
 */
function assessTechnicalNeed(content, csvData) {
  let score = 0;
  
  // Manque de termes techniques spécifiques
  if (csvData?.mc0) {
    const technicalTerms = ['dibond', 'pmma', 'aluminium', 'fraisage', 'impression', 'gravure'];
    const foundTerms = technicalTerms.filter(term => content.toLowerCase().includes(term));
    
    if (foundTerms.length === 0 && content.length > 100) {
      score += 0.4;
    }
  }
  
  // Vocabulaire générique
  const genericWords = ['produit', 'solution', 'service', 'qualité'];
  const genericCount = genericWords.filter(word => content.toLowerCase().includes(word)).length;
  
  if (genericCount > 2) score += 0.3;
  
  return { score: Math.min(1, score) };
}

/**
 * Évaluer besoin transitions (simplifié)
 */
function assessTransitionNeed(content) {
  const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 10);
  if (sentences.length < 2) return { score: 0 };
  
  let score = 0;
  
  // Connecteurs répétitifs
  const connectors = ['par ailleurs', 'en effet', 'de plus'];
  let repetitions = 0;
  
  connectors.forEach(connector => {
    const matches = (content.match(new RegExp(connector, 'gi')) || []);
    if (matches.length > 1) repetitions++;
  });
  
  if (repetitions > 1) score += 0.4;
  
  return { score: Math.min(1, score) };
}

/**
 * Évaluer besoin style (simplifié)
 */
function assessStyleNeed(content, personality) {
  let score = 0;
  
  if (!personality) {
    score += 0.2;
    return { score };
  }
  
  // Style générique
  const personalityWords = (personality.vocabulairePref || '').toLowerCase().split(',');
  const personalityFound = personalityWords.some(word => 
    word.trim() && content.toLowerCase().includes(word.trim())
  );
  
  if (!personalityFound && content.length > 50) score += 0.4;
  
  return { score: Math.min(1, score) };
}

/**
 * Obtenir stacks disponibles
 */
function getAvailableStacks() {
  return Object.values(PREDEFINED_STACKS);
}

module.exports = {
  // Main functions
  applyPredefinedStack,
  applyAdaptiveLayers,
  applyLayerPipeline,
  
  // Utils
  getAvailableStacks,
  analyzeSelectiveNeeds,
  
  // Constants
  PREDEFINED_STACKS
};