// ========================================
// FICHIER: lib/element-extraction.js - CONVERTI POUR NODE.JS
// Description: Extraction et parsing des éléments XML
// ========================================

// 🔄 NODE.JS IMPORTS
const { logSh } = require('./ErrorReporting');
const { logElementsList } = require('./selective-enhancement/SelectiveUtils');

// ============= EXTRACTION PRINCIPALE =============

async function extractElements(xmlTemplate, csvData) {
  try {
    await logSh('Extraction éléments avec séparation tag/contenu...', 'DEBUG');
    
    const regex = /\|([^|]+)\|/g;
    const elements = [];
    let match;
    
    while ((match = regex.exec(xmlTemplate)) !== null) {
      const originalMatch = match[1];
      let fullMatch = match[1]; // Ex: "Titre_H1_1{{T0}}" ou "Titre_H3_3{{MC+1_3}}"

      // RÉPARER les variables cassées par les balises HTML AVANT de les chercher
      // Ex: <strong>{{</strong>MC+1_1}} → {{MC+1_1}}
      fullMatch = fullMatch
        .replace(/<strong>\{\{<\/strong>/g, '{{')
        .replace(/<strong>\{<\/strong>/g, '{')
        .replace(/<code><strong>\{\{<\/strong><\/code>/g, '{{')
        .replace(/<strong><strong>\{\{<\/strong>/g, '{{')
        .replace(/<\/strong>\}\}<\/strong>/g, '}}')
        .replace(/<\/strong>\}<\/strong>/g, '}')
        .replace(/<\/strong>/g, '')  // Enlever </strong> orphelins
        .replace(/<strong>/g, '')    // Enlever <strong> orphelins
        .replace(/<code>/g, '')      // Enlever <code> orphelins
        .replace(/<\/code>/g, '');   // Enlever </code> orphelins

      // Log debug si changement
      if (originalMatch !== fullMatch && originalMatch.includes('{{')) {
        await logSh(`   🔧 Réparation HTML: "${originalMatch.substring(0, 80)}" → "${fullMatch.substring(0, 80)}"`, 'DEBUG');
      }

      // Séparer nom du tag et variables
      const nameMatch = fullMatch.match(/^([^{]+)/);
      let tagName = nameMatch ? nameMatch[1].trim() : fullMatch.split('{')[0];
      tagName = tagName.replace(/<\/?strong>/g, ''); // Nettoyage

      const variablesMatch = fullMatch.match(/\{\{([^}]+)\}\}/g);

      // CAPTURER les instructions EN GARDANT les {{variables}} intactes
      // Stratégie : d'abord enlever temporairement toutes les {{variables}},
      // trouver la position de {instruction}, puis revenir au texte original
      let instructionsMatch = null;

      // Créer une version sans {{variables}} pour trouver où est {instruction}
      const withoutVars = fullMatch.replace(/\{\{[^}]+\}\}/g, '');
      const tempInstructionMatch = withoutVars.match(/\{([^}]+)\}/);

      if (tempInstructionMatch) {
        // On a trouvé une instruction dans la version sans variables
        // Trouver le PREMIER { qui n'est PAS suivi de { (= début instruction)
        let instructionStart = -1;
        for (let idx = 0; idx < fullMatch.length - 1; idx++) {
          if (fullMatch[idx] === '{' && fullMatch[idx + 1] !== '{') {
            instructionStart = idx;
            break;
          }
        }

        if (instructionStart !== -1) {
          // Capturer jusqu'à la } de fermeture (en ignorant les }} de variables)
          let depth = 0;
          let instructionEnd = -1;
          let i = instructionStart;

          while (i < fullMatch.length) {
            if (fullMatch[i] === '{') {
              if (fullMatch[i+1] === '{') {
                // C'est une variable, skip les deux {
                i += 2;
                continue;
              } else {
                depth++;
              }
            } else if (fullMatch[i] === '}') {
              if (fullMatch[i+1] === '}') {
                // Fin de variable, skip les deux }
                i += 2;
                continue;
              } else {
                depth--;
                if (depth === 0) {
                  instructionEnd = i;
                  break;
                }
              }
            }
            i++;
          }

          if (instructionEnd !== -1) {
            const instructionContent = fullMatch.substring(instructionStart + 1, instructionEnd);
            instructionsMatch = [fullMatch.substring(instructionStart, instructionEnd + 1), instructionContent];

            // Log debug instruction capturée
            await logSh(`   📜 Instruction capturée (${tagName}): ${instructionContent.substring(0, 80)}...`, 'DEBUG');
          }
        }
      }

      // TAG PUR (sans variables)
      const pureTag = `|${tagName}|`;
      
      // RÉSOUDRE le contenu des variables
      const resolvedContent = resolveVariablesContent(variablesMatch, csvData);

      // RÉSOUDRE aussi les variables DANS les instructions
      let resolvedInstructions = instructionsMatch ? instructionsMatch[1] : null;
      if (resolvedInstructions) {
        const originalInstruction = resolvedInstructions;
        // Remplacer chaque variable {{XX}} par sa valeur résolue
        resolvedInstructions = resolvedInstructions.replace(/\{\{([^}]+)\}\}/g, (match, variable) => {
          const singleVarMatch = [match];
          return resolveVariablesContent(singleVarMatch, csvData);
        });
        // Log si changement
        if (originalInstruction !== resolvedInstructions && originalInstruction.includes('{{')) {
          await logSh(`   ✨ Instructions résolues (${tagName}): ${originalInstruction.substring(0, 60)} → ${resolvedInstructions.substring(0, 60)}`, 'DEBUG');
        }
      }

      elements.push({
        originalTag: pureTag,                    // ← TAG PUR : |Titre_H3_3|
        name: tagName,                          // ← Titre_H3_3
        variables: variablesMatch || [],        // ← [{{MC+1_3}}]
        resolvedContent: resolvedContent,       // ← "Plaque de rue en aluminium"
        instructions: resolvedInstructions,     // ← Instructions avec variables résolues
        type: getElementType(tagName),
        originalFullMatch: fullMatch            // ← Backup si besoin
      });
      
      await logSh(`Tag séparé: ${pureTag} → "${resolvedContent}"`, 'DEBUG');
    }

    await logSh(`${elements.length} éléments extraits avec séparation`, 'INFO');

    // 📊 DÉTAIL DES ÉLÉMENTS EXTRAITS
    logElementsList(elements, 'ÉLÉMENTS EXTRAITS (depuis XML + Google Sheets)');

    return elements;
    
  } catch (error) {
    await logSh(`Erreur extractElements: ${error}`, 'ERROR');
    return [];
  }
}

// ============= RÉSOLUTION VARIABLES - IDENTIQUE =============

function resolveVariablesContent(variablesMatch, csvData) {
  if (!variablesMatch || variablesMatch.length === 0) {
    return ""; // Pas de variables à résoudre
  }
  
  let resolvedContent = "";
  
  variablesMatch.forEach(variable => {
    const cleanVar = variable.replace(/[{}]/g, ''); // Enlever {{ }}
    
    switch (cleanVar) {
      case 'T0':
        resolvedContent += csvData.t0;
        break;
      case 'MC0':
        resolvedContent += csvData.mc0;
        break;
      case 'T-1':
        resolvedContent += csvData.tMinus1;
        break;
      case 'L-1':
        resolvedContent += csvData.lMinus1;
        break;
      default:
        // Gérer MC+1_1, MC+1_2, etc.
        if (cleanVar.startsWith('MC+1_')) {
          const index = parseInt(cleanVar.split('_')[1]) - 1;
          const mcPlus1 = csvData.mcPlus1.split(',').map(s => s.trim());
          resolvedContent += mcPlus1[index] || `[${cleanVar} non défini]`;
        }
        else if (cleanVar.startsWith('T+1_')) {
          const index = parseInt(cleanVar.split('_')[1]) - 1;
          const tPlus1 = csvData.tPlus1.split(',').map(s => s.trim());
          resolvedContent += tPlus1[index] || `[${cleanVar} non défini]`;
        }
        else if (cleanVar.startsWith('L+1_')) {
          const index = parseInt(cleanVar.split('_')[1]) - 1;
          const lPlus1 = csvData.lPlus1.split(',').map(s => s.trim());
          resolvedContent += lPlus1[index] || `[${cleanVar} non défini]`;
        }
        else {
          resolvedContent += `[${cleanVar} non résolu]`;
        }
        break;
    }
  });
  
  return resolvedContent;
}

// ============= CLASSIFICATION ÉLÉMENTS - IDENTIQUE =============

function getElementType(name) {
  if (name.includes('Titre_H1')) return 'titre_h1';
  if (name.includes('Titre_H2')) return 'titre_h2';
  if (name.includes('Titre_H3')) return 'titre_h3';
  if (name.includes('Intro_')) return 'intro';
  if (name.includes('Txt_')) return 'texte';
  if (name.includes('Faq_q')) return 'faq_question';
  if (name.includes('Faq_a')) return 'faq_reponse';
  if (name.includes('Faq_H3')) return 'faq_titre';
  return 'autre';
}

// ============= GÉNÉRATION SÉQUENTIELLE - ADAPTÉE =============

async function generateAllContent(elements, csvData, xmlTemplate) {
  await logSh(`Début génération pour ${elements.length} éléments`, 'INFO');
  
  const generatedContent = {};
  
  for (let index = 0; index < elements.length; index++) {
    const element = elements[index];
    
    try {
      await logSh(`Élément ${index + 1}/${elements.length}: ${element.name}`, 'DEBUG');

      const prompt = createPromptForElement(element, csvData);

      // 🔄 NODE.JS : Import callOpenAI depuis LLM manager (le prompt/réponse seront loggés par LLMManager)
      const { callLLM } = require('./LLMManager');
      const content = await callLLM('gpt-4o-mini', prompt, {}, csvData.personality);
      
      generatedContent[element.originalTag] = content;
      
      // 🔄 NODE.JS : Pas de Utilities.sleep(), les appels API gèrent leur rate limiting
      
    } catch (error) {
      await logSh(`ERREUR élément ${element.name}: ${error.toString()}`, 'ERROR');
      generatedContent[element.originalTag] = `[Erreur génération: ${element.name}]`;
    }
  }
  
  await logSh(`Génération terminée. ${Object.keys(generatedContent).length} éléments`, 'INFO');
  return generatedContent;
}

// ============= PARSING STRUCTURE - IDENTIQUE =============

function parseElementStructure(element) {
  // NETTOYER le nom : enlever <strong>, </strong>, {{...}}, {...}
  let cleanName = element.name
    .replace(/<\/?strong>/g, '')  // ← ENLEVER <strong>
    .replace(/\{\{[^}]*\}\}/g, '') // Enlever {{MC0}}
    .replace(/\{[^}]*\}/g, '');    // Enlever {instructions}
  
  const parts = cleanName.split('_');
  
  return {
    type: parts[0],        
    level: parts[1],       
    indices: parts.slice(2).map(Number),
    hierarchyPath: parts.slice(1).join('_'),
    originalElement: element,
    variables: element.variables || [],
    instructions: element.instructions
  };
}

