// ========================================
// ADVERSARIAL CORE - MOTEUR MODULAIRE
// Responsabilité: Moteur adversarial réutilisable sur tout contenu
// Architecture: Couches applicables à la demande
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { callLLM } = require('../LLMManager');

// Import stratégies et utilitaires
const { DetectorStrategyFactory, selectOptimalStrategy } = require('./DetectorStrategies');

/**
 * MAIN ENTRY POINT - APPLICATION COUCHE ADVERSARIALE
 * Input: contenu existant + configuration adversariale
 * Output: contenu avec couche adversariale appliquée
 */
async function applyAdversarialLayer(existingContent, config = {}) {
  return await tracer.run('AdversarialCore.applyAdversarialLayer()', async () => {
    const {
      detectorTarget = 'general',
      intensity = 1.0,
      method = 'regeneration', // 'regeneration' | 'enhancement' | 'hybrid'
      preserveStructure = true,
      csvData = null,
      context = {},
      llmProvider = 'gemini-pro'  // ✅ AJOUTÉ: Extraction llmProvider avec fallback
    } = config;

    await tracer.annotate({
      adversarialLayer: true,
      detectorTarget,
      intensity,
      method,
      llmProvider,
      elementsCount: Object.keys(existingContent).length
    });

    const startTime = Date.now();
    logSh(`🎯 APPLICATION COUCHE ADVERSARIALE: ${detectorTarget} (${method})`, 'INFO');
    logSh(`   📊 ${Object.keys(existingContent).length} éléments | Intensité: ${intensity} | LLM: ${llmProvider}`, 'INFO');

    try {
      // Initialiser stratégie détecteur  
      const strategy = DetectorStrategyFactory.createStrategy(detectorTarget);
      
      // Appliquer méthode adversariale choisie avec LLM spécifié
      let adversarialContent = {};
      const methodConfig = { ...config, llmProvider };  // ✅ Assurer propagation llmProvider

      switch (method) {
        case 'regeneration':
          adversarialContent = await applyRegenerationMethod(existingContent, methodConfig, strategy);
          break;
        case 'enhancement':
          adversarialContent = await applyEnhancementMethod(existingContent, methodConfig, strategy);
          break;
        case 'hybrid':
          adversarialContent = await applyHybridMethod(existingContent, methodConfig, strategy);
          break;
        default:
          throw new Error(`Méthode adversariale inconnue: ${method}`);
      }

      const duration = Date.now() - startTime;
      const stats = {
        elementsProcessed: Object.keys(existingContent).length,
        elementsModified: countModifiedElements(existingContent, adversarialContent),
        detectorTarget,
        intensity,
        method,
        duration
      };

      logSh(`✅ COUCHE ADVERSARIALE APPLIQUÉE: ${stats.elementsModified}/${stats.elementsProcessed} modifiés (${duration}ms)`, 'INFO');

      await tracer.event('Couche adversariale appliquée', stats);

      return {
        content: adversarialContent,
        stats,
        modifications: stats.elementsModified,  // ✅ AJOUTÉ: Mapping pour PipelineExecutor
        original: existingContent,
        config
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ COUCHE ADVERSARIALE ÉCHOUÉE après ${duration}ms: ${error.message}`, 'ERROR');
      
      // Fallback: retourner contenu original
      logSh(`🔄 Fallback: contenu original conservé`, 'WARNING');
      return {
        content: existingContent,
        stats: { fallback: true, duration },
        original: existingContent,
        config,
        error: error.message
      };
    }
  }, { existingContent: Object.keys(existingContent), config });
}

/**
 * MÉTHODE RÉGÉNÉRATION - Réécrire complètement avec prompts adversariaux
 */
async function applyRegenerationMethod(existingContent, config, strategy) {
  const llmToUse = config.llmProvider || 'gemini-pro';
  logSh(`🔄 Méthode régénération adversariale (LLM: ${llmToUse})`, 'DEBUG');

  const results = {};
  const contentEntries = Object.entries(existingContent);

  // Traiter en chunks pour éviter timeouts
  const chunks = chunkArray(contentEntries, 4);

  for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
    const chunk = chunks[chunkIndex];
    logSh(`   📦 Régénération chunk ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG');

    try {
      const regenerationPrompt = createRegenerationPrompt(chunk, config, strategy);

      const response = await callLLM(llmToUse, regenerationPrompt, {
        temperature: 0.7 + (config.intensity * 0.2), // Température variable selon intensité
        maxTokens: 2000 * chunk.length
      }, config.csvData?.personality);
      
      const chunkResults = parseRegenerationResponse(response, chunk);
      Object.assign(results, chunkResults);
      
      logSh(`   ✅ Chunk ${chunkIndex + 1}: ${Object.keys(chunkResults).length} éléments régénérés`, 'DEBUG');
      
      // Délai entre chunks
      if (chunkIndex < chunks.length - 1) {
        await sleep(1500);
      }
      
    } catch (error) {
      logSh(`   ❌ Chunk ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR');
      
      // Fallback: garder contenu original pour ce chunk
      chunk.forEach(([tag, content]) => {
        results[tag] = content;
      });
    }
  }
  
  return results;
}

/**
 * MÉTHODE ENHANCEMENT - Améliorer sans réécrire complètement
 */
async function applyEnhancementMethod(existingContent, config, strategy) {
  const llmToUse = config.llmProvider || 'gemini-pro';
  logSh(`🔧 Méthode enhancement adversarial (LLM: ${llmToUse})`, 'DEBUG');

  const results = { ...existingContent }; // Base: contenu original
  const elementsToEnhance = selectElementsForEnhancement(existingContent, config);

  if (elementsToEnhance.length === 0) {
    logSh(`   ⏭️ Aucun élément nécessite enhancement`, 'DEBUG');
    return results;
  }

  logSh(`   📋 ${elementsToEnhance.length} éléments sélectionnés pour enhancement`, 'DEBUG');

  const enhancementPrompt = createEnhancementPrompt(elementsToEnhance, config, strategy);

  try {
    const response = await callLLM(llmToUse, enhancementPrompt, {
      temperature: 0.5 + (config.intensity * 0.3),
      maxTokens: 3000
    }, config.csvData?.personality);
    
    const enhancedResults = parseEnhancementResponse(response, elementsToEnhance);
    
    // Appliquer améliorations
    Object.keys(enhancedResults).forEach(tag => {
      if (enhancedResults[tag] !== existingContent[tag]) {
        results[tag] = enhancedResults[tag];
      }
    });
    
    return results;
    
  } catch (error) {
    logSh(`❌ Enhancement échoué: ${error.message}`, 'ERROR');
    return results; // Fallback: contenu original
  }
}

/**
 * MÉTHODE HYBRIDE - Combinaison régénération + enhancement
 */
async function applyHybridMethod(existingContent, config, strategy) {
  logSh(`⚡ Méthode hybride adversariale`, 'DEBUG');
  
  // 1. Enhancement léger sur tout le contenu
  const enhancedContent = await applyEnhancementMethod(existingContent, {
    ...config,
    intensity: config.intensity * 0.6 // Intensité réduite pour enhancement
  }, strategy);
  
  // 2. Régénération ciblée sur éléments clés
  const keyElements = selectKeyElementsForRegeneration(enhancedContent, config);
  
  if (keyElements.length === 0) {
    return enhancedContent;
  }
  
  const keyElementsContent = {};
  keyElements.forEach(tag => {
    keyElementsContent[tag] = enhancedContent[tag];
  });
  
  const regeneratedElements = await applyRegenerationMethod(keyElementsContent, {
    ...config,
    intensity: config.intensity * 1.2 // Intensité augmentée pour régénération
  }, strategy);
  
  // 3. Merger résultats
  const hybridContent = { ...enhancedContent };
  Object.keys(regeneratedElements).forEach(tag => {
    hybridContent[tag] = regeneratedElements[tag];
  });
  
  return hybridContent;
}

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

/**
 * Créer prompt de régénération adversariale
 */
function createRegenerationPrompt(chunk, config, strategy) {
  const { detectorTarget, intensity, csvData } = config;
  
  let prompt = `MISSION: Réécris ces contenus pour éviter détection par ${detectorTarget}.

TECHNIQUE ANTI-${detectorTarget.toUpperCase()}:
${strategy.getInstructions(intensity).join('\n')}

CONTENUS À RÉÉCRIRE:

${chunk.map(([tag, content], i) => `[${i + 1}] TAG: ${tag}
ORIGINAL: "${content}"`).join('\n\n')}

CONSIGNES:
- GARDE exactement le même message et informations factuelles
- CHANGE structure, vocabulaire, style pour éviter détection ${detectorTarget}
- Intensité adversariale: ${intensity.toFixed(2)}
${csvData?.personality ? `- Style: ${csvData.personality.nom} (${csvData.personality.style})` : ''}

IMPORTANT: Réponse DIRECTE par les contenus réécrits, pas d'explication.

FORMAT:
[1] Contenu réécrit anti-${detectorTarget}
[2] Contenu réécrit anti-${detectorTarget}
etc...`;

  return prompt;
}

/**
 * Créer prompt d'enhancement adversarial
 */
function createEnhancementPrompt(elementsToEnhance, config, strategy) {
  const { detectorTarget, intensity } = config;
  
  let prompt = `MISSION: Améliore subtilement ces contenus pour réduire détection ${detectorTarget}.

AMÉLIORATIONS CIBLÉES:
${strategy.getEnhancementTips(intensity).join('\n')}

ÉLÉMENTS À AMÉLIORER:

${elementsToEnhance.map((element, i) => `[${i + 1}] TAG: ${element.tag}
CONTENU: "${element.content}"
PROBLÈME: ${element.detectionRisk}`).join('\n\n')}

CONSIGNES:
- Modifications LÉGÈRES et naturelles
- GARDE le fond du message intact
- Focus sur réduction détection ${detectorTarget}
- Intensité: ${intensity.toFixed(2)}

FORMAT:
[1] Contenu légèrement amélioré
[2] Contenu légèrement amélioré
etc...`;

  return prompt;
}

/**
 * Parser réponse régénération
 */
function parseRegenerationResponse(response, chunk) {
  const results = {};
  const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
  let match;
  const parsedItems = {};
  
  while ((match = regex.exec(response)) !== null) {
    const index = parseInt(match[1]) - 1;
    const content = cleanAdversarialContent(match[2].trim());
    if (index >= 0 && index < chunk.length) {
      parsedItems[index] = content;
    }
  }
  
  // Mapper aux vrais tags
  chunk.forEach(([tag, originalContent], index) => {
    if (parsedItems[index] && parsedItems[index].length > 10) {
      results[tag] = parsedItems[index];
    } else {
      results[tag] = originalContent; // Fallback
      logSh(`⚠️ Fallback régénération pour [${tag}]`, 'WARNING');
    }
  });
  
  return results;
}

/**
 * Parser réponse enhancement
 */
function parseEnhancementResponse(response, elementsToEnhance) {
  const results = {};
  const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
  let match;
  let index = 0;
  
  while ((match = regex.exec(response)) && index < elementsToEnhance.length) {
    let enhancedContent = cleanAdversarialContent(match[2].trim());
    const element = elementsToEnhance[index];
    
    if (enhancedContent && enhancedContent.length > 10) {
      results[element.tag] = enhancedContent;
    } else {
      results[element.tag] = element.content; // Fallback
    }
    
    index++;
  }
  
  return results;
}

/**
 * Sélectionner éléments pour enhancement
 */
function selectElementsForEnhancement(existingContent, config) {
  const elements = [];
  
  Object.entries(existingContent).forEach(([tag, content]) => {
    const detectionRisk = assessDetectionRisk(content, config.detectorTarget);
    
    if (detectionRisk.score > 0.6) { // Risque élevé
      elements.push({
        tag,
        content,
        detectionRisk: detectionRisk.reasons.join(', '),
        priority: detectionRisk.score
      });
    }
  });
  
  // Trier par priorité (risque élevé en premier)
  elements.sort((a, b) => b.priority - a.priority);
  
  return elements;
}

/**
 * Sélectionner éléments clés pour régénération (hybride)
 */
function selectKeyElementsForRegeneration(content, config) {
  const keyTags = [];
  
  Object.keys(content).forEach(tag => {
    // Éléments clés: titres, intro, premiers paragraphes
    if (tag.includes('Titre') || tag.includes('H1') || tag.includes('intro') || 
        tag.includes('Introduction') || tag.includes('1')) {
      keyTags.push(tag);
    }
  });
  
  return keyTags.slice(0, 3); // Maximum 3 éléments clés
}

/**
 * Évaluer risque de détection
 */
function assessDetectionRisk(content, detectorTarget) {
  let score = 0;
  const reasons = [];
  
  // Indicateurs génériques de contenu IA
  const aiWords = ['optimal', 'comprehensive', 'seamless', 'robust', 'leverage', 'cutting-edge'];
  const aiCount = aiWords.reduce((count, word) => {
    return count + (content.toLowerCase().includes(word) ? 1 : 0);
  }, 0);
  
  if (aiCount > 2) {
    score += 0.4;
    reasons.push('mots_typiques_ia');
  }
  
  // Structure trop parfaite
  const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 10);
  if (sentences.length > 2) {
    const avgLength = sentences.reduce((sum, s) => sum + s.length, 0) / sentences.length;
    const variance = sentences.reduce((sum, s) => sum + Math.pow(s.length - avgLength, 2), 0) / sentences.length;
    const uniformity = 1 - (Math.sqrt(variance) / avgLength);
    
    if (uniformity > 0.8) {
      score += 0.3;
      reasons.push('structure_uniforme');
    }
  }
  
  // Spécifique selon détecteur
  if (detectorTarget === 'gptZero') {
    // GPTZero détecte la prévisibilité
    if (content.includes('par ailleurs') && content.includes('en effet')) {
      score += 0.3;
      reasons.push('connecteurs_prévisibles');
    }
  }
  
  return { score: Math.min(1, score), reasons };
}

/**
 * Nettoyer contenu adversarial généré
 */
function cleanAdversarialContent(content) {
  if (!content) return content;
  
  // Supprimer préfixes indésirables
  content = content.replace(/^(voici\s+)?le\s+contenu\s+(réécrit|amélioré)[:\s]*/gi, '');
  content = content.replace(/^(bon,?\s*)?(alors,?\s*)?/gi, '');
  content = content.replace(/\*\*[^*]+\*\*/g, '');
  content = content.replace(/\s{2,}/g, ' ');
  content = content.trim();
  
  return content;
}

/**
 * Compter éléments modifiés
 */
function countModifiedElements(original, modified) {
  let count = 0;
  
  Object.keys(original).forEach(tag => {
    if (modified[tag] && modified[tag] !== original[tag]) {
      count++;
    }
  });
  
  return count;
}

/**
 * Chunk array utility
 */
function chunkArray(array, size) {
  const chunks = [];
  for (let i = 0; i < array.length; i += size) {
    chunks.push(array.slice(i, i + size));
  }
  return chunks;
}

/**
 * Sleep utility
 */
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

module.exports = {
  applyAdversarialLayer,            // ← MAIN ENTRY POINT MODULAIRE
  applyRegenerationMethod,
  applyEnhancementMethod,
  applyHybridMethod,
  assessDetectionRisk,
  selectElementsForEnhancement
};