// ============= HIÉRARCHIE INTELLIGENTE - ADAPTÉE =============

async function buildSmartHierarchy(elements) {
  await logSh(`🏗️ CONSTRUCTION HIÉRARCHIE - Début avec ${elements.length} éléments`, 'INFO');

  const hierarchy = {};

  elements.forEach((element, index) => {
    const structure = parseElementStructure(element);
    const path = structure.hierarchyPath;

    // 📊 LOG: Détailler chaque élément traité
    logSh(`   [${index + 1}/${elements.length}] ${element.name}`, 'DEBUG');
    logSh(`      📍 Path: ${path}`, 'DEBUG');
    logSh(`      📝 Type: ${structure.type}`, 'DEBUG');
    logSh(`      📄 ResolvedContent: "${element.resolvedContent}"`, 'DEBUG');
    logSh(`      📜 Instructions: "${element.instructions ? element.instructions.substring(0, 80) : 'AUCUNE'}"`, 'DEBUG');

    if (!hierarchy[path]) {
      hierarchy[path] = {
        title: null,
        text: null,
        questions: [],
        children: {}
      };
    }

    // Associer intelligemment
    if (structure.type === 'Titre') {
      hierarchy[path].title = structure; // Tout l'objet avec variables + instructions
      logSh(`      ✅ Assigné comme TITRE dans hiérarchie[${path}].title`, 'DEBUG');
    } else if (structure.type === 'Txt') {
      hierarchy[path].text = structure;
      logSh(`      ✅ Assigné comme TEXTE dans hiérarchie[${path}].text`, 'DEBUG');
    } else if (structure.type === 'Intro') {
      hierarchy[path].text = structure;
      logSh(`      ✅ Assigné comme INTRO dans hiérarchie[${path}].text`, 'DEBUG');
    } else if (structure.type === 'Faq') {
      hierarchy[path].questions.push(structure);
      logSh(`      ✅ Ajouté comme FAQ dans hiérarchie[${path}].questions`, 'DEBUG');
    }
  });

  // 📊 LOG: Résumé de la hiérarchie construite
  const mappingSummary = Object.keys(hierarchy).map(path => {
    const section = hierarchy[path];
    return `${path}:[T:${section.title ? '✓' : '✗'} Txt:${section.text ? '✓' : '✗'} FAQ:${section.questions.length}]`;
  }).join(' | ');

  await logSh(`📊 HIÉRARCHIE CONSTRUITE: ${Object.keys(hierarchy).length} sections`, 'INFO');
  await logSh(`   ${mappingSummary}`, 'INFO');

  // 📊 LOG: Détail complet d'une section exemple
  const firstPath = Object.keys(hierarchy)[0];
  if (firstPath) {
    const firstSection = hierarchy[firstPath];
    await logSh(`📋 EXEMPLE SECTION [${firstPath}]:`, 'DEBUG');
    if (firstSection.title) {
      await logSh(`   📌 Title.instructions: "${firstSection.title.instructions ? firstSection.title.instructions.substring(0, 100) : 'AUCUNE'}"`, 'DEBUG');
    }
    if (firstSection.text) {
      await logSh(`   📌 Text.instructions: "${firstSection.text.instructions ? firstSection.text.instructions.substring(0, 100) : 'AUCUNE'}"`, 'DEBUG');
    }
  }

  return hierarchy;
}

// ============= PARSERS RÉPONSES - ADAPTÉS =============

async function parseTitlesResponse(response, allTitles) {
  const results = {};
  
  // Utiliser regex pour extraire [TAG] contenu
  const regex = /\[([^\]]+)\]\s*\n([^[]*?)(?=\n\[|$)/gs;
  let match;
  
  while ((match = regex.exec(response)) !== null) {
    const tag = match[1].trim();
    const content = match[2].trim();
    
    // Nettoyer le contenu (enlever # et balises HTML si présentes)
    const cleanContent = content
      .replace(/^#+\s*/, '')  // Enlever # du début
      .replace(/<\/?[^>]+(>|$)/g, ""); // Enlever balises HTML
    
    results[`|${tag}|`] = cleanContent;
    
    await logSh(`✓ Titre parsé [${tag}]: "${cleanContent}"`, 'DEBUG');
  }
  
  // Fallback si parsing échoue
  if (Object.keys(results).length === 0) {
    await logSh('Parsing titres échoué, fallback ligne par ligne', 'WARNING');
    const lines = response.split('\n').filter(line => line.trim());
    
    allTitles.forEach((titleInfo, index) => {
      if (lines[index]) {
        results[titleInfo.tag] = lines[index].trim();
      }
    });
  }
  
  return results;
}

async function parseTextsResponse(response, allTexts) {
  const results = {};
  
  await logSh('Parsing réponse textes avec vrais tags...', 'DEBUG');
  
  // Utiliser regex pour extraire [TAG] contenu avec les vrais noms
  const regex = /\[([^\]]+)\]\s*\n([^[]*?)(?=\n\[|$)/gs;
  let match;
  
  while ((match = regex.exec(response)) !== null) {
    const tag = match[1].trim();
    const content = match[2].trim();
    
    // Nettoyer le contenu
    const cleanContent = content.replace(/^#+\s*/, '').replace(/<\/?[^>]+(>|$)/g, "");
    
    results[`|${tag}|`] = cleanContent;
    
    await logSh(`✓ Texte parsé [${tag}]: "${cleanContent}"`, 'DEBUG');
  }
  
  // Fallback si parsing échoue - mapper par position
  if (Object.keys(results).length === 0) {
    await logSh('Parsing textes échoué, fallback ligne par ligne', 'WARNING');
    
    const lines = response.split('\n')
      .map(line => line.trim())
      .filter(line => line.length > 0 && !line.startsWith('['));
    
    for (let index = 0; index < allTexts.length; index++) {
      const textInfo = allTexts[index];
      if (index < lines.length) {
        let content = lines[index];
        content = content.replace(/^\d+\.\s*/, ''); // Enlever "1. " si présent
        results[textInfo.tag] = content;
        
        await logSh(`✓ Texte fallback ${index + 1} → ${textInfo.tag}: "${content}"`, 'DEBUG');
      } else {
        await logSh(`✗ Pas assez de lignes pour ${textInfo.tag}`, 'WARNING');
        results[textInfo.tag] = `[Texte manquant ${index + 1}]`;
      }
    }
  }
  
  return results;
}

// ============= PARSER FAQ SPÉCIALISÉ - ADAPTÉ =============

async function parseFAQPairsResponse(response, faqPairs) {
  const results = {};
  
  await logSh('Parsing réponse paires FAQ...', 'DEBUG');
  
  // Parser avec regex pour capturer question + réponse
  const regex = /\[([^\]]+)\]\s*\n([^[]*?)(?=\n\[|$)/gs;
  let match;
  
  const parsedItems = {};
  
  while ((match = regex.exec(response)) !== null) {
    const tag = match[1].trim();
    const content = match[2].trim();
    
    const cleanContent = content.replace(/^#+\s*/, '').replace(/<\/?[^>]+(>|$)/g, "");
    
    parsedItems[tag] = cleanContent;
    
    await logSh(`✓ Item FAQ parsé [${tag}]: "${cleanContent}"`, 'DEBUG');
  }
  
  // Mapper aux tags originaux avec |
  Object.keys(parsedItems).forEach(cleanTag => {
    const content = parsedItems[cleanTag];
    results[`|${cleanTag}|`] = content;
  });
  
  // Vérification de cohérence paires
  let pairsCompletes = 0;
  for (const pair of faqPairs) {
    const hasQuestion = results[pair.question.tag];
    const hasAnswer = results[pair.answer.tag];
    
    if (hasQuestion && hasAnswer) {
      pairsCompletes++;
      await logSh(`✓ Paire FAQ ${pair.number} complète: Q+R`, 'DEBUG');
    } else {
      await logSh(`⚠ Paire FAQ ${pair.number} incomplète: Q=${!!hasQuestion} R=${!!hasAnswer}`, 'WARNING');
    }
  }
  
  await logSh(`${pairsCompletes}/${faqPairs.length} paires FAQ complètes`, 'INFO');
  
  // FATAL si paires FAQ manquantes
  if (pairsCompletes < faqPairs.length) {
    const manquantes = faqPairs.length - pairsCompletes;
    await logSh(`❌ FATAL: ${manquantes} paires FAQ manquantes sur ${faqPairs.length}`, 'ERROR');
    throw new Error(`FATAL: Génération FAQ incomplète (${manquantes}/${faqPairs.length} manquantes) - arrêt du workflow`);
  }
  
  return results;
}

async function parseOtherElementsResponse(response, allOtherElements) {
  const results = {};
  
  await logSh('Parsing réponse autres éléments...', 'DEBUG');
  
  const regex = /\[([^\]]+)\]\s*\n([^[]*?)(?=\n\[|$)/gs;
  let match;
  
  while ((match = regex.exec(response)) !== null) {
    const tag = match[1].trim();
    const content = match[2].trim();
    
    const cleanContent = content.replace(/^#+\s*/, '').replace(/<\/?[^>]+(>|$)/g, "");
    
    results[`|${tag}|`] = cleanContent;
    
    await logSh(`✓ Autre élément parsé [${tag}]: "${cleanContent}"`, 'DEBUG');
  }
  
  // Fallback si parsing partiel
  if (Object.keys(results).length < allOtherElements.length) {
    await logSh('Parsing autres éléments partiel, complétion fallback', 'WARNING');
    
    const lines = response.split('\n')
      .map(line => line.trim())
      .filter(line => line.length > 0 && !line.startsWith('['));
    
    allOtherElements.forEach((element, index) => {
      if (!results[element.tag] && lines[index]) {
        results[element.tag] = lines[index];
      }
    });
  }
  
  return results;
}

// ============= HELPER FUNCTIONS - ADAPTÉES =============

function createPromptForElement(element, csvData) {
  // Cette fonction sera probablement définie dans content-generation.js
  // Pour l'instant, retour basique
  return `Génère du contenu pour ${element.type}: ${element.resolvedContent}`;
}


// 🔄 NODE.JS EXPORTS
module.exports = {
  extractElements,
  resolveVariablesContent,
  getElementType,
  generateAllContent,
  parseElementStructure,
  buildSmartHierarchy,
  parseTitlesResponse,
  parseTextsResponse,
  parseFAQPairsResponse,
  parseOtherElementsResponse,
  createPromptForElement
};