/*
  code.js — bundle concaténé
  Généré: 2025-10-08T10:03:49.358Z
  Source: lib
  Fichiers: 50
  Ordre: topo
*/

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/ErrorReporting.js                                       │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: lib/error-reporting.js - CONVERTI POUR NODE.JS
// Description: Système de validation et rapport d'erreur
// ========================================

// Lazy loading des modules externes (évite blocage googleapis)
let google, nodemailer;
const fs = require('fs').promises;
const path = require('path');
const pino = require('pino');
const pretty = require('pino-pretty');
const { PassThrough } = require('stream');
const WebSocket = require('ws');

// Configuration
const SHEET_ID = process.env.GOOGLE_SHEETS_ID || '1iA2GvWeUxX-vpnAMfVm3ZMG9LhaC070SdGssEcXAh2c';

// WebSocket server for real-time logs
let wsServer;
const wsClients = new Set();

// Enhanced Pino logger configuration with real-time streaming and dated files
const now = new Date();
const timestamp = now.toISOString().slice(0, 10) + '_' + 
                 now.toLocaleTimeString('fr-FR').replace(/:/g, '-');
const logFile = path.join(__dirname, '..', 'logs', `seo-generator-${timestamp}.log`);

const prettyStream = pretty({
  colorize: true,
  translateTime: 'HH:MM:ss.l',
  ignore: 'pid,hostname',
});

const tee = new PassThrough();
// Lazy loading des pipes console (évite blocage à l'import)
let consolePipeInitialized = false;

// File destination with dated filename - FORCE DEBUG LEVEL
const fileDest = pino.destination({ 
  dest: logFile, 
  mkdir: true, 
  sync: false,
  minLength: 0 // Force immediate write even for small logs
});
tee.pipe(fileDest);

// Custom levels for Pino to include TRACE, PROMPT, and LLM
const customLevels = {
  trace: 5,   // Below debug (10)
  debug: 10,
  info: 20,
  prompt: 25, // New level for prompts (between info and warn)
  llm: 26,    // New level for LLM interactions (between prompt and warn)
  warn: 30,
  error: 40,
  fatal: 50
};

// Pino logger instance with enhanced configuration and custom levels
const logger = pino(
  { 
    level: 'debug', // FORCE DEBUG LEVEL for file logging
    base: undefined,
    timestamp: pino.stdTimeFunctions.isoTime,
    customLevels: customLevels,
    useOnlyCustomLevels: true
  },
  tee
);

// Initialize WebSocket server (only when explicitly requested)
function initWebSocketServer() {
  if (!wsServer && process.env.ENABLE_LOG_WS === 'true') {
    try {
      const logPort = process.env.LOG_WS_PORT || 8082;
      wsServer = new WebSocket.Server({ port: logPort });
      
      wsServer.on('connection', (ws) => {
        wsClients.add(ws);
        logger.info('Client connected to log WebSocket');
        
        ws.on('close', () => {
          wsClients.delete(ws);
          logger.info('Client disconnected from log WebSocket');
        });
        
        ws.on('error', (error) => {
          logger.error('WebSocket error:', error.message);
          wsClients.delete(ws);
        });
      });
      
      wsServer.on('error', (error) => {
        if (error.code === 'EADDRINUSE') {
          logger.warn(`WebSocket port ${logPort} already in use`);
          wsServer = null;
        } else {
          logger.error('WebSocket server error:', error.message);
        }
      });
      
      logger.info(`Log WebSocket server started on port ${logPort}`);
    } catch (error) {
      logger.warn(`Failed to start WebSocket server: ${error.message}`);
      wsServer = null;
    }
  }
}

// Broadcast log to WebSocket clients
function broadcastLog(message, level) {
  const logData = {
    timestamp: new Date().toISOString(),
    level: level.toUpperCase(),
    message: message
  };
  
  wsClients.forEach(ws => {
    if (ws.readyState === WebSocket.OPEN) {
      try {
        ws.send(JSON.stringify(logData));
      } catch (error) {
        logger.error('Failed to send log to WebSocket client:', error.message);
        wsClients.delete(ws);
      }
    }
  });
}

// 🔄 NODE.JS : Google Sheets API setup (remplace SpreadsheetApp)
let sheets;
let auth;

async function initGoogleSheets() {
  if (!sheets) {
    // Lazy load googleapis seulement quand nécessaire
    if (!google) {
      google = require('googleapis').google;
    }
    
    // Configuration auth Google Sheets API
    // Pour la démo, on utilise une clé de service (à configurer)
    auth = new google.auth.GoogleAuth({
      keyFile: process.env.GOOGLE_CREDENTIALS_PATH, // Chemin vers fichier JSON credentials
      scopes: ['https://www.googleapis.com/auth/spreadsheets']
    });
    
    sheets = google.sheets({ version: 'v4', auth });
  }
  return sheets;
}

async function logSh(message, level = 'INFO') {
  // Initialize WebSocket server if not already done
  if (!wsServer) {
    initWebSocketServer();
  }
  
  // Initialize console pipe if needed (lazy loading)
  if (!consolePipeInitialized && process.env.ENABLE_CONSOLE_LOG === 'true') {
    tee.pipe(prettyStream).pipe(process.stdout);
    consolePipeInitialized = true;
  }
  
  // Convert level to lowercase for Pino
  const pinoLevel = level.toLowerCase();
  
  // Enhanced trace metadata for hierarchical logging
  const traceData = {};
  if (message.includes('▶') || message.includes('✔') || message.includes('✖') || message.includes('•')) {
    traceData.trace = true;
    traceData.evt = message.includes('▶') ? 'span.start' : 
                   message.includes('✔') ? 'span.end' : 
                   message.includes('✖') ? 'span.error' : 'span.event';
  }
  
  // Log with Pino (handles console output with pretty formatting and file logging)
  switch (pinoLevel) {
    case 'error':
      logger.error(traceData, message);
      break;
    case 'warning':
    case 'warn':
      logger.warn(traceData, message);
      break;
    case 'debug':
      logger.debug(traceData, message);
      break;
    case 'trace':
      logger.trace(traceData, message);
      break;
    case 'prompt':
      logger.prompt(traceData, message);
      break;
    case 'llm':
      logger.llm(traceData, message);
      break;
    default:
      logger.info(traceData, message);
  }
  
  // Broadcast to WebSocket clients for real-time viewing
  broadcastLog(message, level);
  
  // Force immediate flush to ensure real-time display and prevent log loss
  logger.flush();
  
  // Log to Google Sheets if enabled (async, non-blocking)
  if (process.env.ENABLE_SHEETS_LOGGING === 'true') {
    setImmediate(() => {
      logToGoogleSheets(message, level).catch(err => {
        // Silent fail for Google Sheets logging to avoid recursion
      });
    });
  }
}

// Fonction pour déterminer si on doit logger en console
function shouldLogToConsole(messageLevel, configLevel) {
  const levels = { DEBUG: 0, INFO: 1, WARNING: 2, ERROR: 3 };
  return levels[messageLevel] >= levels[configLevel];
}

// Log to file is now handled by Pino transport
// This function is kept for compatibility but does nothing
async function logToFile(message, level) {
  // Pino handles file logging via transport configuration
  // This function is deprecated and kept for compatibility only
}

// 🔄 NODE.JS : Log vers Google Sheets (version async)
async function logToGoogleSheets(message, level) {
  try {
    const sheetsApi = await initGoogleSheets();
    
    const values = [[
      new Date().toISOString(),
      level,
      message,
      'Node.js workflow'
    ]];
    
    await sheetsApi.spreadsheets.values.append({
      spreadsheetId: SHEET_ID,
      range: 'Logs!A:D',
      valueInputOption: 'RAW',
      insertDataOption: 'INSERT_ROWS',
      resource: { values }
    });
    
  } catch (error) {
    logSh('Échec log Google Sheets: ' + error.message, 'WARNING'); // Using logSh instead of console.warn
  }
}

// 🔄 NODE.JS : Version simplifiée cleanLogSheet 
async function cleanLogSheet() {
  try {
    logSh('🧹 Nettoyage logs...', 'INFO'); // Using logSh instead of console.log
    
    // 1. Nettoyer fichiers logs locaux (garder 7 derniers jours)
    await cleanLocalLogs();
    
    // 2. Nettoyer Google Sheets si activé
    if (process.env.ENABLE_SHEETS_LOGGING === 'true') {
      await cleanGoogleSheetsLogs();
    }
    
    logSh('✅ Logs nettoyés', 'INFO'); // Using logSh instead of console.log
    
  } catch (error) {
    logSh('Erreur nettoyage logs: ' + error.message, 'ERROR'); // Using logSh instead of console.error
  }
}

async function cleanLocalLogs() {
  try {
    // Note: With Pino, log files are managed differently
    // This function is kept for compatibility with Google Sheets logs cleanup
    // Pino log rotation should be handled by external tools like logrotate
    
    // For now, we keep the basic cleanup for any remaining old log files
    const logsDir = path.join(__dirname, '../logs');
    
    try {
      const files = await fs.readdir(logsDir);
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - 7); // Garder 7 jours
      
      for (const file of files) {
        if (file.endsWith('.log')) {
          const filePath = path.join(logsDir, file);
          const stats = await fs.stat(filePath);
          
          if (stats.mtime < cutoffDate) {
            await fs.unlink(filePath);
            logSh(`🗑️ Supprimé log ancien: ${file}`, 'INFO');
          }
        }
      }
    } catch (error) {
      // Directory might not exist, that's fine
    }
  } catch (error) {
    // Silent fail
  }
}

async function cleanGoogleSheetsLogs() {
  try {
    const sheetsApi = await initGoogleSheets();
    
    // Clear + remettre headers
    await sheetsApi.spreadsheets.values.clear({
      spreadsheetId: SHEET_ID,
      range: 'Logs!A:D'
    });
    
    await sheetsApi.spreadsheets.values.update({
      spreadsheetId: SHEET_ID,
      range: 'Logs!A1:D1',
      valueInputOption: 'RAW',
      resource: {
        values: [['Timestamp', 'Level', 'Message', 'Source']]
      }
    });
    
  } catch (error) {
    logSh('Échec nettoyage Google Sheets: ' + error.message, 'WARNING'); // Using logSh instead of console.warn
  }
}

// ============= VALIDATION PRINCIPALE - IDENTIQUE =============

function validateWorkflowIntegrity(elements, generatedContent, finalXML, csvData) {
  logSh('🔍 >>> VALIDATION INTÉGRITÉ WORKFLOW <<<', 'INFO'); // Using logSh instead of console.log
  
  const errors = [];
  const warnings = [];
  const stats = {
    elementsExtracted: elements.length,
    contentGenerated: Object.keys(generatedContent).length,
    tagsReplaced: 0,
    tagsRemaining: 0
  };
  
  // TEST 1: Détection tags dupliqués
  const duplicateCheck = detectDuplicateTags(elements);
  if (duplicateCheck.hasDuplicates) {
    errors.push({
      type: 'DUPLICATE_TAGS',
      severity: 'HIGH',
      message: `Tags dupliqués détectés: ${duplicateCheck.duplicates.join(', ')}`,
      impact: 'Certains contenus ne seront pas remplacés dans le XML final',
      suggestion: 'Vérifier le template XML pour corriger la structure'
    });
  }
  
  // TEST 2: Cohérence éléments extraits vs générés
  const missingGeneration = elements.filter(el => !generatedContent[el.originalTag]);
  if (missingGeneration.length > 0) {
    errors.push({
      type: 'MISSING_GENERATION',
      severity: 'HIGH', 
      message: `${missingGeneration.length} éléments extraits mais non générés`,
      details: missingGeneration.map(el => el.originalTag),
      impact: 'Contenu incomplet dans le XML final'
    });
  }
  
  // TEST 3: Tags non remplacés dans XML final
  const remainingTags = (finalXML.match(/\|[^|]*\|/g) || []);
  stats.tagsRemaining = remainingTags.length;
  
  if (remainingTags.length > 0) {
    errors.push({
      type: 'UNREPLACED_TAGS',
      severity: 'HIGH',
      message: `${remainingTags.length} tags non remplacés dans le XML final`,
      details: remainingTags.slice(0, 5),
      impact: 'XML final contient des placeholders non remplacés'
    });
  }
  
  // TEST 4: Variables CSV manquantes
  const missingVars = detectMissingCSVVariables(csvData);
  if (missingVars.length > 0) {
    warnings.push({
      type: 'MISSING_CSV_VARIABLES',
      severity: 'MEDIUM',
      message: `Variables CSV manquantes: ${missingVars.join(', ')}`,
      impact: 'Système de génération de mots-clés automatique activé'
    });
  }
  
  // TEST 5: Qualité génération IA
  const generationQuality = assessGenerationQuality(generatedContent);
  if (generationQuality.errorRate > 0.1) {
    warnings.push({
      type: 'GENERATION_QUALITY',
      severity: 'MEDIUM', 
      message: `${(generationQuality.errorRate * 100).toFixed(1)}% d'erreurs de génération IA`,
      impact: 'Qualité du contenu potentiellement dégradée'
    });
  }
  
  // CALCUL STATS FINALES
  stats.tagsReplaced = elements.length - remainingTags.length;
  stats.successRate = stats.elementsExtracted > 0 ? 
    ((stats.tagsReplaced / elements.length) * 100).toFixed(1) : '100';
  
  const report = {
    timestamp: new Date().toISOString(),
    csvData: { mc0: csvData.mc0, t0: csvData.t0 },
    stats: stats,
    errors: errors,
    warnings: warnings,
    status: errors.length === 0 ? 'SUCCESS' : 'ERROR'
  };
  
  const logLevel = report.status === 'SUCCESS' ? 'INFO' : 'ERROR';
  logSh(`✅ Validation terminée: ${report.status} (${errors.length} erreurs, ${warnings.length} warnings)`, 'INFO'); // Using logSh instead of console.log
  
  // ENVOYER RAPPORT SI ERREURS (async en arrière-plan)
  if (errors.length > 0 || warnings.length > 2) {
    sendErrorReport(report).catch(err => {
      logSh('Erreur envoi rapport: ' + err.message, 'ERROR'); // Using logSh instead of console.error
    });
  }
  
  return report;
}

// ============= HELPERS - IDENTIQUES =============

function detectDuplicateTags(elements) {
  const tagCounts = {};
  const duplicates = [];
  
  elements.forEach(element => {
    const tag = element.originalTag;
    tagCounts[tag] = (tagCounts[tag] || 0) + 1;
    
    if (tagCounts[tag] === 2) {
      duplicates.push(tag);
      logSh(`❌ DUPLICATE détecté: ${tag}`, 'ERROR'); // Using logSh instead of console.error
    }
  });
  
  return {
    hasDuplicates: duplicates.length > 0,
    duplicates: duplicates,
    counts: tagCounts
  };
}

function detectMissingCSVVariables(csvData) {
  const missing = [];
  
  if (!csvData.mcPlus1 || csvData.mcPlus1.split(',').length < 4) {
    missing.push('MC+1 (insuffisant)');
  }
  if (!csvData.tPlus1 || csvData.tPlus1.split(',').length < 4) {
    missing.push('T+1 (insuffisant)');  
  }
  if (!csvData.lPlus1 || csvData.lPlus1.split(',').length < 4) {
    missing.push('L+1 (insuffisant)');
  }
  
  return missing;
}

function assessGenerationQuality(generatedContent) {
  let errorCount = 0;
  let totalCount = Object.keys(generatedContent).length;
  
  Object.values(generatedContent).forEach(content => {
    if (content && (
        content.includes('[ERREUR') || 
        content.includes('ERROR') ||
        content.length < 10
    )) {
      errorCount++;
    }
  });
  
  return {
    errorRate: totalCount > 0 ? errorCount / totalCount : 0,
    totalGenerated: totalCount,
    errorsFound: errorCount
  };
}

// 🔄 NODE.JS : Email avec nodemailer (remplace MailApp)
async function sendErrorReport(report) {
  try {
    logSh('📧 Envoi rapport d\'erreur par email...', 'INFO'); // Using logSh instead of console.log
    
    // Lazy load nodemailer seulement quand nécessaire
    if (!nodemailer) {
      nodemailer = require('nodemailer');
    }
    
    // Configuration nodemailer (Gmail par exemple)
    const transporter = nodemailer.createTransport({
      service: 'gmail',
      auth: {
        user: process.env.EMAIL_USER, // 'your-email@gmail.com'
        pass: process.env.EMAIL_APP_PASSWORD // App password Google
      }
    });
    
    const subject = `Erreur Workflow SEO Node.js - ${report.status} - ${report.csvData.mc0}`;
    const htmlBody = createHTMLReport(report);
    
    const mailOptions = {
      from: process.env.EMAIL_USER,
      to: 'alexistrouve.pro@gmail.com',
      subject: subject,
      html: htmlBody,
      attachments: [{
        filename: `error-report-${Date.now()}.json`,
        content: JSON.stringify(report, null, 2),
        contentType: 'application/json'
      }]
    };
    
    await transporter.sendMail(mailOptions);
    logSh('✅ Rapport d\'erreur envoyé par email', 'INFO'); // Using logSh instead of console.log
    
  } catch (error) {
    logSh(`❌ Échec envoi email: ${error.message}`, 'ERROR'); // Using logSh instead of console.error
  }
}

// ============= HTML REPORT - IDENTIQUE =============

function createHTMLReport(report) {
  const statusColor = report.status === 'SUCCESS' ? '#28a745' : '#dc3545';
  
  let html = `
    <div style="font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto;">
      <h1 style="color: ${statusColor};">Rapport Workflow SEO Automatisé (Node.js)</h1>
      
      <div style="background: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0;">
        <h2>Résumé Exécutif</h2>
        <p><strong>Statut:</strong> <span style="color: ${statusColor};">${report.status}</span></p>
        <p><strong>Article:</strong> ${report.csvData.t0}</p>
        <p><strong>Mot-clé:</strong> ${report.csvData.mc0}</p>
        <p><strong>Taux de réussite:</strong> ${report.stats.successRate}%</p>
        <p><strong>Timestamp:</strong> ${report.timestamp}</p>
        <p><strong>Plateforme:</strong> Node.js Server</p>
      </div>`;
  
  if (report.errors.length > 0) {
    html += `<div style="background: #f8d7da; padding: 15px; border-radius: 5px; margin: 20px 0;">
      <h2>Erreurs Critiques (${report.errors.length})</h2>`;
    
    report.errors.forEach((error, i) => {
      html += `
        <div style="margin: 10px 0; padding: 10px; border-left: 3px solid #dc3545;">
          <h4>${i + 1}. ${error.type}</h4>
          <p><strong>Message:</strong> ${error.message}</p>
          <p><strong>Impact:</strong> ${error.impact}</p>
          ${error.suggestion ? `<p><strong>Solution:</strong> ${error.suggestion}</p>` : ''}
        </div>`;
    });
    
    html += `</div>`;
  }
  
  if (report.warnings.length > 0) {
    html += `<div style="background: #fff3cd; padding: 15px; border-radius: 5px; margin: 20px 0;">
      <h2>Avertissements (${report.warnings.length})</h2>`;
    
    report.warnings.forEach((warning, i) => {
      html += `
        <div style="margin: 10px 0; padding: 10px; border-left: 3px solid #ffc107;">
          <h4>${i + 1}. ${warning.type}</h4>
          <p>${warning.message}</p>
        </div>`;
    });
    
    html += `</div>`;
  }
  
  html += `
      <div style="background: #e9ecef; padding: 15px; border-radius: 5px; margin: 20px 0;">
        <h2>Statistiques Détaillées</h2>
        <ul>
          <li>Éléments extraits: ${report.stats.elementsExtracted}</li>
          <li>Contenus générés: ${report.stats.contentGenerated}</li>
          <li>Tags remplacés: ${report.stats.tagsReplaced}</li>
          <li>Tags restants: ${report.stats.tagsRemaining}</li>
        </ul>
      </div>
      
      <div style="background: #d1ecf1; padding: 15px; border-radius: 5px; margin: 20px 0;">
        <h2>Informations Système</h2>
        <ul>
          <li>Plateforme: Node.js</li>
          <li>Version: ${process.version}</li>
          <li>Mémoire: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB</li>
          <li>Uptime: ${Math.round(process.uptime())}s</li>
        </ul>
      </div>
    </div>`;
  
  return html;
}

// 🔄 NODE.JS EXPORTS
module.exports = {
  logSh,
  cleanLogSheet,
  validateWorkflowIntegrity,
  detectDuplicateTags,
  detectMissingCSVVariables,
  assessGenerationQuality,
  sendErrorReport,
  createHTMLReport,
  initWebSocketServer
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/trace.js                                                │
└────────────────────────────────────────────────────────────────────┘
*/

// lib/trace.js
const { AsyncLocalStorage } = require('node:async_hooks');
const { randomUUID } = require('node:crypto');
const { logSh } = require('./ErrorReporting');

const als = new AsyncLocalStorage();

function now() { return performance.now(); }
function dur(ms) {
  if (ms < 1e3) return `${ms.toFixed(1)}ms`;
  const s = ms / 1e3;
  return s < 60 ? `${s.toFixed(2)}s` : `${(s/60).toFixed(2)}m`;
}

class Span {
  constructor({ name, parent = null, attrs = {} }) {
    this.id = randomUUID();
    this.name = name;
    this.parent = parent;
    this.children = [];
    this.attrs = attrs;
    this.start = now();
    this.end = null;
    this.status = 'ok';
    this.error = null;
  }
  pathNames() {
    const names = [];
    let cur = this;
    while (cur) { names.unshift(cur.name); cur = cur.parent; }
    return names.join(' > ');
  }
  finish() { this.end = now(); }
  duration() { return (this.end ?? now()) - this.start; }
}

class Tracer {
  constructor() {
    this.rootSpans = [];
  }
  current() { return als.getStore(); }

  async startSpan(name, attrs = {}) {
    const parent = this.current();
    const span = new Span({ name, parent, attrs });
    if (parent) parent.children.push(span);
    else this.rootSpans.push(span);
    
    // Formater les paramètres pour affichage
    const paramsStr = this.formatParams(attrs);
    await logSh(`▶ ${name}${paramsStr}`, 'TRACE');
    return span;
  }

  async run(name, fn, attrs = {}) {
    const parent = this.current();
    const span = await this.startSpan(name, attrs);
    return await als.run(span, async () => {
      try {
        const res = await fn();
        span.finish();
        const paramsStr = this.formatParams(span.attrs);
        await logSh(`✔ ${name}${paramsStr} (${dur(span.duration())})`, 'TRACE');
        return res;
      } catch (err) {
        span.status = 'error';
        span.error = { message: err?.message, stack: err?.stack };
        span.finish();
        const paramsStr = this.formatParams(span.attrs);
        await logSh(`✖ ${name}${paramsStr} FAILED (${dur(span.duration())})`, 'ERROR');
        await logSh(`Stack trace: ${span.error.message}`, 'ERROR');
        if (span.error.stack) {
          const stackLines = span.error.stack.split('\n').slice(1, 6); // Première 5 lignes du stack
          for (const line of stackLines) {
            await logSh(`  ${line.trim()}`, 'ERROR');
          }
        }
        throw err;
      }
    });
  }

  async event(msg, extra = {}) {
    const span = this.current();
    const data = { trace: true, evt: 'span.event', ...extra };
    if (span) {
      data.span = span.id;
      data.path = span.pathNames();
      data.since_ms = +( (now() - span.start).toFixed(1) );
    }
    await logSh(`• ${msg}`, 'TRACE');
  }

  async annotate(fields = {}) {
    const span = this.current();
    if (span) Object.assign(span.attrs, fields);
    await logSh('… annotate', 'TRACE');
  }

  formatParams(attrs = {}) {
    const params = Object.entries(attrs)
      .filter(([key, value]) => value !== undefined && value !== null)
      .map(([key, value]) => {
        // Tronquer les valeurs trop longues
        const strValue = String(value);
        const truncated = strValue.length > 50 ? strValue.substring(0, 47) + '...' : strValue;
        return `${key}=${truncated}`;
      });
    
    return params.length > 0 ? `(${params.join(', ')})` : '';
  }

  printSummary() {
    const lines = [];
    const draw = (node, depth = 0) => {
      const pad = '  '.repeat(depth);
      const icon = node.status === 'error' ? '✖' : '✔';
      lines.push(`${pad}${icon} ${node.name}  (${dur(node.duration())})`);
      if (Object.keys(node.attrs ?? {}).length) {
        lines.push(`${pad}   attrs: ${JSON.stringify(node.attrs)}`);
      }
      for (const ch of node.children) draw(ch, depth + 1);
      if (node.status === 'error' && node.error?.message) {
        lines.push(`${pad}   error: ${node.error.message}`);
        if (node.error.stack) {
          const stackLines = String(node.error.stack || '').split('\n').slice(1, 4).map(s => s.trim());
          if (stackLines.length) {
            lines.push(`${pad}   stack:`);
            stackLines.forEach(line => {
              if (line) lines.push(`${pad}     ${line}`);
            });
          }
        }
      }
    };
    for (const r of this.rootSpans) draw(r, 0);
    const summary = lines.join('\n');
    logSh(`\n—— TRACE SUMMARY ——\n${summary}\n—— END TRACE ——`, 'INFO');
    return summary;
  }
}

const tracer = new Tracer();

module.exports = {
  Span,
  Tracer,
  tracer
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/trend-prompts/TrendManager.js                           │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// TREND MANAGER - GESTION TENDANCES PROMPTS
// Responsabilité: Configuration tendances pour moduler les prompts selon contexte
// ========================================

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

/**
 * TREND MANAGER
 * Gère les tendances configurables pour adapter les prompts selon le contexte
 */
class TrendManager {
  constructor() {
    this.name = 'TrendManager';
    this.currentTrend = null;
    this.customTrends = new Map();

    // Initialiser les tendances prédéfinies
    this.initializePredefinedTrends();
  }

  /**
   * TENDANCES PRÉDÉFINIES
   */
  initializePredefinedTrends() {
    this.predefinedTrends = {
      // ========== TENDANCES SECTORIELLES ==========

      'eco-responsable': {
        name: 'Eco-Responsable',
        description: 'Accent sur durabilité, écologie, responsabilité environnementale',
        config: {
          technical: {
            targetTerms: ['durable', 'écologique', 'responsable', 'recyclé', 'bio', 'naturel'],
            focusAreas: ['impact environnemental', 'cycle de vie', 'matériaux durables']
          },
          style: {
            targetStyle: 'conscient et responsable',
            tone: 'engagé mais pédagogique',
            values: ['durabilité', 'respect environnement', 'qualité long terme']
          },
          adversarial: {
            avoidTerms: ['jetable', 'synthétique', 'intensive'],
            emphasize: ['naturel', 'durable', 'responsable']
          }
        }
      },

      'tech-innovation': {
        name: 'Tech Innovation',
        description: 'Focus technologie avancée, innovation, digitalisation',
        config: {
          technical: {
            targetTerms: ['intelligent', 'connecté', 'automatisé', 'numérique', 'innovation'],
            focusAreas: ['technologie avancée', 'connectivité', 'automatisation']
          },
          style: {
            targetStyle: 'moderne et dynamique',
            tone: 'enthousiaste et précis',
            values: ['innovation', 'performance', 'efficacité']
          },
          adversarial: {
            avoidTerms: ['traditionnel', 'manuel', 'basique'],
            emphasize: ['intelligent', 'avancé', 'innovant']
          }
        }
      },

      'artisanal-premium': {
        name: 'Artisanal Premium',
        description: 'Savoir-faire artisanal, qualité premium, tradition',
        config: {
          technical: {
            targetTerms: ['artisanal', 'fait main', 'traditionnel', 'savoir-faire', 'premium'],
            focusAreas: ['qualité artisanale', 'techniques traditionnelles', 'finitions soignées']
          },
          style: {
            targetStyle: 'authentique et raffiné',
            tone: 'respectueux et valorisant',
            values: ['authenticité', 'qualité', 'tradition']
          },
          adversarial: {
            avoidTerms: ['industriel', 'masse', 'standard'],
            emphasize: ['unique', 'authentique', 'raffiné']
          }
        }
      },

      // ========== TENDANCES GÉNÉRATIONNELLES ==========

      'generation-z': {
        name: 'Génération Z',
        description: 'Style moderne, inclusif, digital native',
        config: {
          technical: {
            targetTerms: ['tendance', 'viral', 'personnalisable', 'inclusif', 'durable'],
            focusAreas: ['personnalisation', 'impact social', 'durabilité']
          },
          style: {
            targetStyle: 'moderne et inclusif',
            tone: 'décontracté mais informatif',
            values: ['authenticité', 'inclusivité', 'durabilité']
          },
          adversarial: {
            avoidTerms: ['traditionnel', 'conventionnel'],
            emphasize: ['moderne', 'inclusif', 'authentique']
          }
        }
      },

      'millenial-pro': {
        name: 'Millennial Pro',
        description: 'Efficacité, équilibre vie-travail, qualité',
        config: {
          technical: {
            targetTerms: ['efficace', 'pratique', 'gain de temps', 'qualité de vie'],
            focusAreas: ['efficacité', 'praticité', 'équilibre']
          },
          style: {
            targetStyle: 'pratique et équilibré',
            tone: 'professionnel mais humain',
            values: ['efficacité', 'équilibre', 'qualité']
          },
          adversarial: {
            avoidTerms: ['compliqué', 'chronophage'],
            emphasize: ['pratique', 'efficace', 'équilibré']
          }
        }
      },

      // ========== TENDANCES SAISONNIÈRES ==========

      'automne-cocooning': {
        name: 'Automne Cocooning',
        description: 'Chaleur, confort, intérieur douillet',
        config: {
          technical: {
            targetTerms: ['chaleureux', 'confortable', 'douillet', 'cosy', 'réconfortant'],
            focusAreas: ['ambiance chaleureuse', 'confort', 'bien-être']
          },
          style: {
            targetStyle: 'chaleureux et enveloppant',
            tone: 'bienveillant et réconfortant',
            values: ['confort', 'chaleur', 'sérénité']
          },
          adversarial: {
            avoidTerms: ['froid', 'strict', 'minimaliste'],
            emphasize: ['chaleureux', 'confortable', 'accueillant']
          }
        }
      },

      'printemps-renouveau': {
        name: 'Printemps Renouveau',
        description: 'Fraîcheur, renouveau, énergie positive',
        config: {
          technical: {
            targetTerms: ['frais', 'nouveau', 'énergisant', 'revitalisant', 'lumineux'],
            focusAreas: ['renouveau', 'fraîcheur', 'dynamisme']
          },
          style: {
            targetStyle: 'frais et dynamique',
            tone: 'optimiste et énergique',
            values: ['renouveau', 'fraîcheur', 'vitalité']
          },
          adversarial: {
            avoidTerms: ['terne', 'monotone', 'statique'],
            emphasize: ['frais', 'nouveau', 'dynamique']
          }
        }
      }
    };

    logSh(`✅ TrendManager: ${Object.keys(this.predefinedTrends).length} tendances prédéfinies chargées`, 'DEBUG');
  }

  /**
   * SÉLECTIONNER UNE TENDANCE
   */
  setTrend(trendId, customConfig = null) {
    return tracer.run('TrendManager.setTrend()', async () => {
      try {
        if (customConfig) {
          // Tendance personnalisée
          this.currentTrend = {
            id: trendId,
            name: customConfig.name || trendId,
            description: customConfig.description || 'Tendance personnalisée',
            config: customConfig.config,
            isCustom: true
          };

          logSh(`🎯 Tendance personnalisée appliquée: ${trendId}`, 'INFO');

        } else if (this.predefinedTrends[trendId]) {
          // Tendance prédéfinie
          this.currentTrend = {
            id: trendId,
            ...this.predefinedTrends[trendId],
            isCustom: false
          };

          logSh(`🎯 Tendance appliquée: ${this.currentTrend.name}`, 'INFO');

        } else if (this.customTrends.has(trendId)) {
          // Tendance personnalisée existante
          const customTrend = this.customTrends.get(trendId);
          this.currentTrend = {
            id: trendId,
            ...customTrend,
            isCustom: true
          };

          logSh(`🎯 Tendance personnalisée appliquée: ${this.currentTrend.name}`, 'INFO');

        } else {
          throw new Error(`Tendance inconnue: ${trendId}`);
        }

        await tracer.annotate({
          trendId,
          trendName: this.currentTrend.name,
          isCustom: this.currentTrend.isCustom
        });

        return this.currentTrend;

      } catch (error) {
        logSh(`❌ Erreur sélection tendance: ${error.message}`, 'ERROR');
        throw error;
      }
    });
  }

  /**
   * APPLIQUER TENDANCE À UNE CONFIGURATION DE COUCHE
   */
  applyTrendToLayerConfig(layerType, baseConfig = {}) {
    if (!this.currentTrend) {
      return baseConfig;
    }

    const trendConfig = this.currentTrend.config[layerType];
    if (!trendConfig) {
      return baseConfig;
    }

    // Fusionner configuration tendance avec configuration de base
    const enhancedConfig = {
      ...baseConfig,
      ...trendConfig,
      // Préserver les paramètres existants tout en ajoutant la tendance
      trendApplied: this.currentTrend.id,
      trendName: this.currentTrend.name
    };

    logSh(`🎨 Tendance "${this.currentTrend.name}" appliquée à ${layerType}`, 'DEBUG');

    return enhancedConfig;
  }

  /**
   * OBTENIR CONFIGURATION POUR UNE COUCHE SPÉCIFIQUE
   */
  getLayerConfig(layerType, baseConfig = {}) {
    const config = this.applyTrendToLayerConfig(layerType, baseConfig);

    return {
      ...config,
      _trend: this.currentTrend ? {
        id: this.currentTrend.id,
        name: this.currentTrend.name,
        appliedTo: layerType
      } : null
    };
  }

  /**
   * LISTER TOUTES LES TENDANCES DISPONIBLES
   */
  getAvailableTrends() {
    const trends = Object.keys(this.predefinedTrends).map(id => ({
      id,
      name: this.predefinedTrends[id].name,
      description: this.predefinedTrends[id].description,
      category: this.getTrendCategory(id),
      isCustom: false
    }));

    // Ajouter tendances personnalisées
    for (const [id, trend] of this.customTrends) {
      trends.push({
        id,
        name: trend.name,
        description: trend.description,
        category: 'custom',
        isCustom: true
      });
    }

    return trends;
  }

  /**
   * OBTENIR CATÉGORIE D'UNE TENDANCE
   */
  getTrendCategory(trendId) {
    if (trendId.includes('generation')) return 'générationnelle';
    if (trendId.includes('eco') || trendId.includes('tech') || trendId.includes('artisanal')) return 'sectorielle';
    if (trendId.includes('automne') || trendId.includes('printemps')) return 'saisonnière';
    return 'autre';
  }

  /**
   * CRÉER UNE TENDANCE PERSONNALISÉE
   */
  createCustomTrend(id, config) {
    this.customTrends.set(id, config);
    logSh(`✨ Tendance personnalisée créée: ${id}`, 'INFO');
    return config;
  }

  /**
   * RÉINITIALISER (AUCUNE TENDANCE)
   */
  clearTrend() {
    this.currentTrend = null;
    logSh('🔄 Aucune tendance appliquée', 'DEBUG');
  }

  /**
   * OBTENIR TENDANCE ACTUELLE
   */
  getCurrentTrend() {
    return this.currentTrend;
  }

  /**
   * OBTENIR STATUT
   */
  getStatus() {
    return {
      activeTrend: this.currentTrend ? {
        id: this.currentTrend.id,
        name: this.currentTrend.name,
        description: this.currentTrend.description,
        isCustom: this.currentTrend.isCustom
      } : null,
      availableTrends: this.getAvailableTrends().length,
      customTrends: this.customTrends.size
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pipeline/PipelineDefinition.js                          │
└────────────────────────────────────────────────────────────────────┘
*/

/**
 * PipelineDefinition.js
 *
 * Schemas et validation pour les pipelines modulaires flexibles.
 * Permet de définir des workflows custom avec n'importe quelle combinaison de modules.
 */

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

/**
 * Modules disponibles dans le pipeline
 */
const AVAILABLE_MODULES = {
  generation: {
    name: 'Generation',
    description: 'Génération initiale du contenu',
    modes: ['simple'],
    defaultIntensity: 1.0,
    parameters: {}
  },
  selective: {
    name: 'Selective Enhancement',
    description: 'Amélioration sélective par couches',
    modes: [
      'lightEnhancement',
      'standardEnhancement',
      'fullEnhancement',
      'personalityFocus',
      'fluidityFocus',
      'adaptive'
    ],
    defaultIntensity: 1.0,
    parameters: {
      layers: { type: 'array', description: 'Couches spécifiques à appliquer' }
    }
  },
  adversarial: {
    name: 'Adversarial Generation',
    description: 'Techniques anti-détection',
    modes: ['none', 'light', 'standard', 'heavy', 'adaptive'],
    defaultIntensity: 1.0,
    parameters: {
      detector: { type: 'string', enum: ['general', 'gptZero', 'originality'], default: 'general' },
      method: { type: 'string', enum: ['enhancement', 'regeneration', 'hybrid'], default: 'regeneration' }
    }
  },
  human: {
    name: 'Human Simulation',
    description: 'Simulation comportement humain',
    modes: [
      'none',
      'lightSimulation',
      'standardSimulation',
      'heavySimulation',
      'adaptiveSimulation',
      'personalityFocus',
      'temporalFocus'
    ],
    defaultIntensity: 1.0,
    parameters: {
      fatigueLevel: { type: 'number', min: 0, max: 1, default: 0.5 },
      errorRate: { type: 'number', min: 0, max: 1, default: 0.3 }
    }
  },
  pattern: {
    name: 'Pattern Breaking',
    description: 'Cassage patterns LLM',
    modes: [
      'none',
      'lightPatternBreaking',
      'standardPatternBreaking',
      'heavyPatternBreaking',
      'adaptivePatternBreaking',
      'syntaxFocus',
      'connectorsFocus'
    ],
    defaultIntensity: 1.0,
    parameters: {
      focus: { type: 'string', enum: ['syntax', 'connectors', 'both'], default: 'both' }
    }
  }
};

/**
 * Schema d'une étape de pipeline
 */
const STEP_SCHEMA = {
  step: { type: 'number', required: true, description: 'Numéro séquentiel de l\'étape' },
  module: { type: 'string', required: true, enum: Object.keys(AVAILABLE_MODULES), description: 'Module à exécuter' },
  mode: { type: 'string', required: true, description: 'Mode du module' },
  intensity: { type: 'number', required: false, min: 0.1, max: 2.0, default: 1.0, description: 'Intensité d\'application' },
  parameters: { type: 'object', required: false, default: {}, description: 'Paramètres spécifiques au module' },
  saveCheckpoint: { type: 'boolean', required: false, default: false, description: 'Sauvegarder checkpoint après cette étape' },
  enabled: { type: 'boolean', required: false, default: true, description: 'Activer/désactiver l\'étape' }
};

/**
 * Schema complet d'un pipeline
 */
const PIPELINE_SCHEMA = {
  name: { type: 'string', required: true, minLength: 3, maxLength: 100 },
  description: { type: 'string', required: false, maxLength: 500 },
  pipeline: { type: 'array', required: true, minLength: 1, maxLength: 20 },
  metadata: {
    type: 'object',
    required: false,
    properties: {
      author: { type: 'string' },
      created: { type: 'string' },
      version: { type: 'string' },
      tags: { type: 'array' }
    }
  }
};

/**
 * Classe PipelineDefinition
 */
class PipelineDefinition {
  constructor(definition = null) {
    this.definition = definition;
  }

  /**
   * Valide un pipeline complet
   */
  static validate(pipeline) {
    const errors = [];

    // Validation schema principal
    if (!pipeline.name || typeof pipeline.name !== 'string' || pipeline.name.length < 3) {
      errors.push('Le nom du pipeline doit contenir au moins 3 caractères');
    }

    if (!Array.isArray(pipeline.pipeline) || pipeline.pipeline.length === 0) {
      errors.push('Le pipeline doit contenir au moins une étape');
    }

    if (pipeline.pipeline && pipeline.pipeline.length > 20) {
      errors.push('Le pipeline ne peut pas contenir plus de 20 étapes');
    }

    // Validation des étapes
    if (Array.isArray(pipeline.pipeline)) {
      pipeline.pipeline.forEach((step, index) => {
        const stepErrors = PipelineDefinition.validateStep(step, index);
        errors.push(...stepErrors);
      });

      // Vérifier séquence des steps
      const steps = pipeline.pipeline.map(s => s.step).sort((a, b) => a - b);
      for (let i = 0; i < steps.length; i++) {
        if (steps[i] !== i + 1) {
          errors.push(`Numérotation des étapes incorrecte: attendu ${i + 1}, trouvé ${steps[i]}`);
          break;
        }
      }
    }

    if (errors.length > 0) {
      logSh(`❌ Pipeline validation failed: ${errors.join(', ')}`, 'ERROR');
      return { valid: false, errors };
    }

    logSh(`✅ Pipeline "${pipeline.name}" validé: ${pipeline.pipeline.length} étapes`, 'DEBUG');
    return { valid: true, errors: [] };
  }

  /**
   * Valide une étape individuelle
   */
  static validateStep(step, index) {
    const errors = [];

    // Step number
    if (typeof step.step !== 'number' || step.step < 1) {
      errors.push(`Étape ${index}: 'step' doit être un nombre >= 1`);
    }

    // Module
    if (!step.module || !AVAILABLE_MODULES[step.module]) {
      errors.push(`Étape ${index}: module '${step.module}' inconnu. Disponibles: ${Object.keys(AVAILABLE_MODULES).join(', ')}`);
      return errors; // Stop si module invalide
    }

    const moduleConfig = AVAILABLE_MODULES[step.module];

    // Mode
    if (!step.mode) {
      errors.push(`Étape ${index}: 'mode' requis pour module ${step.module}`);
    } else if (!moduleConfig.modes.includes(step.mode)) {
      errors.push(`Étape ${index}: mode '${step.mode}' invalide pour ${step.module}. Disponibles: ${moduleConfig.modes.join(', ')}`);
    }

    // Intensity
    if (step.intensity !== undefined) {
      if (typeof step.intensity !== 'number' || step.intensity < 0.1 || step.intensity > 2.0) {
        errors.push(`Étape ${index}: intensity doit être entre 0.1 et 2.0`);
      }
    }

    // Parameters (validation basique)
    if (step.parameters && typeof step.parameters !== 'object') {
      errors.push(`Étape ${index}: parameters doit être un objet`);
    }

    return errors;
  }

  /**
   * Crée une étape de pipeline valide
   */
  static createStep(stepNumber, module, mode, options = {}) {
    const moduleConfig = AVAILABLE_MODULES[module];
    if (!moduleConfig) {
      throw new Error(`Module inconnu: ${module}`);
    }

    if (!moduleConfig.modes.includes(mode)) {
      throw new Error(`Mode ${mode} invalide pour module ${module}`);
    }

    return {
      step: stepNumber,
      module,
      mode,
      intensity: options.intensity ?? moduleConfig.defaultIntensity,
      parameters: options.parameters ?? {},
      saveCheckpoint: options.saveCheckpoint ?? false,
      enabled: options.enabled ?? true
    };
  }

  /**
   * Crée un pipeline vide
   */
  static createEmpty(name, description = '') {
    return {
      name,
      description,
      pipeline: [],
      metadata: {
        author: 'system',
        created: new Date().toISOString(),
        version: '1.0',
        tags: []
      }
    };
  }

  /**
   * Clone un pipeline
   */
  static clone(pipeline, newName = null) {
    const cloned = JSON.parse(JSON.stringify(pipeline));
    if (newName) {
      cloned.name = newName;
    }
    cloned.metadata = {
      ...cloned.metadata,
      created: new Date().toISOString(),
      clonedFrom: pipeline.name
    };
    return cloned;
  }

  /**
   * Estime la durée d'un pipeline
   */
  static estimateDuration(pipeline) {
    // Durées moyennes par module (en secondes)
    const DURATIONS = {
      generation: 15,
      selective: 20,
      adversarial: 25,
      human: 15,
      pattern: 18
    };

    let totalSeconds = 0;
    pipeline.pipeline.forEach(step => {
      if (!step.enabled) return;

      const baseDuration = DURATIONS[step.module] || 20;
      const intensityFactor = step.intensity || 1.0;
      totalSeconds += baseDuration * intensityFactor;
    });

    return {
      seconds: Math.round(totalSeconds),
      formatted: PipelineDefinition.formatDuration(totalSeconds)
    };
  }

  /**
   * Formate une durée en secondes
   */
  static formatDuration(seconds) {
    if (seconds < 60) return `${seconds}s`;
    const minutes = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${minutes}m ${secs}s`;
  }

  /**
   * Obtient les infos d'un module
   */
  static getModuleInfo(moduleName) {
    return AVAILABLE_MODULES[moduleName] || null;
  }

  /**
   * Liste tous les modules disponibles
   */
  static listModules() {
    return Object.entries(AVAILABLE_MODULES).map(([key, config]) => ({
      id: key,
      ...config
    }));
  }

  /**
   * Génère un résumé lisible du pipeline
   */
  static getSummary(pipeline) {
    const enabledSteps = pipeline.pipeline.filter(s => s.enabled !== false);
    const moduleCount = {};

    enabledSteps.forEach(step => {
      moduleCount[step.module] = (moduleCount[step.module] || 0) + 1;
    });

    const summary = Object.entries(moduleCount)
      .map(([module, count]) => `${module}×${count}`)
      .join(' → ');

    return {
      totalSteps: enabledSteps.length,
      summary,
      duration: PipelineDefinition.estimateDuration(pipeline)
    };
  }
}

module.exports = {
  PipelineDefinition,
  AVAILABLE_MODULES,
  PIPELINE_SCHEMA,
  STEP_SCHEMA
};


/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/batch/DigitalOceanTemplates.js                          │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// DIGITAL OCEAN TEMPLATES - RÉCUPÉRATION XML
// Responsabilité: Récupération et cache des templates XML depuis DigitalOcean Spaces
// ========================================

require('dotenv').config();
const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const fs = require('fs').promises;
const path = require('path');
const axios = require('axios');
const AWS = require('aws-sdk');

/**
 * DIGITAL OCEAN TEMPLATES MANAGER
 * Gestion récupération, cache et fallback des templates XML
 */
class DigitalOceanTemplates {

  constructor() {
    this.cacheDir = path.join(__dirname, '../../cache/templates');

    // Extraire bucket du endpoint si présent (ex: https://autocollant.fra1.digitaloceanspaces.com)
    let endpoint = process.env.DO_ENDPOINT || process.env.DO_SPACES_ENDPOINT || 'https://fra1.digitaloceanspaces.com';
    let bucket = process.env.DO_BUCKET_NAME || process.env.DO_SPACES_BUCKET || 'autocollant';

    // Si endpoint contient le bucket, le retirer
    if (endpoint.includes(`${bucket}.`)) {
      endpoint = endpoint.replace(`${bucket}.`, '');
    }

    this.config = {
      endpoint: endpoint,
      bucket: bucket,
      region: process.env.DO_REGION || process.env.DO_SPACES_REGION || 'fra1',
      accessKey: process.env.DO_ACCESS_KEY_ID || process.env.DO_SPACES_KEY,
      secretKey: process.env.DO_SECRET_ACCESS_KEY || process.env.DO_SPACES_SECRET,
      timeout: 10000 // 10 secondes
    };

    // Cache en mémoire
    this.memoryCache = new Map();
    this.cacheExpiry = 5 * 60 * 1000; // 5 minutes

    // Templates par défaut
    this.defaultTemplates = {
      'default.xml': this.getDefaultTemplate(),
      'simple.xml': this.getSimpleTemplate(),
      'advanced.xml': this.getAdvancedTemplate()
    };

    this.initializeTemplateManager();
  }

  /**
   * Initialise le gestionnaire de templates
   */
  async initializeTemplateManager() {
    try {
      // Créer le dossier cache
      await fs.mkdir(this.cacheDir, { recursive: true });

      // Vérifier la configuration DO
      this.checkConfiguration();

      logSh('🌊 DigitalOceanTemplates initialisé', 'DEBUG');

    } catch (error) {
      logSh(`❌ Erreur initialisation DigitalOceanTemplates: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Vérifie la configuration Digital Ocean
   */
  checkConfiguration() {
    const hasCredentials = this.config.accessKey && this.config.secretKey;

    if (!hasCredentials) {
      logSh('⚠️ Credentials Digital Ocean manquantes, utilisation cache/fallback uniquement', 'WARNING');
    } else {
      logSh('✅ Configuration Digital Ocean OK', 'DEBUG');
    }

    return hasCredentials;
  }

  // ========================================
  // RÉCUPÉRATION TEMPLATES
  // ========================================

  /**
   * Récupère un template XML (avec cache et fallback)
   */
  async getTemplate(filename) {
    return tracer.run('DigitalOceanTemplates.getTemplate', async () => {
      if (!filename) {
        throw new Error('Nom de fichier template requis');
      }

      logSh(`📋 Récupération template: ${filename}`, 'DEBUG');

      try {
        // 1. Vérifier le cache mémoire
        const memoryCached = this.getFromMemoryCache(filename);
        if (memoryCached) {
          logSh(`⚡ Template ${filename} trouvé en cache mémoire`, 'DEBUG');
          return memoryCached;
        }

        // 2. Vérifier le cache fichier
        const fileCached = await this.getFromFileCache(filename);
        if (fileCached) {
          logSh(`💾 Template ${filename} trouvé en cache fichier`, 'DEBUG');
          this.setMemoryCache(filename, fileCached);
          return fileCached;
        }

        // 3. Récupérer depuis Digital Ocean
        if (this.checkConfiguration()) {
          try {
            const template = await this.fetchFromDigitalOcean(filename);
            if (template) {
              logSh(`🌊 Template ${filename} récupéré depuis Digital Ocean`, 'INFO');

              // Sauvegarder en cache
              await this.saveToFileCache(filename, template);
              this.setMemoryCache(filename, template);

              return template;
            }
          } catch (doError) {
            logSh(`⚠️ Erreur Digital Ocean pour ${filename}: ${doError.message}`, 'WARNING');
          }
        }

        // 4. Fallback sur template par défaut
        const defaultTemplate = this.getDefaultTemplateForFile(filename);
        logSh(`🔄 Utilisation template par défaut pour ${filename}`, 'WARNING');

        return defaultTemplate;

      } catch (error) {
        logSh(`❌ Erreur récupération template ${filename}: ${error.message}`, 'ERROR');

        // Fallback ultime
        return this.getDefaultTemplate();
      }
    });
  }

  /**
   * Récupère depuis Digital Ocean Spaces
   */
  async fetchFromDigitalOcean(filename) {
    return tracer.run('DigitalOceanTemplates.fetchFromDigitalOcean', async () => {
      const fileKey = `wp-content/XML/${filename}`;

      logSh(`🌊 Récupération DO avec authentification S3: ${fileKey}`, 'DEBUG');

      try {
        // Configuration S3 pour Digital Ocean Spaces
        const s3 = new AWS.S3({
          endpoint: this.config.endpoint,
          accessKeyId: this.config.accessKey,
          secretAccessKey: this.config.secretKey,
          region: this.config.region,
          s3ForcePathStyle: false,
          signatureVersion: 'v4'
        });

        const params = {
          Bucket: this.config.bucket,
          Key: fileKey
        };

        logSh(`🔑 S3 getObject: bucket=${this.config.bucket}, key=${fileKey}`, 'DEBUG');

        const data = await s3.getObject(params).promise();
        const template = data.Body.toString('utf-8');

        logSh(`✅ Template ${filename} récupéré depuis DO (${template.length} chars)`, 'INFO');
        return template;

      } catch (error) {
        logSh(`❌ Digital Ocean S3 error: ${error.message} (code: ${error.code})`, 'WARNING');
        throw error;
      }
    });
  }

  // ========================================
  // GESTION CACHE
  // ========================================

  /**
   * Récupère depuis le cache mémoire
   */
  getFromMemoryCache(filename) {
    const cached = this.memoryCache.get(filename);

    if (cached && Date.now() - cached.timestamp < this.cacheExpiry) {
      return cached.content;
    }

    if (cached) {
      this.memoryCache.delete(filename);
    }

    return null;
  }

  /**
   * Sauvegarde en cache mémoire
   */
  setMemoryCache(filename, content) {
    this.memoryCache.set(filename, {
      content,
      timestamp: Date.now()
    });
  }

  /**
   * Récupère depuis le cache fichier
   */
  async getFromFileCache(filename) {
    try {
      const cachePath = path.join(this.cacheDir, filename);
      const stats = await fs.stat(cachePath);

      // Cache valide pendant 1 heure
      const maxAge = 60 * 60 * 1000;
      if (Date.now() - stats.mtime.getTime() < maxAge) {
        const content = await fs.readFile(cachePath, 'utf8');
        return content;
      }
    } catch (error) {
      // Fichier cache n'existe pas ou erreur
    }

    return null;
  }

  /**
   * Sauvegarde en cache fichier
   */
  async saveToFileCache(filename, content) {
    try {
      const cachePath = path.join(this.cacheDir, filename);
      await fs.writeFile(cachePath, content, 'utf8');
      logSh(`💾 Template ${filename} sauvé en cache`, 'DEBUG');
    } catch (error) {
      logSh(`⚠️ Erreur sauvegarde cache ${filename}: ${error.message}`, 'WARNING');
    }
  }

  // ========================================
  // TEMPLATES PAR DÉFAUT
  // ========================================

  /**
   * Retourne le template par défaut approprié
   */
  getDefaultTemplateForFile(filename) {
    const lowerFilename = filename.toLowerCase();

    if (lowerFilename.includes('simple')) {
      return this.defaultTemplates['simple.xml'];
    } else if (lowerFilename.includes('advanced') || lowerFilename.includes('complet')) {
      return this.defaultTemplates['advanced.xml'];
    }

    return this.defaultTemplates['default.xml'];
  }

  /**
   * Template par défaut standard
   */
  getDefaultTemplate() {
    return `<?xml version='1.0' encoding='UTF-8'?>
<article>
  <h1>|Titre_Principal{{T0}}{Rédige un titre H1 accrocheur de maximum 10 mots pour {{MC0}}. Style {{personality.style}}}|</h1>

  <intro>|Introduction{{MC0}}{Rédige une introduction engageante de 2-3 phrases qui présente {{MC0}} et donne envie de lire la suite. Ton {{personality.style}}}|</intro>

  <section>
    <h2>|Titre_H2_1{{MC+1_1}}{Crée un titre H2 informatif sur {{MC+1_1}}. Style {{personality.style}}}|</h2>
    <p>|Paragraphe_1{{MC+1_1}}{Rédige un paragraphe détaillé de 4-5 phrases sur {{MC+1_1}}. Explique les avantages et caractéristiques. Ton {{personality.style}}}|</p>
  </section>

  <section>
    <h2>|Titre_H2_2{{MC+1_2}}{Crée un titre H2 informatif sur {{MC+1_2}}. Style {{personality.style}}}|</h2>
    <p>|Paragraphe_2{{MC+1_2}}{Rédige un paragraphe détaillé de 4-5 phrases sur {{MC+1_2}}. Explique les avantages et caractéristiques. Ton {{personality.style}}}|</p>
  </section>

  <conclusion>|Conclusion{{MC0}}{Conclusion engageante de 2 phrases sur {{MC0}}. Appel à l'action subtil. Ton {{personality.style}}}|</conclusion>
</article>`;
  }

  /**
   * Template simple
   */
  getSimpleTemplate() {
    return `<?xml version='1.0' encoding='UTF-8'?>
<article>
  <h1>|Titre_H1{{T0}}{Titre principal pour {{MC0}}}|</h1>
  <intro>|Introduction{{MC0}}{Introduction pour {{MC0}}}|</intro>
  <content>|Contenu_Principal{{MC0}}{Contenu principal sur {{MC0}}}|</content>
  <conclusion>|Conclusion{{MC0}}{Conclusion sur {{MC0}}}|</conclusion>
</article>`;
  }

  /**
   * Template avancé
   */
  getAdvancedTemplate() {
    return `<?xml version='1.0' encoding='UTF-8'?>
<article>
  <h1>|Titre_Principal{{T0}}{Rédige un titre H1 accrocheur de maximum 10 mots pour {{MC0}}. Style {{personality.style}}}|</h1>

  <intro>|Introduction{{MC0}}{Rédige une introduction engageante de 2-3 phrases qui présente {{MC0}} et donne envie de lire la suite. Ton {{personality.style}}}|</intro>

  <section>
    <h2>|Titre_H2_1{{MC+1_1}}{Crée un titre H2 informatif sur {{MC+1_1}}. Style {{personality.style}}}|</h2>
    <p>|Paragraphe_1{{MC+1_1}}{Rédige un paragraphe détaillé de 4-5 phrases sur {{MC+1_1}}. Explique les avantages et caractéristiques. Ton {{personality.style}}}|</p>
  </section>

  <section>
    <h2>|Titre_H2_2{{MC+1_2}}{Crée un titre H2 informatif sur {{MC+1_2}}. Style {{personality.style}}}|</h2>
    <p>|Paragraphe_2{{MC+1_2}}{Rédige un paragraphe détaillé de 4-5 phrases sur {{MC+1_2}}. Explique les avantages et caractéristiques. Ton {{personality.style}}}|</p>
  </section>

  <section>
    <h2>|Titre_H2_3{{MC+1_3}}{Crée un titre H2 informatif sur {{MC+1_3}}. Style {{personality.style}}}|</h2>
    <p>|Paragraphe_3{{MC+1_3}}{Explique en 4-5 phrases les avantages de {{MC+1_3}} pour {{MC0}}. Ton {{personality.style}}}|</p>
  </section>

  <faq>
    <h2>|FAQ_Titre{Titre de section FAQ accrocheur sur {{MC0}}}|</h2>

    <question>
      <q>|Faq_q_1{{MC+1_1}}{Question fréquente sur {{MC+1_1}} et {{MC0}}}|</q>
      <a>|Faq_a_1{{MC+1_1}}{Réponse claire et précise. 2-3 phrases. Ton {{personality.style}}}|</a>
    </question>

    <question>
      <q>|Faq_q_2{{MC+1_2}}{Question pratique sur {{MC+1_2}} en lien avec {{MC0}}}|</q>
      <a>|Faq_a_2{{MC+1_2}}{Réponse détaillée et utile. 2-3 phrases explicatives. Ton {{personality.style}}}|</a>
    </question>

    <question>
      <q>|Faq_q_3{{MC+1_3}}{Question sur {{MC+1_3}} que se posent les clients}|</q>
      <a>|Faq_a_3{{MC+1_3}}{Réponse complète qui rassure et informe. 2-3 phrases. Ton {{personality.style}}}|</a>
    </question>
  </faq>

  <conclusion>|Conclusion{{MC0}}{Conclusion engageante de 2 phrases sur {{MC0}}. Appel à l'action subtil. Ton {{personality.style}}}|</conclusion>
</article>`;
  }

  // ========================================
  // UTILITAIRES
  // ========================================

  /**
   * Liste les templates disponibles
   */
  async listAvailableTemplates() {
    const templates = [];

    // Templates par défaut
    Object.keys(this.defaultTemplates).forEach(name => {
      templates.push({
        name,
        source: 'default',
        cached: true
      });
    });

    // Templates en cache
    try {
      const cacheFiles = await fs.readdir(this.cacheDir);
      cacheFiles.forEach(file => {
        if (file.endsWith('.xml')) {
          templates.push({
            name: file,
            source: 'cache',
            cached: true
          });
        }
      });
    } catch (error) {
      // Dossier cache n'existe pas
    }

    return templates;
  }

  /**
   * Vide le cache
   */
  async clearCache() {
    try {
      // Vider cache mémoire
      this.memoryCache.clear();

      // Vider cache fichier
      const cacheFiles = await fs.readdir(this.cacheDir);
      for (const file of cacheFiles) {
        if (file.endsWith('.xml')) {
          await fs.unlink(path.join(this.cacheDir, file));
        }
      }

      logSh('🗑️ Cache templates vidé', 'INFO');

    } catch (error) {
      logSh(`❌ Erreur vidage cache: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Retourne les statistiques du cache
   */
  getCacheStats() {
    return {
      memoryCache: {
        size: this.memoryCache.size,
        expiry: this.cacheExpiry
      },
      config: {
        hasCredentials: this.checkConfiguration(),
        endpoint: this.config.endpoint,
        bucket: this.config.bucket,
        timeout: this.config.timeout
      },
      defaultTemplates: Object.keys(this.defaultTemplates).length
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/BrainConfig.js                                          │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: BrainConfig.js - Version Node.js
// Description: Configuration cerveau + sélection personnalité IA
// ========================================

require('dotenv').config();
const axios = require('axios');
const fs = require('fs').promises;
const path = require('path');

// Import de la fonction logSh (assumant qu'elle existe dans votre projet Node.js)
const { logSh } = require('./ErrorReporting');
const { DigitalOceanTemplates } = require('./batch/DigitalOceanTemplates');

// Configuration
const CONFIG = {
  openai: {
    apiKey: process.env.OPENAI_API_KEY,
    endpoint: 'https://api.openai.com/v1/chat/completions'
  },
  dataSource: {
    type: process.env.DATA_SOURCE_TYPE || 'json', // 'json', 'csv', 'database'
    instructionsPath: './data/instructions.json',
    personalitiesPath: './data/personalities.json'
  }
};

/**
 * FONCTION PRINCIPALE - Équivalent getBrainConfig()
 * @param {number|object} data - Numéro de ligne ou données directes
 * @returns {object} Configuration avec données CSV + personnalité
 */
async function getBrainConfig(data) {
  try {
    logSh("🧠 Début getBrainConfig Node.js", "INFO");
    
    // 1. RÉCUPÉRER LES DONNÉES CSV
    let csvData;
    if (typeof data === 'number') {
      // Numéro de ligne fourni - lire depuis fichier
      csvData = await readInstructionsData(data);
    } else if (typeof data === 'object' && data.rowNumber) {
      csvData = await readInstructionsData(data.rowNumber);
    } else {
      // Données déjà fournies
      csvData = data;
    }
    
    logSh(`✅ CSV récupéré: ${csvData.mc0}`, "INFO");
    
    // 2. RÉCUPÉRER LES PERSONNALITÉS
    const personalities = await getPersonalities();
    logSh(`✅ ${personalities.length} personnalités chargées`, "INFO");
    
    // 3. SÉLECTIONNER LA MEILLEURE PERSONNALITÉ VIA IA
    const selectedPersonality = await selectPersonalityWithAI(
      csvData.mc0, 
      csvData.t0, 
      personalities
    );
    
    logSh(`✅ Personnalité sélectionnée: ${selectedPersonality.nom}`, "INFO");
    
    return {
      success: true,
      data: {
        ...csvData,
        personality: selectedPersonality,
        timestamp: new Date().toISOString()
      }
    };
    
  } catch (error) {
    logSh(`❌ Erreur getBrainConfig: ${error.message}`, "ERROR");
    return {
      success: false,
      error: error.message
    };
  }
}

/**
 * LIRE DONNÉES INSTRUCTIONS depuis Google Sheets DIRECTEMENT
 * @param {number} rowNumber - Numéro de ligne (2 = première ligne de données)
 * @returns {object} Données CSV parsées
 */
async function readInstructionsData(rowNumber = 2) {
  try {
    logSh(`📊 Lecture Google Sheet ligne ${rowNumber}...`, 'INFO');
    
    // NOUVEAU : Lecture directe depuis Google Sheets
    const { google } = require('googleapis');
    
    // Configuration auth Google Sheets - FORCE utilisation fichier JSON pour éviter problème TLS
    const keyFilePath = path.join(__dirname, '..', 'seo-generator-470715-85d4a971c1af.json');
    const auth = new google.auth.GoogleAuth({
      keyFile: keyFilePath,
      scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly']
    });
    logSh('🔑 Utilisation fichier JSON pour contourner problème TLS OAuth', 'INFO');
    
    const sheets = google.sheets({ version: 'v4', auth });
    const SHEET_ID = process.env.GOOGLE_SHEETS_ID || '1iA2GvWeUxX-vpnAMfVm3ZMG9LhaC070SdGssEcXAh2c';
    
    // Récupérer la ligne spécifique (A à I au minimum)
    const response = await sheets.spreadsheets.values.get({
      spreadsheetId: SHEET_ID,
      range: `Instructions!A${rowNumber}:I${rowNumber}` // Ligne spécifique A-I
    });
    
    if (!response.data.values || response.data.values.length === 0) {
      throw new Error(`Ligne ${rowNumber} non trouvée dans Google Sheet`);
    }
    
    const row = response.data.values[0];
    logSh(`✅ Ligne ${rowNumber} récupérée: ${row.length} colonnes`, 'INFO');
    
    const xmlTemplateValue = row[8] || '';
    let xmlTemplate = xmlTemplateValue;
    let xmlFileName = null;

    // Si c'est un nom de fichier, le récupérer depuis Digital Ocean
    if (xmlTemplateValue && xmlTemplateValue.endsWith('.xml') && xmlTemplateValue.length < 100) {
      logSh(`🔧 XML filename detected (${xmlTemplateValue}), fetching from Digital Ocean`, 'INFO');
      xmlFileName = xmlTemplateValue;

      // Récupérer le template depuis Digital Ocean
      try {
        const doTemplates = new DigitalOceanTemplates();
        xmlTemplate = await doTemplates.getTemplate(xmlFileName);
        logSh(`✅ Template ${xmlFileName} récupéré depuis Digital Ocean (${xmlTemplate?.length || 0} chars)`, 'INFO');

        if (!xmlTemplate) {
          throw new Error('Template vide récupéré');
        }
      } catch (error) {
        logSh(`⚠️ Erreur récupération ${xmlFileName} depuis DO: ${error.message}. Fallback template par défaut.`, 'WARNING');
        xmlTemplate = createDefaultXMLTemplate();
      }
    }
    
    return {
      rowNumber: rowNumber,
      slug: row[0] || '',           // Colonne A
      t0: row[1] || '',             // Colonne B  
      mc0: row[2] || '',            // Colonne C
      tMinus1: row[3] || '',        // Colonne D
      lMinus1: row[4] || '',        // Colonne E
      mcPlus1: row[5] || '',        // Colonne F
      tPlus1: row[6] || '',         // Colonne G
      lPlus1: row[7] || '',         // Colonne H
      xmlTemplate: xmlTemplate,    // XML template pour processing
      xmlFileName: xmlFileName      // Nom fichier pour Digital Ocean (si applicable)
    };
    
  } catch (error) {
    logSh(`❌ Erreur lecture Google Sheet: ${error.message}`, "ERROR");
    throw error;
  }
}

/**
 * RÉCUPÉRER PERSONNALITÉS depuis l'onglet "Personnalites" du Google Sheet
 * @returns {Array} Liste des personnalités disponibles
 */
async function getPersonalities() {
  try {
    logSh('📊 Lecture personnalités depuis Google Sheet (onglet Personnalites)...', 'INFO');
    
    // Configuration auth Google Sheets - FORCE utilisation fichier JSON pour éviter problème TLS
    const { google } = require('googleapis');
    const keyFilePath = path.join(__dirname, '..', 'seo-generator-470715-85d4a971c1af.json');
    const auth = new google.auth.GoogleAuth({
      keyFile: keyFilePath,
      scopes: ['https://www.googleapis.com/auth/spreadsheets.readonly']
    });
    logSh('🔑 Utilisation fichier JSON pour contourner problème TLS OAuth (personnalités)', 'INFO');
    
    const sheets = google.sheets({ version: 'v4', auth });
    const SHEET_ID = process.env.GOOGLE_SHEETS_ID || '1iA2GvWeUxX-vpnAMfVm3ZMG9LhaC070SdGssEcXAh2c';
    
    // Récupérer toutes les personnalités (après la ligne d'en-tête)
    const response = await sheets.spreadsheets.values.get({
      spreadsheetId: SHEET_ID,
      range: 'Personnalites!A2:O' // Colonnes A à O pour inclure les nouvelles colonnes IA
    });
    
    if (!response.data.values || response.data.values.length === 0) {
      throw new Error('Aucune personnalité trouvée dans l\'onglet Personnalites');
    }
    
    const personalities = [];
    
    // Traiter chaque ligne de personnalité
    response.data.values.forEach((row, index) => {
      if (row[0] && row[0].toString().trim() !== '') { // Si nom existe (colonne A)
        const personality = {
          nom: row[0]?.toString().trim() || '',
          description: row[1]?.toString().trim() || 'Expert généraliste',
          style: row[2]?.toString().trim() || 'professionnel',
          
          // Configuration avancée depuis colonnes Google Sheet
          motsClesSecteurs: parseCSVField(row[3]),
          vocabulairePref: parseCSVField(row[4]),
          connecteursPref: parseCSVField(row[5]),
          erreursTypiques: parseCSVField(row[6]),
          longueurPhrases: row[7]?.toString().trim() || 'moyennes',
          niveauTechnique: row[8]?.toString().trim() || 'moyen',
          ctaStyle: parseCSVField(row[9]),
          defautsSimules: parseCSVField(row[10]),
          
          // NOUVEAU: Configuration IA par étape depuis Google Sheets (colonnes L-O)
          aiEtape1Base: row[11]?.toString().trim().toLowerCase() || '',
          aiEtape2Technique: row[12]?.toString().trim().toLowerCase() || '',
          aiEtape3Transitions: row[13]?.toString().trim().toLowerCase() || '', 
          aiEtape4Style: row[14]?.toString().trim().toLowerCase() || '',
          
          // Backward compatibility
          motsCles: parseCSVField(row[3] || '') // Utilise motsClesSecteurs
        };
        
        personalities.push(personality);
        logSh(`✓ Personnalité chargée: ${personality.nom} (${personality.style})`, 'DEBUG');
      }
    });
    
    logSh(`📊 ${personalities.length} personnalités chargées depuis Google Sheet`, "INFO");
    
    return personalities;
    
  } catch (error) {
    logSh(`❌ ÉCHEC: Impossible de récupérer les personnalités Google Sheets - ${error.message}`, "ERROR");
    throw new Error(`FATAL: Personnalités Google Sheets inaccessibles - arrêt du workflow: ${error.message}`);
  }
}

/**
 * PARSER CHAMP CSV - Helper function
 * @param {string} field - Champ à parser
 * @returns {Array} Liste des éléments parsés
 */
function parseCSVField(field) {
  if (!field || field.toString().trim() === '') return [];
  
  return field.toString()
    .split(',')
    .map(item => item.trim())
    .filter(item => item.length > 0);
}

/**
 * Sélectionner un sous-ensemble aléatoire de personnalités
 * @param {Array} allPersonalities - Liste complète des personnalités
 * @param {number} percentage - Pourcentage à garder (0.6 = 60%)
 * @returns {Array} Sous-ensemble aléatoire
 */
function selectRandomPersonalities(allPersonalities, percentage = 0.6) {
  const count = Math.ceil(allPersonalities.length * percentage);
  
  // Mélanger avec Fisher-Yates shuffle (meilleur que sort())
  const shuffled = [...allPersonalities];
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  }
  
  return shuffled.slice(0, count);
}

/**
 * NOUVELLE FONCTION: Sélection de 4 personnalités complémentaires pour le pipeline multi-AI
 * @param {string} mc0 - Mot-clé principal  
 * @param {string} t0 - Titre principal
 * @param {Array} personalities - Liste des personnalités
 * @returns {Array} 4 personnalités sélectionnées pour chaque étape
 */
async function selectMultiplePersonalitiesWithAI(mc0, t0, personalities) {
  try {
    logSh(`🎭 Sélection MULTI-personnalités IA pour: ${mc0}`, "INFO");
    
    // Sélection aléatoire de 80% des personnalités (plus large pour 4 choix)
    const randomPersonalities = selectRandomPersonalities(personalities, 0.8);
    const totalCount = personalities.length;
    const selectedCount = randomPersonalities.length;
    
    logSh(`🎲 Pool aléatoire: ${selectedCount}/${totalCount} personnalités disponibles`, "DEBUG");
    logSh(`📋 Personnalités dans le pool: ${randomPersonalities.map(p => p.nom).join(', ')}`, "DEBUG");
    
    const prompt = `Choisis 4 personnalités COMPLÉMENTAIRES pour générer du contenu sur "${mc0}":

OBJECTIF: Créer une équipe de 4 rédacteurs avec styles différents mais cohérents

PERSONNALITÉS DISPONIBLES:
${randomPersonalities.map(p => `- ${p.nom}: ${p.description} (Style: ${p.style})`).join('\n')}

RÔLES À ATTRIBUER:
1. GÉNÉRATEUR BASE: Personnalité technique/experte pour la génération initiale
2. ENHANCER TECHNIQUE: Personnalité commerciale/précise pour améliorer les termes techniques  
3. FLUIDITÉ: Personnalité créative/littéraire pour améliorer les transitions
4. STYLE FINAL: Personnalité terrain/accessible pour le style final

CRITÈRES:
- 4 personnalités aux styles DIFFÉRENTS mais complémentaires
- Adapté au secteur: ${mc0}
- Variabilité maximale pour anti-détection
- Éviter les doublons de style

FORMAT DE RÉPONSE (EXACTEMENT 4 noms séparés par des virgules):
Nom1, Nom2, Nom3, Nom4`;

    const requestData = {
      model: "gpt-4o-mini", 
      messages: [{"role": "user", "content": prompt}],
      max_tokens: 100,
      temperature: 1.0
    };

    const response = await axios.post(CONFIG.openai.endpoint, requestData, {
      headers: {
        'Authorization': `Bearer ${CONFIG.openai.apiKey}`,
        'Content-Type': 'application/json'
      },
      timeout: 300000
    });

    const selectedNames = response.data.choices[0].message.content.trim()
      .split(',')
      .map(name => name.trim());
    
    logSh(`🔍 Noms retournés par IA: ${selectedNames.join(', ')}`, "DEBUG");
    
    // Mapper aux vraies personnalités
    const selectedPersonalities = [];
    selectedNames.forEach(name => {
      const personality = randomPersonalities.find(p => p.nom === name);
      if (personality) {
        selectedPersonalities.push(personality);
      }
    });
    
    // Compléter si pas assez de personnalités trouvées (sécurité)
    while (selectedPersonalities.length < 4 && randomPersonalities.length > selectedPersonalities.length) {
      const remaining = randomPersonalities.filter(p => 
        !selectedPersonalities.some(selected => selected.nom === p.nom)
      );
      if (remaining.length > 0) {
        const randomIndex = Math.floor(Math.random() * remaining.length);
        selectedPersonalities.push(remaining[randomIndex]);
      } else {
        break;
      }
    }
    
    // Garantir exactement 4 personnalités
    const final4Personalities = selectedPersonalities.slice(0, 4);
    
    logSh(`✅ Équipe de 4 personnalités sélectionnée:`, "INFO");
    final4Personalities.forEach((p, index) => {
      const roles = ['BASE', 'TECHNIQUE', 'FLUIDITÉ', 'STYLE'];
      logSh(`   ${index + 1}. ${roles[index]}: ${p.nom} (${p.style})`, "INFO");
    });
    
    return final4Personalities;
    
  } catch (error) {
    logSh(`❌ FATAL: Sélection multi-personnalités échouée: ${error.message}`, "ERROR");
    throw new Error(`FATAL: Sélection multi-personnalités IA impossible - arrêt du workflow: ${error.message}`);
  }
}

/**
 * FONCTION LEGACY: Sélection personnalité unique (maintenue pour compatibilité)
 * @param {string} mc0 - Mot-clé principal
 * @param {string} t0 - Titre principal
 * @param {Array} personalities - Liste des personnalités
 * @returns {object} Personnalité sélectionnée
 */
async function selectPersonalityWithAI(mc0, t0, personalities) {
  try {
    logSh(`🤖 Sélection personnalité IA UNIQUE pour: ${mc0}`, "DEBUG");
    
    // Appeler la fonction multi et prendre seulement la première
    const multiPersonalities = await selectMultiplePersonalitiesWithAI(mc0, t0, personalities);
    const selectedPersonality = multiPersonalities[0];
    
    logSh(`✅ Personnalité IA sélectionnée (mode legacy): ${selectedPersonality.nom}`, "INFO");
    
    return selectedPersonality;
    
  } catch (error) {
    logSh(`❌ FATAL: Sélection personnalité par IA échouée: ${error.message}`, "ERROR");
    throw new Error(`FATAL: Sélection personnalité IA inaccessible - arrêt du workflow: ${error.message}`);
  }
}

/**
 * CRÉER TEMPLATE XML PAR DÉFAUT quand colonne I contient un nom de fichier
 * Utilise les données CSV disponibles pour créer un template robuste
 */
function createDefaultXMLTemplate() {
  return `<?xml version="1.0" encoding="UTF-8"?>
<article>
  <header>
    <h1>|Titre_Principal{{T0}}{Rédige un titre H1 accrocheur de maximum 10 mots pour {{MC0}}. Style {{personality.style}}}|</h1>
    <intro>|Introduction{{MC0}}{Rédige une introduction engageante de 2-3 phrases sur {{MC0}}. Ton {{personality.style}}, utilise {{personality.vocabulairePref}}}|</intro>
  </header>
  
  <main>
    <section class="primary">
      <h2>|Titre_H2_1{{MC+1_1}}{Crée un titre H2 informatif sur {{MC+1_1}}. Style {{personality.style}}}|</h2>
      <p>|Paragraphe_1{{MC+1_1}}{Rédige un paragraphe détaillé de 4-5 phrases sur {{MC+1_1}}. Explique les avantages et caractéristiques. Ton {{personality.style}}}|</p>
    </section>
    
    <section class="secondary">
      <h2>|Titre_H2_2{{MC+1_2}}{Titre H2 pour {{MC+1_2}}. Mets en valeur les points forts. Ton {{personality.style}}}|</h2>
      <p>|Paragraphe_2{{MC+1_2}}{Paragraphe de 4-5 phrases sur {{MC+1_2}}. Détaille pourquoi c'est important pour {{MC0}}. Ton {{personality.style}}}|</p>
    </section>
    
    <section class="benefits">
      <h2>|Titre_H2_3{{MC+1_3}}{Titre H2 sur les bénéfices de {{MC+1_3}}. Accrocheur et informatif}|</h2>
      <p>|Paragraphe_3{{MC+1_3}}{Explique en 4-5 phrases les avantages de {{MC+1_3}} pour {{MC0}}. Ton {{personality.style}}}|</p>
    </section>
  </main>
  
  <aside class="faq">
    <h2>|FAQ_Titre{Titre de section FAQ accrocheur sur {{MC0}}}|</h2>
    
    <div class="faq-item">
      <h3>|Faq_q_1{{MC+1_1}}{Question fréquente sur {{MC+1_1}} et {{MC0}}}|</h3>
      <p>|Faq_a_1{{MC+1_1}}{Réponse claire et précise. 2-3 phrases. Ton {{personality.style}}}|</p>
    </div>
    
    <div class="faq-item">
      <h3>|Faq_q_2{{MC+1_2}}{Question pratique sur {{MC+1_2}} en lien avec {{MC0}}}|</h3>
      <p>|Faq_a_2{{MC+1_2}}{Réponse détaillée et utile. 2-3 phrases explicatives. Ton {{personality.style}}}|</p>
    </div>
    
    <div class="faq-item">
      <h3>|Faq_q_3{{MC+1_3}}{Question sur {{MC+1_3}} que se posent les clients}|</h3>
      <p>|Faq_a_3{{MC+1_3}}{Réponse complète qui rassure et informe. 2-3 phrases. Ton {{personality.style}}}|</p>
    </div>
  </aside>
  
  <footer>
    <p>|Conclusion{{MC0}}{Conclusion engageante de 2 phrases sur {{MC0}}. Appel à l'action subtil. Ton {{personality.style}}}|</p>
  </footer>
</article>`;
}

/**
 * CRÉER FICHIERS DE DONNÉES D'EXEMPLE
 * Fonction utilitaire pour initialiser les fichiers JSON
 */
async function createSampleDataFiles() {
  try {
    // Créer répertoire data s'il n'existe pas
    await fs.mkdir('./data', { recursive: true });
    
    // Exemple instructions.json
    const sampleInstructions = [
      {
        slug: "plaque-test",
        t0: "Plaque test signalétique",
        mc0: "plaque signalétique",
        "t-1": "Signalétique",
        "l-1": "/signaletique/",
        "mc+1": "plaque dibond, plaque aluminium, plaque PVC",
        "t+1": "Plaque dibond, Plaque alu, Plaque PVC",
        "l+1": "/plaque-dibond/, /plaque-aluminium/, /plaque-pvc/",
        xmlFileName: "template-plaque.xml"
      }
    ];
    
    // Exemple personalities.json
    const samplePersonalities = [
      {
        nom: "Marc",
        description: "Expert technique en signalétique",
        style: "professionnel et précis",
        motsClesSecteurs: "technique,dibond,aluminium,impression",
        vocabulairePref: "précision,qualité,expertise,performance",
        connecteursPref: "par ailleurs,en effet,notamment,cependant",
        erreursTypiques: "accord_proximite,repetition_legere",
        longueurPhrases: "moyennes",
        niveauTechnique: "élevé",
        ctaStyle: "découvrir,choisir,commander",
        defautsSimules: "fatigue_cognitive,hesitation_technique"
      },
      {
        nom: "Sophie",
        description: "Passionnée de décoration et design",
        style: "familier et chaleureux",
        motsClesSecteurs: "décoration,design,esthétique,tendances",
        vocabulairePref: "joli,magnifique,tendance,style",
        connecteursPref: "du coup,en fait,sinon,au fait",
        erreursTypiques: "familiarite_excessive,expression_populaire",
        longueurPhrases: "courtes",
        niveauTechnique: "moyen",
        ctaStyle: "craquer,adopter,foncer",
        defautsSimules: "enthousiasme_variable,anecdote_personnelle"
      }
    ];
    
    // Écrire les fichiers
    await fs.writeFile('./data/instructions.json', JSON.stringify(sampleInstructions, null, 2));
    await fs.writeFile('./data/personalities.json', JSON.stringify(samplePersonalities, null, 2));
    
    logSh('✅ Fichiers de données d\'exemple créés dans ./data/', "INFO");
    
  } catch (error) {
    logSh(`❌ Erreur création fichiers exemple: ${error.message}`, "ERROR");
  }
}

// ============= EXPORTS NODE.JS =============

module.exports = {
  getBrainConfig,
  getPersonalities,
  selectPersonalityWithAI,
  selectMultiplePersonalitiesWithAI,  // NOUVEAU: Export de la fonction multi-personnalités
  selectRandomPersonalities,
  parseCSVField,
  readInstructionsData,
  createSampleDataFiles,
  createDefaultXMLTemplate,
  CONFIG
};

// ============= TEST RAPIDE SI LANCÉ DIRECTEMENT =============

if (require.main === module) {
  (async () => {
    try {
      logSh('🧪 Test BrainConfig Node.js...', "INFO");
      
      // Créer fichiers exemple si nécessaire
      try {
        await fs.access('./data/instructions.json');
      } catch {
        await createSampleDataFiles();
      }
      
      // Test de la fonction principale
      const result = await getBrainConfig(2);
      
      if (result.success) {
        logSh(`✅ Test réussi: ${result.data.personality.nom} pour ${result.data.mc0}`, "INFO");
      } else {
        logSh(`❌ Test échoué: ${result.error}`, "ERROR");
      }
      
    } catch (error) {
      logSh(`❌ Erreur test: ${error.message}`, "ERROR");
    }
  })();
}

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/LLMManager.js                                           │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: LLMManager.js
// Description: Hub central pour tous les appels LLM (Version Node.js)
// Support: Claude, OpenAI, Gemini, Deepseek, Moonshot, Mistral
// ========================================

const fetch = globalThis.fetch.bind(globalThis);
const { logSh } = require('./ErrorReporting');

// Charger les variables d'environnement
require('dotenv').config();

// ============= CONFIGURATION CENTRALISÉE =============

const LLM_CONFIG = {
  openai: {
    apiKey: process.env.OPENAI_API_KEY,
    endpoint: 'https://api.openai.com/v1/chat/completions',
    model: 'gpt-4o-mini',
    headers: {
      'Authorization': 'Bearer {API_KEY}',
      'Content-Type': 'application/json'
    },
    temperature: 0.7,
    timeout: 300000, // 5 minutes
    retries: 3
  },

  claude: {
    apiKey: process.env.ANTHROPIC_API_KEY,
    endpoint: 'https://api.anthropic.com/v1/messages',
    model: 'claude-sonnet-4-20250514',
    headers: {
      'x-api-key': '{API_KEY}',
      'Content-Type': 'application/json',
      'anthropic-version': '2023-06-01'
    },
    temperature: 0.7,
    maxTokens: 6000,
    timeout: 300000, // 5 minutes
    retries: 6
  },

  deepseek: {
    apiKey: process.env.DEEPSEEK_API_KEY,
    endpoint: 'https://api.deepseek.com/v1/chat/completions',
    model: 'deepseek-chat',
    headers: {
      'Authorization': 'Bearer {API_KEY}',
      'Content-Type': 'application/json'
    },
    temperature: 0.7,
    timeout: 300000, // 5 minutes
    retries: 3
  },
  
  moonshot: {
    apiKey: process.env.MOONSHOT_API_KEY,
    endpoint: 'https://api.moonshot.ai/v1/chat/completions',
    model: 'moonshot-v1-32k',
    headers: {
      'Authorization': 'Bearer {API_KEY}',
      'Content-Type': 'application/json'
    },
    temperature: 0.7,
    timeout: 300000, // 5 minutes
    retries: 3
  },
  
  mistral: {
    apiKey: process.env.MISTRAL_API_KEY,
    endpoint: 'https://api.mistral.ai/v1/chat/completions',
    model: 'mistral-small-latest',
    headers: {
      'Authorization': 'Bearer {API_KEY}',
      'Content-Type': 'application/json'
    },
    max_tokens: 5000,
    temperature: 0.7,
    timeout: 300000, // 5 minutes
    retries: 3
  }
};

// Alias pour compatibilité avec le code existant
LLM_CONFIG.gpt4 = LLM_CONFIG.openai;

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

const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

// ============= INTERFACE UNIVERSELLE =============

/**
 * Fonction principale pour appeler n'importe quel LLM
 * @param {string} llmProvider - claude|openai|deepseek|moonshot|mistral
 * @param {string} prompt - Le prompt à envoyer
 * @param {object} options - Options personnalisées (température, tokens, etc.)
 * @param {object} personality - Personnalité pour contexte système
 * @returns {Promise<string>} - Réponse générée
 */
async function callLLM(llmProvider, prompt, options = {}, personality = null) {
  const startTime = Date.now();
  
  try {
    // Vérifier si le provider existe
    if (!LLM_CONFIG[llmProvider]) {
      throw new Error(`Provider LLM inconnu: ${llmProvider}`);
    }
    
    // Vérifier si l'API key est configurée
    const config = LLM_CONFIG[llmProvider];
    if (!config.apiKey || config.apiKey.startsWith('VOTRE_CLE_')) {
      throw new Error(`Clé API manquante pour ${llmProvider}`);
    }
    
    logSh(`🤖 Appel LLM: ${llmProvider.toUpperCase()} (${config.model}) | Personnalité: ${personality?.nom || 'aucune'}`, 'DEBUG');
    
    // 📢 AFFICHAGE PROMPT COMPLET POUR DEBUG AVEC INFO IA
    logSh(`\n🔍 ===== PROMPT ENVOYÉ À ${llmProvider.toUpperCase()} (${config.model}) | PERSONNALITÉ: ${personality?.nom || 'AUCUNE'} =====`, 'PROMPT');
    logSh(prompt, 'PROMPT');
    
    // 📤 LOG LLM REQUEST COMPLET
    logSh(`📤 LLM REQUEST [${llmProvider.toUpperCase()}] (${config.model}) | Personnalité: ${personality?.nom || 'AUCUNE'}`, 'LLM');
    logSh(prompt, 'LLM');
    
    // Préparer la requête selon le provider
    const requestData = buildRequestData(llmProvider, prompt, options, personality);
    
    // Effectuer l'appel avec retry logic
    const response = await callWithRetry(llmProvider, requestData, config);
    
    // Parser la réponse selon le format du provider
    const content = parseResponse(llmProvider, response);
    
    // 📥 LOG LLM RESPONSE COMPLET
    logSh(`📥 LLM RESPONSE [${llmProvider.toUpperCase()}] (${config.model}) | Durée: ${Date.now() - startTime}ms`, 'LLM');
    logSh(content, 'LLM');
    
    const duration = Date.now() - startTime;
    logSh(`✅ ${llmProvider.toUpperCase()} (${personality?.nom || 'sans personnalité'}) réponse en ${duration}ms`, 'INFO');
    
    // Enregistrer les stats d'usage
    await recordUsageStats(llmProvider, prompt.length, content.length, duration);
    
    return content;
    
  } catch (error) {
    const duration = Date.now() - startTime;
    logSh(`❌ Erreur ${llmProvider.toUpperCase()} (${personality?.nom || 'sans personnalité'}): ${error.toString()}`, 'ERROR');
    
    // Enregistrer l'échec
    await recordUsageStats(llmProvider, prompt.length, 0, duration, error.toString());
    
    throw error;
  }
}

// ============= CONSTRUCTION DES REQUÊTES =============

function buildRequestData(provider, prompt, options, personality) {
  const config = LLM_CONFIG[provider];
  const temperature = options.temperature || config.temperature;
  const maxTokens = options.maxTokens || config.maxTokens;
  
  // Construire le système prompt si personnalité fournie
  const systemPrompt = personality ? 
    `Tu es ${personality.nom}. ${personality.description}. Style: ${personality.style}` : 
    'Tu es un assistant expert.';
  
  switch (provider) {
    case 'openai':
    case 'gpt4':
    case 'deepseek':
    case 'moonshot':
    case 'mistral':
      return {
        model: config.model,
        messages: [
          { role: 'system', content: systemPrompt },
          { role: 'user', content: prompt }
        ],
        max_tokens: maxTokens,
        temperature: temperature,
        stream: false
      };
    
    case 'claude':
      return {
        model: config.model,
        max_tokens: maxTokens,
        temperature: temperature,
        system: systemPrompt,
        messages: [
          { role: 'user', content: prompt }
        ]
      };
    
    
    default:
      throw new Error(`Format de requête non supporté pour ${provider}`);
  }
}

// ============= APPELS AVEC RETRY =============

async function callWithRetry(provider, requestData, config) {
  let lastError;
  
  for (let attempt = 1; attempt <= config.retries; attempt++) {
    try {
      logSh(`🔄 Tentative ${attempt}/${config.retries} pour ${provider.toUpperCase()}`, 'DEBUG');
      
      // Préparer les headers avec la clé API
      const headers = {};
      Object.keys(config.headers).forEach(key => {
        headers[key] = config.headers[key].replace('{API_KEY}', config.apiKey);
      });
      
      // URL standard
      let url = config.endpoint;
      
      const options = {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(requestData),
        timeout: config.timeout
      };
      
      const response = await fetch(url, options);
      const responseText = await response.text();
      
      if (response.ok) {
        return JSON.parse(responseText);
      } else if (response.status === 429) {
        // Rate limiting - attendre plus longtemps
        const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff
        logSh(`⏳ Rate limit ${provider.toUpperCase()}, attente ${waitTime}ms`, 'WARNING');
        await sleep(waitTime);
        continue;
      } else {
        throw new Error(`HTTP ${response.status}: ${responseText}`);
      }
      
    } catch (error) {
      lastError = error;
      
      if (attempt < config.retries) {
        const waitTime = 1000 * attempt;
        logSh(`⚠ Erreur tentative ${attempt}: ${error.toString()}, retry dans ${waitTime}ms`, 'WARNING');
        await sleep(waitTime);
      }
    }
  }
  
  throw new Error(`Échec après ${config.retries} tentatives: ${lastError.toString()}`);
}

// ============= PARSING DES RÉPONSES =============

function parseResponse(provider, responseData) {
  try {
    switch (provider) {
      case 'openai':
      case 'gpt4':
      case 'deepseek':
      case 'moonshot':
      case 'mistral':
        return responseData.choices[0].message.content.trim();
      
      case 'claude':
        return responseData.content[0].text.trim();
      
      default:
        throw new Error(`Parser non supporté pour ${provider}`);
    }
  } catch (error) {
    logSh(`❌ Erreur parsing ${provider}: ${error.toString()}`, 'ERROR');
    logSh(`Response brute: ${JSON.stringify(responseData)}`, 'DEBUG');
    throw new Error(`Impossible de parser la réponse ${provider}: ${error.toString()}`);
  }
}

// ============= GESTION DES STATISTIQUES =============

async function recordUsageStats(provider, promptTokens, responseTokens, duration, error = null) {
  try {
    // TODO: Adapter selon votre système de stockage Node.js
    // Peut être une base de données, un fichier, MongoDB, etc.
    const statsData = {
      timestamp: new Date(),
      provider: provider,
      model: LLM_CONFIG[provider].model,
      promptTokens: promptTokens,
      responseTokens: responseTokens,
      duration: duration,
      error: error || ''
    };
    
    // Exemple: log vers console ou fichier
    logSh(`📊 Stats: ${JSON.stringify(statsData)}`, 'DEBUG');
    
    // TODO: Implémenter sauvegarde réelle (DB, fichier, etc.)
    
  } catch (statsError) {
    // Ne pas faire planter le workflow si les stats échouent
    logSh(`⚠ Erreur enregistrement stats: ${statsError.toString()}`, 'WARNING');
  }
}

// ============= FONCTIONS UTILITAIRES =============

/**
 * Tester la connectivité de tous les LLMs
 */
async function testAllLLMs() {
  const testPrompt = "Dis bonjour en 5 mots maximum.";
  const results = {};
  
  const allProviders = Object.keys(LLM_CONFIG);
  
  for (const provider of allProviders) {
    try {
      logSh(`🧪 Test ${provider}...`, 'INFO');
      
      const response = await callLLM(provider, testPrompt);
      results[provider] = {
        status: 'SUCCESS',
        response: response,
        model: LLM_CONFIG[provider].model
      };
      
    } catch (error) {
      results[provider] = {
        status: 'ERROR',
        error: error.toString(),
        model: LLM_CONFIG[provider].model
      };
    }
    
    // Petit délai entre tests
    await sleep(500);
  }
  
  logSh(`📊 Tests terminés: ${JSON.stringify(results, null, 2)}`, 'INFO');
  return results;
}

/**
 * Obtenir les providers disponibles (avec clés API valides)
 */
function getAvailableProviders() {
  const available = [];
  
  Object.keys(LLM_CONFIG).forEach(provider => {
    const config = LLM_CONFIG[provider];
    if (config.apiKey && !config.apiKey.startsWith('VOTRE_CLE_')) {
      available.push(provider);
    }
  });
  
  return available;
}

/**
 * Obtenir des statistiques d'usage par provider
 */
async function getUsageStats() {
  try {
    // TODO: Adapter selon votre système de stockage
    // Pour l'instant retourne un message par défaut
    return { message: 'Statistiques non implémentées en Node.js' };
    
  } catch (error) {
    return { error: error.toString() };
  }
}

// ============= MIGRATION DE L'ANCIEN CODE =============

/**
 * Fonction de compatibilité pour remplacer votre ancien callOpenAI()
 * Maintient la même signature pour ne pas casser votre code existant
 */
async function callOpenAI(prompt, personality) {
  return await callLLM('openai', prompt, {}, personality);
}

// ============= EXPORTS POUR TESTS =============

/**
 * Fonction de test rapide
 */
async function testLLMManager() {
  logSh('🚀 Test du LLM Manager Node.js...', 'INFO');
  
  // Test des providers disponibles
  const available = getAvailableProviders();
  logSh('Providers disponibles: ' + available.join(', ') + ' (' + available.length + '/5)', 'INFO');
  
  // Test d'appel simple sur chaque provider disponible
  for (const provider of available) {
    try {
      logSh(`🧪 Test ${provider}...`, 'DEBUG');
      const startTime = Date.now();
      
      const response = await callLLM(provider, 'Dis juste "Test OK"');
      const duration = Date.now() - startTime;
      
      logSh(`✅ Test ${provider} réussi: "${response}" (${duration}ms)`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Test ${provider} échoué: ${error.toString()}`, 'ERROR');
    }
    
    // Petit délai pour éviter rate limits
    await sleep(500);
  }
  
  // Test spécifique OpenAI (compatibilité avec ancien code)
  try {
    logSh('🎯 Test spécifique OpenAI (compatibilité)...', 'DEBUG');
    const response = await callLLM('openai', 'Dis juste "Test OK"');
    logSh('✅ Test OpenAI compatibilité: ' + response, 'INFO');
  } catch (error) {
    logSh('❌ Test OpenAI compatibilité échoué: ' + error.toString(), 'ERROR');
  }
  
  // Afficher les stats d'usage
  try {
    logSh('📊 Récupération statistiques d\'usage...', 'DEBUG');
    const stats = await getUsageStats();
    
    if (stats.error) {
      logSh('⚠ Erreur récupération stats: ' + stats.error, 'WARNING');
    } else if (stats.message) {
      logSh('📊 Stats: ' + stats.message, 'INFO');
    } else {
      // Formatter les stats pour les logs
      Object.keys(stats).forEach(provider => {
        const s = stats[provider];
        logSh(`📈 ${provider}: ${s.calls} appels, ${s.successRate}% succès, ${s.avgDuration}ms moyen`, 'INFO');
      });
    }
  } catch (error) {
    logSh('❌ Erreur lors de la récupération des stats: ' + error.toString(), 'ERROR');
  }
  
  // Résumé final
  const workingCount = available.length;
  const totalProviders = Object.keys(LLM_CONFIG).length;
  
  if (workingCount === totalProviders) {
    logSh(`✅ Test LLM Manager COMPLET: ${workingCount}/${totalProviders} providers opérationnels`, 'INFO');
  } else if (workingCount >= 2) {
    logSh(`✅ Test LLM Manager PARTIEL: ${workingCount}/${totalProviders} providers opérationnels (suffisant pour DNA Mixing)`, 'INFO');
  } else {
    logSh(`❌ Test LLM Manager INSUFFISANT: ${workingCount}/${totalProviders} providers opérationnels (minimum 2 requis)`, 'ERROR');
  }
  
  logSh('🏁 Test LLM Manager terminé', 'INFO');
}

/**
 * Version complète avec test de tous les providers (même non configurés)
 */
async function testLLMManagerComplete() {
  logSh('🚀 Test COMPLET du LLM Manager (tous providers)...', 'INFO');
  
  const allProviders = Object.keys(LLM_CONFIG);
  logSh(`Providers configurés: ${allProviders.join(', ')}`, 'INFO');
  
  const results = {
    configured: 0,
    working: 0,
    failed: 0
  };
  
  for (const provider of allProviders) {
    const config = LLM_CONFIG[provider];
    
    // Vérifier si configuré
    if (!config.apiKey || config.apiKey.startsWith('VOTRE_CLE_')) {
      logSh(`⚙️ ${provider}: NON CONFIGURÉ (clé API manquante)`, 'WARNING');
      continue;
    }
    
    results.configured++;
    
    try {
      logSh(`🧪 Test ${provider} (${config.model})...`, 'DEBUG');
      const startTime = Date.now();
      
      const response = await callLLM(provider, 'Réponds "OK" seulement.', { maxTokens: 100 });
      const duration = Date.now() - startTime;
      
      results.working++;
      logSh(`✅ ${provider}: "${response.trim()}" (${duration}ms)`, 'INFO');
      
    } catch (error) {
      results.failed++;
      logSh(`❌ ${provider}: ${error.toString()}`, 'ERROR');
    }
    
    // Délai entre tests
    await sleep(700);
  }
  
  // Résumé final complet
  logSh(`📊 RÉSUMÉ FINAL:`, 'INFO');
  logSh(`   • Providers total: ${allProviders.length}`, 'INFO');
  logSh(`   • Configurés: ${results.configured}`, 'INFO');
  logSh(`   • Fonctionnels: ${results.working}`, 'INFO');
  logSh(`   • En échec: ${results.failed}`, 'INFO');
  
  const status = results.working >= 4 ? 'EXCELLENT' : 
                 results.working >= 2 ? 'BON' : 'INSUFFISANT';
                 
  logSh(`🏆 STATUS: ${status} (${results.working} LLMs opérationnels)`, 
        status === 'INSUFFISANT' ? 'ERROR' : 'INFO');
  
  logSh('🏁 Test LLM Manager COMPLET terminé', 'INFO');
  
  return {
    total: allProviders.length,
    configured: results.configured,
    working: results.working,
    failed: results.failed,
    status: status
  };
}

// ============= EXPORTS MODULE =============

module.exports = {
  callLLM,
  callOpenAI,
  testAllLLMs,
  getAvailableProviders,
  getUsageStats,
  testLLMManager,
  testLLMManagerComplete,
  LLM_CONFIG
};



/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/SelectiveUtils.js                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// SELECTIVE UTILS - UTILITAIRES MODULAIRES
// Responsabilité: Fonctions utilitaires partagées par tous les modules selective
// Architecture: Helper functions réutilisables et composables
// ========================================

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

/**
 * ANALYSEURS DE CONTENU SELECTIVE
 */

/**
 * Analyser qualité technique d'un contenu
 */
function analyzeTechnicalQuality(content, contextualTerms = []) {
  if (!content || typeof content !== 'string') return { score: 0, details: {} };
  
  const analysis = {
    score: 0,
    details: {
      technicalTermsFound: 0,
      technicalTermsExpected: contextualTerms.length,
      genericWordsCount: 0,
      hasSpecifications: false,
      hasDimensions: false,
      contextIntegration: 0
    }
  };
  
  const lowerContent = content.toLowerCase();
  
  // 1. Compter termes techniques présents
  contextualTerms.forEach(term => {
    if (lowerContent.includes(term.toLowerCase())) {
      analysis.details.technicalTermsFound++;
    }
  });
  
  // 2. Détecter mots génériques
  const genericWords = ['produit', 'solution', 'service', 'offre', 'article', 'élément'];
  analysis.details.genericWordsCount = genericWords.filter(word => 
    lowerContent.includes(word)
  ).length;
  
  // 3. Vérifier spécifications techniques
  analysis.details.hasSpecifications = /\b(norme|iso|din|ce)\b/i.test(content);
  
  // 4. Vérifier dimensions/données techniques
  analysis.details.hasDimensions = /\d+\s*(mm|cm|m|%|°|kg|g)\b/i.test(content);
  
  // 5. Calculer score global (0-100)
  const termRatio = contextualTerms.length > 0 ? 
    (analysis.details.technicalTermsFound / contextualTerms.length) * 40 : 20;
  const genericPenalty = Math.min(20, analysis.details.genericWordsCount * 5);
  const specificationBonus = analysis.details.hasSpecifications ? 15 : 0;
  const dimensionBonus = analysis.details.hasDimensions ? 15 : 0;
  const lengthBonus = content.length > 100 ? 10 : 0;
  
  analysis.score = Math.max(0, Math.min(100, 
    termRatio + specificationBonus + dimensionBonus + lengthBonus - genericPenalty
  ));
  
  return analysis;
}

/**
 * Analyser fluidité des transitions
 */
function analyzeTransitionFluidity(content) {
  if (!content || typeof content !== 'string') return { score: 0, details: {} };
  
  const sentences = content.split(/[.!?]+/)
    .map(s => s.trim())
    .filter(s => s.length > 5);
    
  if (sentences.length < 2) {
    return { score: 100, details: { reason: 'Contenu trop court pour analyse transitions' } };
  }
  
  const analysis = {
    score: 0,
    details: {
      sentencesCount: sentences.length,
      connectorsFound: 0,
      repetitiveConnectors: 0,
      abruptTransitions: 0,
      averageSentenceLength: 0,
      lengthVariation: 0
    }
  };
  
  // 1. Analyser connecteurs
  const commonConnectors = ['par ailleurs', 'en effet', 'de plus', 'cependant', 'ainsi', 'donc', 'ensuite'];
  const connectorCounts = {};
  
  commonConnectors.forEach(connector => {
    const matches = (content.match(new RegExp(`\\b${connector}\\b`, 'gi')) || []);
    connectorCounts[connector] = matches.length;
    analysis.details.connectorsFound += matches.length;
    if (matches.length > 1) analysis.details.repetitiveConnectors++;
  });
  
  // 2. Détecter transitions abruptes
  for (let i = 1; i < sentences.length; i++) {
    const sentence = sentences[i].toLowerCase().trim();
    const hasConnector = commonConnectors.some(connector => 
      sentence.startsWith(connector) || sentence.includes(` ${connector} `)
    );
    
    if (!hasConnector && sentence.length > 20) {
      analysis.details.abruptTransitions++;
    }
  }
  
  // 3. Analyser variation de longueur
  const lengths = sentences.map(s => s.split(/\s+/).length);
  analysis.details.averageSentenceLength = lengths.reduce((a, b) => a + b, 0) / lengths.length;
  
  const variance = lengths.reduce((acc, len) => 
    acc + Math.pow(len - analysis.details.averageSentenceLength, 2), 0
  ) / lengths.length;
  analysis.details.lengthVariation = Math.sqrt(variance);
  
  // 4. Calculer score fluidité (0-100)
  const connectorScore = Math.min(30, (analysis.details.connectorsFound / sentences.length) * 100);
  const repetitionPenalty = Math.min(20, analysis.details.repetitiveConnectors * 5);
  const abruptPenalty = Math.min(30, (analysis.details.abruptTransitions / sentences.length) * 50);
  const variationScore = Math.min(20, analysis.details.lengthVariation * 2);
  
  analysis.score = Math.max(0, Math.min(100,
    connectorScore + variationScore - repetitionPenalty - abruptPenalty + 50
  ));
  
  return analysis;
}

/**
 * Analyser cohérence de style
 */
function analyzeStyleConsistency(content, expectedPersonality = null) {
  if (!content || typeof content !== 'string') return { score: 0, details: {} };
  
  const analysis = {
    score: 0,
    details: {
      personalityAlignment: 0,
      toneConsistency: 0,
      vocabularyLevel: 'standard',
      formalityScore: 0,
      personalityWordsFound: 0
    }
  };
  
  // 1. Analyser alignement personnalité
  if (expectedPersonality && expectedPersonality.vocabulairePref) {
    const personalityWords = expectedPersonality.vocabulairePref.toLowerCase().split(',');
    const contentLower = content.toLowerCase();
    
    personalityWords.forEach(word => {
      if (word.trim() && contentLower.includes(word.trim())) {
        analysis.details.personalityWordsFound++;
      }
    });
    
    analysis.details.personalityAlignment = personalityWords.length > 0 ?
      (analysis.details.personalityWordsFound / personalityWords.length) * 100 : 0;
  }
  
  // 2. Analyser niveau vocabulaire
  const technicalWords = content.match(/\b\w{8,}\b/g) || [];
  const totalWords = content.split(/\s+/).length;
  const techRatio = technicalWords.length / totalWords;
  
  if (techRatio > 0.15) analysis.details.vocabularyLevel = 'expert';
  else if (techRatio < 0.05) analysis.details.vocabularyLevel = 'accessible';
  else analysis.details.vocabularyLevel = 'standard';
  
  // 3. Analyser formalité
  const formalIndicators = ['il convient de', 'par conséquent', 'néanmoins', 'toutefois'];
  const casualIndicators = ['du coup', 'sympa', 'cool', 'nickel'];
  
  let formalCount = formalIndicators.filter(indicator => 
    content.toLowerCase().includes(indicator)
  ).length;
  
  let casualCount = casualIndicators.filter(indicator => 
    content.toLowerCase().includes(indicator)
  ).length;
  
  analysis.details.formalityScore = formalCount - casualCount; // Positif = formel, négatif = casual
  
  // 4. Calculer score cohérence (0-100)
  let baseScore = 50;
  
  if (expectedPersonality) {
    baseScore += analysis.details.personalityAlignment * 0.3;
    
    // Ajustements selon niveau technique attendu
    const expectedLevel = expectedPersonality.niveauTechnique || 'standard';
    if (expectedLevel === analysis.details.vocabularyLevel) {
      baseScore += 20;
    } else {
      baseScore -= 10;
    }
  }
  
  // Bonus cohérence tonale
  const sentences = content.split(/[.!?]+/).filter(s => s.length > 10);
  if (sentences.length > 1) {
    baseScore += Math.min(20, analysis.details.lengthVariation || 10);
  }
  
  analysis.score = Math.max(0, Math.min(100, baseScore));
  
  return analysis;
}

/**
 * COMPARATEURS ET MÉTRIQUES
 */

/**
 * Comparer deux contenus et calculer taux amélioration
 */
function compareContentImprovement(original, enhanced, analysisType = 'general') {
  if (!original || !enhanced) return { improvementRate: 0, details: {} };
  
  const comparison = {
    improvementRate: 0,
    details: {
      lengthChange: ((enhanced.length - original.length) / original.length) * 100,
      wordCountChange: 0,
      structuralChanges: 0,
      contentPreserved: true
    }
  };
  
  // 1. Analyser changements structurels
  const originalSentences = original.split(/[.!?]+/).length;
  const enhancedSentences = enhanced.split(/[.!?]+/).length;
  comparison.details.structuralChanges = Math.abs(enhancedSentences - originalSentences);
  
  // 2. Analyser changements de mots
  const originalWords = original.toLowerCase().split(/\s+/).filter(w => w.length > 2);
  const enhancedWords = enhanced.toLowerCase().split(/\s+/).filter(w => w.length > 2);
  comparison.details.wordCountChange = enhancedWords.length - originalWords.length;
  
  // 3. Vérifier préservation du contenu principal
  const originalKeyWords = originalWords.filter(w => w.length > 4);
  const preservedWords = originalKeyWords.filter(w => enhanced.toLowerCase().includes(w));
  comparison.details.contentPreserved = (preservedWords.length / originalKeyWords.length) > 0.7;
  
  // 4. Calculer taux amélioration selon type d'analyse
  switch (analysisType) {
    case 'technical':
      const originalTech = analyzeTechnicalQuality(original);
      const enhancedTech = analyzeTechnicalQuality(enhanced);
      comparison.improvementRate = enhancedTech.score - originalTech.score;
      break;
      
    case 'transitions':
      const originalFluid = analyzeTransitionFluidity(original);
      const enhancedFluid = analyzeTransitionFluidity(enhanced);
      comparison.improvementRate = enhancedFluid.score - originalFluid.score;
      break;
      
    case 'style':
      const originalStyle = analyzeStyleConsistency(original);
      const enhancedStyle = analyzeStyleConsistency(enhanced);
      comparison.improvementRate = enhancedStyle.score - originalStyle.score;
      break;
      
    default:
      // Amélioration générale (moyenne pondérée)
      comparison.improvementRate = Math.min(50, Math.abs(comparison.details.lengthChange) * 0.1 +
        (comparison.details.contentPreserved ? 20 : -20) +
        Math.min(15, Math.abs(comparison.details.wordCountChange)));
  }
  
  return comparison;
}

/**
 * UTILITAIRES DE CONTENU
 */

/**
 * Nettoyer contenu généré par LLM
 */
function cleanGeneratedContent(content, cleaningLevel = 'standard') {
  if (!content || typeof content !== 'string') return content;
  
  let cleaned = content.trim();
  
  // Nettoyage de base
  cleaned = cleaned.replace(/^(voici\s+)?le\s+contenu\s+(amélioré|modifié|réécrit)[:\s]*/gi, '');
  cleaned = cleaned.replace(/^(bon,?\s*)?(alors,?\s*)?(voici\s+)?/gi, '');
  cleaned = cleaned.replace(/^(avec\s+les?\s+)?améliorations?\s*[:\s]*/gi, '');
  
  // Nettoyage formatage
  cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1'); // Gras markdown → texte normal
  cleaned = cleaned.replace(/\s{2,}/g, ' '); // Espaces multiples
  cleaned = cleaned.replace(/([.!?])\s*([.!?])/g, '$1 '); // Double ponctuation
  
  if (cleaningLevel === 'intensive') {
    // Nettoyage intensif
    cleaned = cleaned.replace(/^\s*[-*+]\s*/gm, ''); // Puces en début de ligne
    cleaned = cleaned.replace(/^(pour\s+)?(ce\s+)?(contenu\s*)?[,:]?\s*/gi, '');
    cleaned = cleaned.replace(/\([^)]*\)/g, ''); // Parenthèses et contenu
  }
  
  // Nettoyage final
  cleaned = cleaned.replace(/^[,.\s]+/, ''); // Début
  cleaned = cleaned.replace(/[,\s]+$/, ''); // Fin
  cleaned = cleaned.trim();
  
  return cleaned;
}

/**
 * Valider contenu selective
 */
function validateSelectiveContent(content, originalContent, criteria = {}) {
  const validation = {
    isValid: true,
    score: 0,
    issues: [],
    suggestions: []
  };
  
  const {
    minLength = 20,
    maxLengthChange = 50, // % de changement maximum
    preserveContent = true,
    checkTechnicalTerms = true
  } = criteria;
  
  // 1. Vérifier longueur
  if (!content || content.length < minLength) {
    validation.isValid = false;
    validation.issues.push('Contenu trop court');
    validation.suggestions.push('Augmenter la longueur du contenu généré');
  } else {
    validation.score += 25;
  }
  
  // 2. Vérifier changements de longueur
  if (originalContent) {
    const lengthChange = Math.abs((content.length - originalContent.length) / originalContent.length) * 100;
    
    if (lengthChange > maxLengthChange) {
      validation.issues.push('Changement de longueur excessif');
      validation.suggestions.push('Réduire l\'intensité d\'amélioration');
    } else {
      validation.score += 25;
    }
    
    // 3. Vérifier préservation du contenu
    if (preserveContent) {
      const preservation = compareContentImprovement(originalContent, content);
      
      if (!preservation.details.contentPreserved) {
        validation.isValid = false;
        validation.issues.push('Contenu original non préservé');
        validation.suggestions.push('Améliorer conservation du sens original');
      } else {
        validation.score += 25;
      }
    }
  }
  
  // 4. Vérifications spécifiques
  if (checkTechnicalTerms) {
    const technicalQuality = analyzeTechnicalQuality(content);
    
    if (technicalQuality.score > 60) {
      validation.score += 25;
    } else if (technicalQuality.score < 30) {
      validation.issues.push('Qualité technique insuffisante');
      validation.suggestions.push('Ajouter plus de termes techniques spécialisés');
    }
  }
  
  // Score final et validation
  validation.score = Math.min(100, validation.score);
  validation.isValid = validation.isValid && validation.score >= 60;
  
  return validation;
}

/**
 * UTILITAIRES TECHNIQUES
 */

/**
 * Chunk array avec gestion intelligente
 */
function chunkArray(array, chunkSize, smartChunking = false) {
  if (!Array.isArray(array)) return [];
  if (array.length <= chunkSize) return [array];
  
  const chunks = [];
  
  if (smartChunking) {
    // Chunking intelligent : éviter de séparer éléments liés
    let currentChunk = [];
    
    for (let i = 0; i < array.length; i++) {
      currentChunk.push(array[i]);
      
      // Conditions de fin de chunk intelligente
      const isChunkFull = currentChunk.length >= chunkSize;
      const isLastElement = i === array.length - 1;
      const nextElementRelated = i < array.length - 1 && 
        array[i].tag && array[i + 1].tag && 
        array[i].tag.includes('FAQ') && array[i + 1].tag.includes('FAQ');
      
      if ((isChunkFull && !nextElementRelated) || isLastElement) {
        chunks.push([...currentChunk]);
        currentChunk = [];
      }
    }
    
    // Ajouter chunk restant si non vide
    if (currentChunk.length > 0) {
      if (chunks.length > 0 && chunks[chunks.length - 1].length + currentChunk.length <= chunkSize * 1.2) {
        // Merger avec dernier chunk si pas trop gros
        chunks[chunks.length - 1].push(...currentChunk);
      } else {
        chunks.push(currentChunk);
      }
    }
  } else {
    // Chunking standard
    for (let i = 0; i < array.length; i += chunkSize) {
      chunks.push(array.slice(i, i + chunkSize));
    }
  }
  
  return chunks;
}

/**
 * Sleep avec logging optionnel
 */
async function sleep(ms, logMessage = null) {
  if (logMessage) {
    logSh(`⏳ ${logMessage} (${ms}ms)`, 'DEBUG');
  }
  
  return new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * Mesurer performance d'opération
 */
function measurePerformance(operationName, startTime = Date.now()) {
  const endTime = Date.now();
  const duration = endTime - startTime;
  
  const performance = {
    operationName,
    startTime,
    endTime,
    duration,
    durationFormatted: formatDuration(duration)
  };
  
  return performance;
}

/**
 * Formater durée en format lisible
 */
function formatDuration(ms) {
  if (ms < 1000) return `${ms}ms`;
  if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
  return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
}

/**
 * GÉNÉRATION SIMPLE (REMPLACE CONTENTGENERATION.JS)
 */

/**
 * Génération simple Claude uniquement (compatible avec l'ancien système)
 */
async function generateSimple(hierarchy, csvData) {
  const { LLMManager } = require('../LLMManager');
  
  logSh(`🔥 Génération simple Claude uniquement`, 'INFO');
  
  if (!hierarchy || Object.keys(hierarchy).length === 0) {
    throw new Error('Hiérarchie vide ou invalide');
  }
  
  const result = {
    content: {},
    stats: {
      processed: 0,
      enhanced: 0,
      duration: 0,
      llmProvider: 'claude'
    }
  };
  
  const startTime = Date.now();
  
  try {
    // Générer chaque élément avec Claude
    for (const [tag, instruction] of Object.entries(hierarchy)) {
      try {
        logSh(`🎯 Génération: ${tag}`, 'DEBUG');
        
        const prompt = `Tu es un expert en rédaction SEO. Tu dois générer du contenu professionnel et naturel.

CONTEXTE:
- Mot-clé principal: ${csvData.mc0}
- Titre principal: ${csvData.t0}
- Personnalité: ${csvData.personality?.nom} (${csvData.personality?.style})

INSTRUCTION SPÉCIFIQUE:
${instruction}

CONSIGNES:
- Contenu naturel et engageant
- Intégration naturelle du mot-clé "${csvData.mc0}"
- Style ${csvData.personality?.style || 'professionnel'}
- Pas de formatage markdown
- Réponse directe sans préambule

RÉPONSE:`;

        const response = await LLMManager.callLLM('claude', prompt, {
          temperature: 0.9,
          maxTokens: 300,
          timeout: 30000
        });
        
        if (response && response.trim()) {
          result.content[tag] = cleanGeneratedContent(response.trim());
          result.stats.processed++;
          result.stats.enhanced++;
        } else {
          logSh(`⚠️ Réponse vide pour ${tag}`, 'WARNING');
          result.content[tag] = `Contenu ${tag} généré automatiquement`;
        }
        
      } catch (error) {
        logSh(`❌ Erreur génération ${tag}: ${error.message}`, 'ERROR');
        result.content[tag] = `Contenu ${tag} - Erreur de génération`;
      }
    }
    
    result.stats.duration = Date.now() - startTime;
    
    logSh(`✅ Génération simple terminée: ${result.stats.enhanced}/${result.stats.processed} éléments (${result.stats.duration}ms)`, 'INFO');
    
    return result;
    
  } catch (error) {
    result.stats.duration = Date.now() - startTime;
    logSh(`❌ Échec génération simple: ${error.message}`, 'ERROR');
    throw error;
  }
}

/**
 * STATISTIQUES ET RAPPORTS
 */

/**
 * Générer rapport amélioration
 */
function generateImprovementReport(originalContent, enhancedContent, layerType = 'general') {
  const report = {
    layerType,
    timestamp: new Date().toISOString(),
    summary: {
      elementsProcessed: 0,
      elementsImproved: 0,
      averageImprovement: 0,
      totalExecutionTime: 0
    },
    details: {
      byElement: [],
      qualityMetrics: {},
      recommendations: []
    }
  };
  
  // Analyser chaque élément
  Object.keys(originalContent).forEach(tag => {
    const original = originalContent[tag];
    const enhanced = enhancedContent[tag];
    
    if (original && enhanced) {
      report.summary.elementsProcessed++;
      
      const improvement = compareContentImprovement(original, enhanced, layerType);
      
      if (improvement.improvementRate > 0) {
        report.summary.elementsImproved++;
      }
      
      report.summary.averageImprovement += improvement.improvementRate;
      
      report.details.byElement.push({
        tag,
        improvementRate: improvement.improvementRate,
        lengthChange: improvement.details.lengthChange,
        contentPreserved: improvement.details.contentPreserved
      });
    }
  });
  
  // Calculer moyennes
  if (report.summary.elementsProcessed > 0) {
    report.summary.averageImprovement = report.summary.averageImprovement / report.summary.elementsProcessed;
  }
  
  // Métriques qualité globales
  const fullOriginal = Object.values(originalContent).join(' ');
  const fullEnhanced = Object.values(enhancedContent).join(' ');
  
  report.details.qualityMetrics = {
    technical: analyzeTechnicalQuality(fullEnhanced),
    transitions: analyzeTransitionFluidity(fullEnhanced), 
    style: analyzeStyleConsistency(fullEnhanced)
  };
  
  // Recommandations
  if (report.summary.averageImprovement < 10) {
    report.details.recommendations.push('Augmenter l\'intensité d\'amélioration');
  }
  
  if (report.details.byElement.some(e => !e.contentPreserved)) {
    report.details.recommendations.push('Améliorer préservation du contenu original');
  }
  
  return report;
}

module.exports = {
  // Analyseurs
  analyzeTechnicalQuality,
  analyzeTransitionFluidity,
  analyzeStyleConsistency,
  
  // Comparateurs
  compareContentImprovement,
  
  // Utilitaires contenu
  cleanGeneratedContent,
  validateSelectiveContent,
  
  // Utilitaires techniques
  chunkArray,
  sleep,
  measurePerformance,
  formatDuration,
  
  // Génération simple (remplace ContentGeneration.js)
  generateSimple,
  
  // Rapports
  generateImprovementReport
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/TechnicalLayer.js                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// TECHNICAL LAYER - COUCHE TECHNIQUE MODULAIRE
// Responsabilité: Amélioration technique modulaire réutilisable
// LLM: GPT-4o-mini (précision technique optimale)
// ========================================

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

/**
 * COUCHE TECHNIQUE MODULAIRE
 */
class TechnicalLayer {
  constructor() {
    this.name = 'TechnicalEnhancement';
    this.defaultLLM = 'openai';
    this.priority = 1; // Haute priorité - appliqué en premier généralement
  }

  /**
   * MAIN METHOD - Appliquer amélioration technique
   */
  async apply(content, config = {}) {
    return await tracer.run('TechnicalLayer.apply()', async () => {
      const {
        llmProvider = this.defaultLLM,
        intensity = 1.0,          // 0.0-2.0 intensité d'amélioration
        analysisMode = true,      // Analyser avant d'appliquer
        csvData = null,
        preserveStructure = true,
        targetTerms = null        // Termes techniques ciblés
      } = config;

      await tracer.annotate({
        technicalLayer: true,
        llmProvider,
        intensity,
        elementsCount: Object.keys(content).length,
        mc0: csvData?.mc0
      });

      const startTime = Date.now();
      logSh(`⚙️ TECHNICAL LAYER: Amélioration technique (${llmProvider})`, 'INFO');
      logSh(`   📊 ${Object.keys(content).length} éléments | Intensité: ${intensity}`, 'INFO');

      try {
        let enhancedContent = {};
        let elementsProcessed = 0;
        let elementsEnhanced = 0;

        if (analysisMode) {
          // 1. Analyser éléments nécessitant amélioration technique
          const analysis = await this.analyzeTechnicalNeeds(content, csvData, targetTerms);
          
          logSh(`   📋 Analyse: ${analysis.candidates.length}/${Object.keys(content).length} éléments candidats`, 'DEBUG');
          
          if (analysis.candidates.length === 0) {
            logSh(`✅ TECHNICAL LAYER: Aucune amélioration nécessaire`, 'INFO');
            return {
              content,
              stats: { 
                processed: Object.keys(content).length, 
                enhanced: 0, 
                analysisSkipped: true, 
                duration: Date.now() - startTime 
              }
            };
          }

          // 2. Améliorer les éléments sélectionnés
          const improvedResults = await this.enhanceTechnicalElements(
            analysis.candidates, 
            csvData, 
            { llmProvider, intensity, preserveStructure }
          );

          // 3. Merger avec contenu original
          enhancedContent = { ...content };
          Object.keys(improvedResults).forEach(tag => {
            if (improvedResults[tag] !== content[tag]) {
              enhancedContent[tag] = improvedResults[tag];
              elementsEnhanced++;
            }
          });
          
          elementsProcessed = analysis.candidates.length;

        } else {
          // Mode direct : améliorer tous les éléments
          enhancedContent = await this.enhanceAllElementsDirect(
            content, 
            csvData, 
            { llmProvider, intensity, preserveStructure }
          );
          
          elementsProcessed = Object.keys(content).length;
          elementsEnhanced = this.countDifferences(content, enhancedContent);
        }

        const duration = Date.now() - startTime;
        const stats = {
          processed: elementsProcessed,
          enhanced: elementsEnhanced,
          total: Object.keys(content).length,
          enhancementRate: (elementsEnhanced / Math.max(elementsProcessed, 1)) * 100,
          duration,
          llmProvider,
          intensity
        };

        logSh(`✅ TECHNICAL LAYER TERMINÉE: ${elementsEnhanced}/${elementsProcessed} améliorés (${duration}ms)`, 'INFO');

        await tracer.event('Technical layer appliquée', stats);

        return { content: enhancedContent, stats };

      } catch (error) {
        const duration = Date.now() - startTime;
        logSh(`❌ TECHNICAL LAYER ÉCHOUÉE après ${duration}ms: ${error.message}`, 'ERROR');
        throw error;
      }
    }, { content: Object.keys(content), config });
  }

  /**
   * ANALYSER BESOINS TECHNIQUES
   */
  async analyzeTechnicalNeeds(content, csvData, targetTerms = null) {
    logSh(`🔍 Analyse besoins techniques`, 'DEBUG');
    
    const analysis = {
      candidates: [],
      technicalTermsFound: [],
      missingTerms: [],
      globalScore: 0
    };

    // Définir termes techniques selon contexte
    const contextualTerms = this.getContextualTechnicalTerms(csvData?.mc0, targetTerms);
    
    // Analyser chaque élément
    Object.entries(content).forEach(([tag, text]) => {
      const elementAnalysis = this.analyzeTechnicalElement(text, contextualTerms, csvData);
      
      if (elementAnalysis.needsImprovement) {
        analysis.candidates.push({
          tag,
          content: text,
          technicalTerms: elementAnalysis.foundTerms,
          missingTerms: elementAnalysis.missingTerms,
          score: elementAnalysis.score,
          improvements: elementAnalysis.improvements
        });
        
        analysis.globalScore += elementAnalysis.score;
      }
      
      analysis.technicalTermsFound.push(...elementAnalysis.foundTerms);
    });

    analysis.globalScore = analysis.globalScore / Math.max(Object.keys(content).length, 1);
    analysis.technicalTermsFound = [...new Set(analysis.technicalTermsFound)];
    
    logSh(`   📊 Score global technique: ${analysis.globalScore.toFixed(2)}`, 'DEBUG');
    
    return analysis;
  }

  /**
   * AMÉLIORER ÉLÉMENTS TECHNIQUES SÉLECTIONNÉS
   */
  async enhanceTechnicalElements(candidates, csvData, config) {
    logSh(`🛠️ Amélioration ${candidates.length} éléments techniques`, 'DEBUG');
    logSh(`🔍 Candidates reçus: ${JSON.stringify(candidates.map(c => c.tag))}`, 'DEBUG');
    
    const results = {};
    const chunks = chunkArray(candidates, 4); // Chunks de 4 pour GPT-4
    
    for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
      const chunk = chunks[chunkIndex];
      
      try {
        logSh(`   📦 Chunk technique ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG');
        
        const enhancementPrompt = this.createTechnicalEnhancementPrompt(chunk, csvData, config);
        
        const response = await callLLM(config.llmProvider, enhancementPrompt, {
          temperature: 0.4, // Précision technique
          maxTokens: 3000
        }, csvData?.personality);
        
        const chunkResults = this.parseTechnicalResponse(response, chunk);
        Object.assign(results, chunkResults);
        
        logSh(`   ✅ Chunk technique ${chunkIndex + 1}: ${Object.keys(chunkResults).length} améliorés`, 'DEBUG');
        
        // Délai entre chunks
        if (chunkIndex < chunks.length - 1) {
          await sleep(1500);
        }
        
      } catch (error) {
        logSh(`   ❌ Chunk technique ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR');
        
        // Fallback: conserver contenu original
        chunk.forEach(element => {
          results[element.tag] = element.content;
        });
      }
    }
    
    return results;
  }

  /**
   * AMÉLIORER TOUS ÉLÉMENTS MODE DIRECT
   */
  async enhanceAllElementsDirect(content, csvData, config) {
    const allElements = Object.entries(content).map(([tag, text]) => ({
      tag,
      content: text,
      technicalTerms: [],
      improvements: ['amélioration_générale_technique'],
      missingTerms: []  // Ajout de la propriété manquante
    }));
    
    return await this.enhanceTechnicalElements(allElements, csvData, config);
  }

  // ============= HELPER METHODS =============

  /**
   * Analyser élément technique individuel
   */
  analyzeTechnicalElement(text, contextualTerms, csvData) {
    let score = 0;
    const foundTerms = [];
    const missingTerms = [];
    const improvements = [];
    
    // 1. Détecter termes techniques présents
    contextualTerms.forEach(term => {
      if (text.toLowerCase().includes(term.toLowerCase())) {
        foundTerms.push(term);
      } else if (text.length > 100) { // Seulement pour textes longs
        missingTerms.push(term);
      }
    });
    
    // 2. Évaluer manque de précision technique
    if (foundTerms.length === 0 && text.length > 80) {
      score += 0.4;
      improvements.push('ajout_termes_techniques');
    }
    
    // 3. Détecter vocabulaire trop générique
    const genericWords = ['produit', 'solution', 'service', 'offre', 'article'];
    const genericCount = genericWords.filter(word => 
      text.toLowerCase().includes(word)
    ).length;
    
    if (genericCount > 1) {
      score += 0.3;
      improvements.push('spécialisation_vocabulaire');
    }
    
    // 4. Manque de données techniques (dimensions, etc.)
    if (text.length > 50 && !(/\d+\s*(mm|cm|m|%|°|kg|g)/.test(text))) {
      score += 0.2;
      improvements.push('ajout_données_techniques');
    }
    
    // 5. Contexte métier spécifique
    if (csvData?.mc0 && !text.toLowerCase().includes(csvData.mc0.toLowerCase().split(' ')[0])) {
      score += 0.1;
      improvements.push('intégration_contexte_métier');
    }
    
    return {
      needsImprovement: score > 0.3,
      score,
      foundTerms,
      missingTerms: missingTerms.slice(0, 3), // Limiter à 3 termes manquants
      improvements
    };
  }

  /**
   * Obtenir termes techniques contextuels
   */
  getContextualTechnicalTerms(mc0, targetTerms) {
    // Termes de base signalétique
    const baseTerms = [
      'dibond', 'aluminium', 'PMMA', 'acrylique', 'plexiglas',
      'impression', 'gravure', 'découpe', 'fraisage', 'perçage',
      'adhésif', 'fixation', 'visserie', 'support'
    ];
    
    // Termes spécifiques selon contexte
    const contextualTerms = [];
    
    if (mc0) {
      const mc0Lower = mc0.toLowerCase();
      
      if (mc0Lower.includes('plaque')) {
        contextualTerms.push('épaisseur 3mm', 'format standard', 'finition brossée', 'anodisation');
      }
      
      if (mc0Lower.includes('signalétique')) {
        contextualTerms.push('norme ISO', 'pictogramme', 'contraste visuel', 'lisibilité');
      }
      
      if (mc0Lower.includes('personnalisée')) {
        contextualTerms.push('découpe forme', 'impression numérique', 'quadrichromie', 'pantone');
      }
    }
    
    // Ajouter termes ciblés si fournis
    if (targetTerms && Array.isArray(targetTerms)) {
      contextualTerms.push(...targetTerms);
    }
    
    return [...baseTerms, ...contextualTerms];
  }

  /**
   * Créer prompt amélioration technique
   */
  createTechnicalEnhancementPrompt(chunk, csvData, config) {
    const personality = csvData?.personality;
    
    let prompt = `MISSION: Améliore UNIQUEMENT la précision technique de ces contenus.

CONTEXTE: ${csvData?.mc0 || 'Signalétique personnalisée'} - Secteur: impression/signalétique
${personality ? `PERSONNALITÉ: ${personality.nom} (${personality.style})` : ''}
INTENSITÉ: ${config.intensity} (0.5=léger, 1.0=standard, 1.5=intensif)

ÉLÉMENTS À AMÉLIORER TECHNIQUEMENT:

${chunk.map((item, i) => `[${i + 1}] TAG: ${item.tag}
CONTENU: "${item.content}"
AMÉLIORATIONS: ${item.improvements.join(', ')}
${item.missingTerms.length > 0 ? `TERMES À INTÉGRER: ${item.missingTerms.join(', ')}` : ''}`).join('\n\n')}

CONSIGNES TECHNIQUES:
- GARDE exactement le même message et ton${personality ? ` ${personality.style}` : ''}
- AJOUTE précision technique naturelle et vocabulaire spécialisé
- INTÈGRE termes métier : matériaux, procédés, normes, dimensions
- REMPLACE vocabulaire générique par termes techniques appropriés
- ÉVITE jargon incompréhensible, reste accessible
- PRESERVE longueur approximative (±15%)

VOCABULAIRE TECHNIQUE RECOMMANDÉ:
- Matériaux: dibond, aluminium anodisé, PMMA coulé, PVC expansé
- Procédés: impression UV, gravure laser, découpe numérique, fraisage CNC  
- Finitions: brossé, poli, texturé, laqué
- Fixations: perçage, adhésif double face, vis inox, plots de fixation

FORMAT RÉPONSE:
[1] Contenu avec amélioration technique précise
[2] Contenu avec amélioration technique précise
etc...

IMPORTANT: Réponse DIRECTE par les contenus améliorés, pas d'explication.`;

    return prompt;
  }

  /**
   * Parser réponse technique
   */
  parseTechnicalResponse(response, chunk) {
    const results = {};
    const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
    let match;
    let index = 0;
    
    while ((match = regex.exec(response)) && index < chunk.length) {
      let technicalContent = match[2].trim();
      const element = chunk[index];
      
      // Nettoyer contenu technique
      technicalContent = this.cleanTechnicalContent(technicalContent);
      
      if (technicalContent && technicalContent.length > 10) {
        results[element.tag] = technicalContent;
        logSh(`✅ Amélioré technique [${element.tag}]: "${technicalContent.substring(0, 60)}..."`, 'DEBUG');
      } else {
        results[element.tag] = element.content; // Fallback
        logSh(`⚠️ Fallback technique [${element.tag}]: amélioration invalide`, 'WARNING');
      }
      
      index++;
    }
    
    // Compléter les manquants
    while (index < chunk.length) {
      const element = chunk[index];
      results[element.tag] = element.content;
      index++;
    }
    
    return results;
  }

  /**
   * Nettoyer contenu technique généré
   */
  cleanTechnicalContent(content) {
    if (!content) return content;
    
    // Supprimer préfixes indésirables
    content = content.replace(/^(voici\s+)?le\s+contenu\s+amélioré\s*[:.]?\s*/gi, '');
    content = content.replace(/^(avec\s+)?amélioration\s+technique\s*[:.]?\s*/gi, '');
    content = content.replace(/^(bon,?\s*)?(alors,?\s*)?pour\s+/gi, '');
    
    // Nettoyer formatage
    content = content.replace(/\*\*[^*]+\*\*/g, ''); // Gras markdown
    content = content.replace(/\s{2,}/g, ' '); // Espaces multiples
    content = content.trim();
    
    return content;
  }

  /**
   * Compter différences entre contenus
   */
  countDifferences(original, enhanced) {
    let count = 0;
    
    Object.keys(original).forEach(tag => {
      if (enhanced[tag] && enhanced[tag] !== original[tag]) {
        count++;
      }
    });
    
    return count;
  }
}

module.exports = { TechnicalLayer };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/TransitionLayer.js                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// TRANSITION LAYER - COUCHE TRANSITIONS MODULAIRE - DISABLED
// Responsabilité: Amélioration fluidité modulaire réutilisable
// LLM: Gemini (DISABLED - remplacé par style)
// ========================================

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

/**
 * COUCHE TRANSITIONS MODULAIRE
 */
class TransitionLayer {
  constructor() {
    this.name = 'TransitionEnhancement';
    this.defaultLLM = 'mistral'; // Changed from gemini to mistral
    this.priority = 2; // Priorité moyenne - appliqué après technique
  }

  /**
   * MAIN METHOD - Appliquer amélioration transitions
   */
  async apply(content, config = {}) {
    return await tracer.run('TransitionLayer.apply()', async () => {
      const {
        llmProvider = this.defaultLLM,
        intensity = 1.0,          // 0.0-2.0 intensité d'amélioration
        analysisMode = true,      // Analyser avant d'appliquer
        csvData = null,
        preserveStructure = true,
        targetIssues = null       // Issues spécifiques à corriger
      } = config;

      await tracer.annotate({
        transitionLayer: true,
        llmProvider,
        intensity,
        elementsCount: Object.keys(content).length,
        mc0: csvData?.mc0
      });

      const startTime = Date.now();
      logSh(`🔗 TRANSITION LAYER: Amélioration fluidité (${llmProvider})`, 'INFO');
      logSh(`   📊 ${Object.keys(content).length} éléments | Intensité: ${intensity}`, 'INFO');

      try {
        let enhancedContent = {};
        let elementsProcessed = 0;
        let elementsEnhanced = 0;

        if (analysisMode) {
          // 1. Analyser éléments nécessitant amélioration transitions
          const analysis = await this.analyzeTransitionNeeds(content, csvData, targetIssues);
          
          logSh(`   📋 Analyse: ${analysis.candidates.length}/${Object.keys(content).length} éléments candidats`, 'DEBUG');
          
          if (analysis.candidates.length === 0) {
            logSh(`✅ TRANSITION LAYER: Fluidité déjà optimale`, 'INFO');
            return {
              content,
              stats: { 
                processed: Object.keys(content).length, 
                enhanced: 0, 
                analysisSkipped: true, 
                duration: Date.now() - startTime 
              }
            };
          }

          // 2. Améliorer les éléments sélectionnés
          const improvedResults = await this.enhanceTransitionElements(
            analysis.candidates, 
            csvData, 
            { llmProvider, intensity, preserveStructure }
          );

          // 3. Merger avec contenu original
          enhancedContent = { ...content };
          Object.keys(improvedResults).forEach(tag => {
            if (improvedResults[tag] !== content[tag]) {
              enhancedContent[tag] = improvedResults[tag];
              elementsEnhanced++;
            }
          });
          
          elementsProcessed = analysis.candidates.length;

        } else {
          // Mode direct : améliorer tous les éléments longs
          const longElements = Object.entries(content)
            .filter(([tag, text]) => text.length > 150)
            .map(([tag, text]) => ({ tag, content: text, issues: ['amélioration_générale'] }));
          
          if (longElements.length === 0) {
            return { content, stats: { processed: 0, enhanced: 0, duration: Date.now() - startTime } };
          }
          
          const improvedResults = await this.enhanceTransitionElements(
            longElements, 
            csvData, 
            { llmProvider, intensity, preserveStructure }
          );
          
          enhancedContent = { ...content };
          Object.keys(improvedResults).forEach(tag => {
            if (improvedResults[tag] !== content[tag]) {
              enhancedContent[tag] = improvedResults[tag];
              elementsEnhanced++;
            }
          });
          
          elementsProcessed = longElements.length;
        }

        const duration = Date.now() - startTime;
        const stats = {
          processed: elementsProcessed,
          enhanced: elementsEnhanced,
          total: Object.keys(content).length,
          enhancementRate: (elementsEnhanced / Math.max(elementsProcessed, 1)) * 100,
          duration,
          llmProvider,
          intensity
        };

        logSh(`✅ TRANSITION LAYER TERMINÉE: ${elementsEnhanced}/${elementsProcessed} fluidifiés (${duration}ms)`, 'INFO');

        await tracer.event('Transition layer appliquée', stats);

        return { content: enhancedContent, stats };

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

  /**
   * ANALYSER BESOINS TRANSITIONS
   */
  async analyzeTransitionNeeds(content, csvData, targetIssues = null) {
    logSh(`🔍 Analyse besoins transitions`, 'DEBUG');
    
    const analysis = {
      candidates: [],
      globalScore: 0,
      issuesFound: {
        repetitiveConnectors: 0,
        abruptTransitions: 0,
        uniformSentences: 0,
        formalityImbalance: 0
      }
    };

    // Analyser chaque élément
    Object.entries(content).forEach(([tag, text]) => {
      const elementAnalysis = this.analyzeTransitionElement(text, csvData);
      
      if (elementAnalysis.needsImprovement) {
        analysis.candidates.push({
          tag,
          content: text,
          issues: elementAnalysis.issues,
          score: elementAnalysis.score,
          improvements: elementAnalysis.improvements
        });
        
        analysis.globalScore += elementAnalysis.score;
        
        // Compter types d'issues
        elementAnalysis.issues.forEach(issue => {
          if (analysis.issuesFound.hasOwnProperty(issue)) {
            analysis.issuesFound[issue]++;
          }
        });
      }
    });

    analysis.globalScore = analysis.globalScore / Math.max(Object.keys(content).length, 1);
    
    logSh(`   📊 Score global transitions: ${analysis.globalScore.toFixed(2)}`, 'DEBUG');
    logSh(`   🔍 Issues trouvées: ${JSON.stringify(analysis.issuesFound)}`, 'DEBUG');
    
    return analysis;
  }

  /**
   * AMÉLIORER ÉLÉMENTS TRANSITIONS SÉLECTIONNÉS
   */
  async enhanceTransitionElements(candidates, csvData, config) {
    logSh(`🔄 Amélioration ${candidates.length} éléments transitions`, 'DEBUG');
    
    const results = {};
    const chunks = chunkArray(candidates, 6); // Chunks plus petits pour Gemini
    
    for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
      const chunk = chunks[chunkIndex];
      
      try {
        logSh(`   📦 Chunk transitions ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG');
        
        const enhancementPrompt = this.createTransitionEnhancementPrompt(chunk, csvData, config);
        
        const response = await callLLM(config.llmProvider, enhancementPrompt, {
          temperature: 0.6, // Créativité modérée pour fluidité
          maxTokens: 2500
        }, csvData?.personality);
        
        const chunkResults = this.parseTransitionResponse(response, chunk);
        Object.assign(results, chunkResults);
        
        logSh(`   ✅ Chunk transitions ${chunkIndex + 1}: ${Object.keys(chunkResults).length} fluidifiés`, 'DEBUG');
        
        // Délai entre chunks
        if (chunkIndex < chunks.length - 1) {
          await sleep(1500);
        }
        
      } catch (error) {
        logSh(`   ❌ Chunk transitions ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR');
        
        // Fallback: conserver contenu original
        chunk.forEach(element => {
          results[element.tag] = element.content;
        });
      }
    }
    
    return results;
  }

  // ============= HELPER METHODS =============

  /**
   * Analyser élément transition individuel
   */
  analyzeTransitionElement(text, csvData) {
    const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 10);
    
    if (sentences.length < 2) {
      return { needsImprovement: false, score: 0, issues: [], improvements: [] };
    }
    
    let score = 0;
    const issues = [];
    const improvements = [];
    
    // 1. Analyser connecteurs répétitifs
    const repetitiveScore = this.analyzeRepetitiveConnectors(text);
    if (repetitiveScore > 0.3) {
      score += 0.3;
      issues.push('repetitiveConnectors');
      improvements.push('varier_connecteurs');
    }
    
    // 2. Analyser transitions abruptes
    const abruptScore = this.analyzeAbruptTransitions(sentences);
    if (abruptScore > 0.4) {
      score += 0.4;
      issues.push('abruptTransitions');
      improvements.push('ajouter_transitions_fluides');
    }
    
    // 3. Analyser uniformité des phrases
    const uniformityScore = this.analyzeSentenceUniformity(sentences);
    if (uniformityScore < 0.3) {
      score += 0.2;
      issues.push('uniformSentences');
      improvements.push('varier_longueurs_phrases');
    }
    
    // 4. Analyser équilibre formalité
    const formalityScore = this.analyzeFormalityBalance(text);
    if (formalityScore > 0.5) {
      score += 0.1;
      issues.push('formalityImbalance');
      improvements.push('équilibrer_registre_langue');
    }
    
    return {
      needsImprovement: score > 0.3,
      score,
      issues,
      improvements
    };
  }

  /**
   * Analyser connecteurs répétitifs
   */
  analyzeRepetitiveConnectors(text) {
    const commonConnectors = ['par ailleurs', 'en effet', 'de plus', 'cependant', 'ainsi', 'donc'];
    let totalConnectors = 0;
    let repetitions = 0;
    
    commonConnectors.forEach(connector => {
      const matches = (text.match(new RegExp(`\\b${connector}\\b`, 'gi')) || []);
      totalConnectors += matches.length;
      if (matches.length > 1) repetitions += matches.length - 1;
    });
    
    return totalConnectors > 0 ? repetitions / totalConnectors : 0;
  }

  /**
   * Analyser transitions abruptes
   */
  analyzeAbruptTransitions(sentences) {
    if (sentences.length < 2) return 0;
    
    let abruptCount = 0;
    
    for (let i = 1; i < sentences.length; i++) {
      const current = sentences[i].trim().toLowerCase();
      const hasConnector = this.hasTransitionWord(current);
      
      if (!hasConnector && current.length > 30) {
        abruptCount++;
      }
    }
    
    return abruptCount / (sentences.length - 1);
  }

  /**
   * Analyser uniformité des phrases
   */
  analyzeSentenceUniformity(sentences) {
    if (sentences.length < 2) return 1;
    
    const lengths = sentences.map(s => s.trim().length);
    const avgLength = lengths.reduce((a, b) => a + b, 0) / lengths.length;
    const variance = lengths.reduce((acc, len) => acc + Math.pow(len - avgLength, 2), 0) / lengths.length;
    const stdDev = Math.sqrt(variance);
    
    return Math.min(1, stdDev / avgLength);
  }

  /**
   * Analyser équilibre formalité
   */
  analyzeFormalityBalance(text) {
    const formalIndicators = ['il convient de', 'par conséquent', 'néanmoins', 'toutefois', 'cependant'];
    const casualIndicators = ['du coup', 'bon', 'franchement', 'nickel', 'sympa'];
    
    let formalCount = 0;
    let casualCount = 0;
    
    formalIndicators.forEach(indicator => {
      if (text.toLowerCase().includes(indicator)) formalCount++;
    });
    
    casualIndicators.forEach(indicator => {
      if (text.toLowerCase().includes(indicator)) casualCount++;
    });
    
    const total = formalCount + casualCount;
    if (total === 0) return 0;
    
    // Déséquilibre si trop d'un côté
    return Math.abs(formalCount - casualCount) / total;
  }

  /**
   * Vérifier présence mots de transition
   */
  hasTransitionWord(sentence) {
    const transitionWords = [
      'par ailleurs', 'en effet', 'de plus', 'cependant', 'ainsi', 'donc', 
      'ensuite', 'puis', 'également', 'aussi', 'néanmoins', 'toutefois',
      'd\'ailleurs', 'en outre', 'par contre', 'en revanche'
    ];
    
    return transitionWords.some(word => sentence.includes(word));
  }

  /**
   * Créer prompt amélioration transitions
   */
  createTransitionEnhancementPrompt(chunk, csvData, config) {
    const personality = csvData?.personality;
    
    let prompt = `MISSION: Améliore UNIQUEMENT les transitions et fluidité de ces contenus.

CONTEXTE: Article SEO ${csvData?.mc0 || 'signalétique personnalisée'}
${personality ? `PERSONNALITÉ: ${personality.nom} (${personality.style} web professionnel)` : ''}
${personality?.connecteursPref ? `CONNECTEURS PRÉFÉRÉS: ${personality.connecteursPref}` : ''}
INTENSITÉ: ${config.intensity} (0.5=léger, 1.0=standard, 1.5=intensif)

CONTENUS À FLUIDIFIER:

${chunk.map((item, i) => `[${i + 1}] TAG: ${item.tag}
PROBLÈMES: ${item.issues.join(', ')}
CONTENU: "${item.content}"`).join('\n\n')}

OBJECTIFS FLUIDITÉ:
- Connecteurs plus naturels et variés${personality?.connecteursPref ? `: ${personality.connecteursPref}` : ''}
- Transitions fluides entre idées et paragraphes
- Variation naturelle longueurs phrases
- ÉVITE répétitions excessives ("du coup", "par ailleurs", "en effet")
- Style ${personality?.style || 'professionnel'} mais naturel web

CONSIGNES STRICTES:
- NE CHANGE PAS le fond du message ni les informations
- GARDE même structure générale et longueur approximative (±20%)
- Améliore SEULEMENT la fluidité et les enchaînements
- RESPECTE le style ${personality?.nom || 'professionnel'}${personality?.style ? ` (${personality.style})` : ''}
- ÉVITE sur-correction qui rendrait artificiel

TECHNIQUES FLUIDITÉ:
- Varier connecteurs logiques sans répétition
- Alterner phrases courtes (8-12 mots) et moyennes (15-20 mots)  
- Utiliser pronoms et reprises pour cohésion
- Ajouter transitions implicites par reformulation
- Équilibrer registre soutenu/accessible

FORMAT RÉPONSE:
[1] Contenu avec transitions améliorées
[2] Contenu avec transitions améliorées
etc...

IMPORTANT: Réponse DIRECTE par les contenus fluidifiés, pas d'explication.`;

    return prompt;
  }

  /**
   * Parser réponse transitions
   */
  parseTransitionResponse(response, chunk) {
    const results = {};
    const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
    let match;
    let index = 0;
    
    while ((match = regex.exec(response)) && index < chunk.length) {
      let fluidContent = match[2].trim();
      const element = chunk[index];
      
      // Nettoyer contenu fluidifié
      fluidContent = this.cleanTransitionContent(fluidContent);
      
      if (fluidContent && fluidContent.length > 10) {
        results[element.tag] = fluidContent;
        logSh(`✅ Fluidifié [${element.tag}]: "${fluidContent.substring(0, 60)}..."`, 'DEBUG');
      } else {
        results[element.tag] = element.content; // Fallback
        logSh(`⚠️ Fallback transitions [${element.tag}]: amélioration invalide`, 'WARNING');
      }
      
      index++;
    }
    
    // Compléter les manquants
    while (index < chunk.length) {
      const element = chunk[index];
      results[element.tag] = element.content;
      index++;
    }
    
    return results;
  }

  /**
   * Nettoyer contenu transitions généré
   */
  cleanTransitionContent(content) {
    if (!content) return content;
    
    // Supprimer préfixes indésirables
    content = content.replace(/^(voici\s+)?le\s+contenu\s+(fluidifié|amélioré)\s*[:.]?\s*/gi, '');
    content = content.replace(/^(avec\s+)?transitions\s+améliorées\s*[:.]?\s*/gi, '');
    content = content.replace(/^(bon,?\s*)?(alors,?\s*)?/, '');
    
    // Nettoyer formatage
    content = content.replace(/\*\*[^*]+\*\*/g, ''); // Gras markdown
    content = content.replace(/\s{2,}/g, ' '); // Espaces multiples
    content = content.trim();
    
    return content;
  }
}

module.exports = { TransitionLayer };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/StyleLayer.js                     │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// STYLE LAYER - COUCHE STYLE MODULAIRE
// Responsabilité: Adaptation personnalité modulaire réutilisable
// LLM: Mistral (excellence style et personnalité)
// ========================================

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

/**
 * COUCHE STYLE MODULAIRE
 */
class StyleLayer {
  constructor() {
    this.name = 'StyleEnhancement';
    this.defaultLLM = 'mistral';
    this.priority = 3; // Priorité basse - appliqué en dernier
  }

  /**
   * MAIN METHOD - Appliquer amélioration style
   */
  async apply(content, config = {}) {
    return await tracer.run('StyleLayer.apply()', async () => {
      const {
        llmProvider = this.defaultLLM,
        intensity = 1.0,          // 0.0-2.0 intensité d'amélioration
        analysisMode = true,      // Analyser avant d'appliquer
        csvData = null,
        preserveStructure = true,
        targetStyle = null        // Style spécifique à appliquer
      } = config;

      await tracer.annotate({
        styleLayer: true,
        llmProvider,
        intensity,
        elementsCount: Object.keys(content).length,
        personality: csvData?.personality?.nom
      });

      const startTime = Date.now();
      logSh(`🎨 STYLE LAYER: Amélioration personnalité (${llmProvider})`, 'INFO');
      logSh(`   📊 ${Object.keys(content).length} éléments | Style: ${csvData?.personality?.nom || 'standard'}`, 'INFO');

      try {
        let enhancedContent = {};
        let elementsProcessed = 0;
        let elementsEnhanced = 0;

        // Vérifier présence personnalité
        if (!csvData?.personality && !targetStyle) {
          logSh(`⚠️ STYLE LAYER: Pas de personnalité définie, style générique appliqué`, 'WARNING');
        }

        if (analysisMode) {
          // 1. Analyser éléments nécessitant amélioration style
          const analysis = await this.analyzeStyleNeeds(content, csvData, targetStyle);
          
          logSh(`   📋 Analyse: ${analysis.candidates.length}/${Object.keys(content).length} éléments candidats`, 'DEBUG');
          
          if (analysis.candidates.length === 0) {
            logSh(`✅ STYLE LAYER: Style déjà cohérent`, 'INFO');
            return {
              content,
              stats: { 
                processed: Object.keys(content).length, 
                enhanced: 0, 
                analysisSkipped: true, 
                duration: Date.now() - startTime 
              }
            };
          }

          // 2. Améliorer les éléments sélectionnés
          const improvedResults = await this.enhanceStyleElements(
            analysis.candidates, 
            csvData, 
            { llmProvider, intensity, preserveStructure, targetStyle }
          );

          // 3. Merger avec contenu original
          enhancedContent = { ...content };
          Object.keys(improvedResults).forEach(tag => {
            if (improvedResults[tag] !== content[tag]) {
              enhancedContent[tag] = improvedResults[tag];
              elementsEnhanced++;
            }
          });
          
          elementsProcessed = analysis.candidates.length;

        } else {
          // Mode direct : améliorer tous les éléments textuels
          const textualElements = Object.entries(content)
            .filter(([tag, text]) => text.length > 50 && !tag.includes('FAQ_Question'))
            .map(([tag, text]) => ({ tag, content: text, styleIssues: ['adaptation_générale'] }));
          
          if (textualElements.length === 0) {
            return { content, stats: { processed: 0, enhanced: 0, duration: Date.now() - startTime } };
          }
          
          const improvedResults = await this.enhanceStyleElements(
            textualElements, 
            csvData, 
            { llmProvider, intensity, preserveStructure, targetStyle }
          );
          
          enhancedContent = { ...content };
          Object.keys(improvedResults).forEach(tag => {
            if (improvedResults[tag] !== content[tag]) {
              enhancedContent[tag] = improvedResults[tag];
              elementsEnhanced++;
            }
          });
          
          elementsProcessed = textualElements.length;
        }

        const duration = Date.now() - startTime;
        const stats = {
          processed: elementsProcessed,
          enhanced: elementsEnhanced,
          total: Object.keys(content).length,
          enhancementRate: (elementsEnhanced / Math.max(elementsProcessed, 1)) * 100,
          duration,
          llmProvider,
          intensity,
          personalityApplied: csvData?.personality?.nom || targetStyle || 'générique'
        };

        logSh(`✅ STYLE LAYER TERMINÉE: ${elementsEnhanced}/${elementsProcessed} stylisés (${duration}ms)`, 'INFO');

        await tracer.event('Style layer appliquée', stats);

        return { content: enhancedContent, stats };

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

  /**
   * ANALYSER BESOINS STYLE
   */
  async analyzeStyleNeeds(content, csvData, targetStyle = null) {
    logSh(`🎨 Analyse besoins style`, 'DEBUG');
    
    const analysis = {
      candidates: [],
      globalScore: 0,
      styleIssues: {
        genericLanguage: 0,
        personalityMismatch: 0,
        inconsistentTone: 0,
        missingVocabulary: 0
      }
    };

    const personality = csvData?.personality;
    const expectedStyle = targetStyle || personality;

    // Analyser chaque élément
    Object.entries(content).forEach(([tag, text]) => {
      const elementAnalysis = this.analyzeStyleElement(text, expectedStyle, csvData);
      
      if (elementAnalysis.needsImprovement) {
        analysis.candidates.push({
          tag,
          content: text,
          styleIssues: elementAnalysis.issues,
          score: elementAnalysis.score,
          improvements: elementAnalysis.improvements
        });
        
        analysis.globalScore += elementAnalysis.score;
        
        // Compter types d'issues
        elementAnalysis.issues.forEach(issue => {
          if (analysis.styleIssues.hasOwnProperty(issue)) {
            analysis.styleIssues[issue]++;
          }
        });
      }
    });

    analysis.globalScore = analysis.globalScore / Math.max(Object.keys(content).length, 1);
    
    logSh(`   📊 Score global style: ${analysis.globalScore.toFixed(2)}`, 'DEBUG');
    logSh(`   🎭 Issues style: ${JSON.stringify(analysis.styleIssues)}`, 'DEBUG');
    
    return analysis;
  }

  /**
   * AMÉLIORER ÉLÉMENTS STYLE SÉLECTIONNÉS
   */
  async enhanceStyleElements(candidates, csvData, config) {
    logSh(`🎨 Amélioration ${candidates.length} éléments style`, 'DEBUG');
    
    const results = {};
    const chunks = chunkArray(candidates, 5); // Chunks optimisés pour Mistral
    
    for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
      const chunk = chunks[chunkIndex];
      
      try {
        logSh(`   📦 Chunk style ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG');
        
        const enhancementPrompt = this.createStyleEnhancementPrompt(chunk, csvData, config);
        
        const response = await callLLM(config.llmProvider, enhancementPrompt, {
          temperature: 0.8, // Créativité élevée pour style
          maxTokens: 3000
        }, csvData?.personality);
        
        const chunkResults = this.parseStyleResponse(response, chunk);
        Object.assign(results, chunkResults);
        
        logSh(`   ✅ Chunk style ${chunkIndex + 1}: ${Object.keys(chunkResults).length} stylisés`, 'DEBUG');
        
        // Délai entre chunks
        if (chunkIndex < chunks.length - 1) {
          await sleep(1800);
        }
        
      } catch (error) {
        logSh(`   ❌ Chunk style ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR');
        
        // Fallback: conserver contenu original
        chunk.forEach(element => {
          results[element.tag] = element.content;
        });
      }
    }
    
    return results;
  }

  // ============= HELPER METHODS =============

  /**
   * Analyser élément style individuel
   */
  analyzeStyleElement(text, expectedStyle, csvData) {
    let score = 0;
    const issues = [];
    const improvements = [];
    
    // Si pas de style attendu, score faible
    if (!expectedStyle) {
      return { needsImprovement: false, score: 0.1, issues: ['pas_style_défini'], improvements: [] };
    }
    
    // 1. Analyser langage générique
    const genericScore = this.analyzeGenericLanguage(text);
    if (genericScore > 0.4) {
      score += 0.3;
      issues.push('genericLanguage');
      improvements.push('personnaliser_vocabulaire');
    }
    
    // 2. Analyser adéquation personnalité
    if (expectedStyle.vocabulairePref) {
      const personalityScore = this.analyzePersonalityAlignment(text, expectedStyle);
      if (personalityScore < 0.3) {
        score += 0.4;
        issues.push('personalityMismatch');
        improvements.push('appliquer_style_personnalité');
      }
    }
    
    // 3. Analyser cohérence de ton
    const toneScore = this.analyzeToneConsistency(text, expectedStyle);
    if (toneScore > 0.5) {
      score += 0.2;
      issues.push('inconsistentTone');
      improvements.push('unifier_ton');
    }
    
    // 4. Analyser vocabulaire spécialisé
    if (expectedStyle.niveauTechnique) {
      const vocabScore = this.analyzeVocabularyLevel(text, expectedStyle);
      if (vocabScore > 0.4) {
        score += 0.1;
        issues.push('missingVocabulary');
        improvements.push('ajuster_niveau_vocabulaire');
      }
    }
    
    return {
      needsImprovement: score > 0.3,
      score,
      issues,
      improvements
    };
  }

  /**
   * Analyser langage générique
   */
  analyzeGenericLanguage(text) {
    const genericPhrases = [
      'nos solutions', 'notre expertise', 'notre savoir-faire', 
      'nous vous proposons', 'nous mettons à votre disposition',
      'qualité optimale', 'service de qualité', 'expertise reconnue'
    ];
    
    let genericCount = 0;
    genericPhrases.forEach(phrase => {
      if (text.toLowerCase().includes(phrase)) genericCount++;
    });
    
    const wordCount = text.split(/\s+/).length;
    return Math.min(1, (genericCount / Math.max(wordCount / 50, 1)));
  }

  /**
   * Analyser alignement personnalité
   */
  analyzePersonalityAlignment(text, personality) {
    if (!personality.vocabulairePref) return 1;
    
    const preferredWords = personality.vocabulairePref.toLowerCase().split(',');
    const contentLower = text.toLowerCase();
    
    let alignmentScore = 0;
    preferredWords.forEach(word => {
      if (word.trim() && contentLower.includes(word.trim())) {
        alignmentScore++;
      }
    });
    
    return Math.min(1, alignmentScore / Math.max(preferredWords.length, 1));
  }

  /**
   * Analyser cohérence de ton
   */
  analyzeToneConsistency(text, expectedStyle) {
    const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 10);
    if (sentences.length < 2) return 0;
    
    const tones = sentences.map(sentence => this.detectSentenceTone(sentence));
    const expectedTone = this.getExpectedTone(expectedStyle);
    
    let inconsistencies = 0;
    tones.forEach(tone => {
      if (tone !== expectedTone && tone !== 'neutral') {
        inconsistencies++;
      }
    });
    
    return inconsistencies / tones.length;
  }

  /**
   * Analyser niveau vocabulaire
   */
  analyzeVocabularyLevel(text, expectedStyle) {
    const technicalWords = text.match(/\b\w{8,}\b/g) || [];
    const expectedLevel = expectedStyle.niveauTechnique || 'standard';
    
    const techRatio = technicalWords.length / text.split(/\s+/).length;
    
    switch (expectedLevel) {
      case 'accessible':
        return techRatio > 0.1 ? techRatio : 0; // Trop technique
      case 'expert':
        return techRatio < 0.05 ? 1 - techRatio : 0; // Pas assez technique
      default:
        return techRatio > 0.15 || techRatio < 0.02 ? Math.abs(0.08 - techRatio) : 0;
    }
  }

  /**
   * Détecter ton de phrase
   */
  detectSentenceTone(sentence) {
    const lowerSentence = sentence.toLowerCase();
    
    if (/\b(excellent|remarquable|exceptionnel|parfait)\b/.test(lowerSentence)) return 'enthusiastic';
    if (/\b(il convient|nous recommandons|il est conseillé)\b/.test(lowerSentence)) return 'formal';
    if (/\b(sympa|cool|nickel|top)\b/.test(lowerSentence)) return 'casual';
    if (/\b(technique|précision|spécification)\b/.test(lowerSentence)) return 'technical';
    
    return 'neutral';
  }

  /**
   * Obtenir ton attendu selon personnalité
   */
  getExpectedTone(personality) {
    if (!personality || !personality.style) return 'neutral';
    
    const style = personality.style.toLowerCase();
    
    if (style.includes('technique') || style.includes('expert')) return 'technical';
    if (style.includes('commercial') || style.includes('vente')) return 'enthusiastic';
    if (style.includes('décontracté') || style.includes('moderne')) return 'casual';
    if (style.includes('professionnel') || style.includes('formel')) return 'formal';
    
    return 'neutral';
  }

  /**
   * Créer prompt amélioration style
   */
  createStyleEnhancementPrompt(chunk, csvData, config) {
    const personality = csvData?.personality || config.targetStyle;
    
    let prompt = `MISSION: Adapte UNIQUEMENT le style et la personnalité de ces contenus.

CONTEXTE: Article SEO ${csvData?.mc0 || 'signalétique personnalisée'}
${personality ? `PERSONNALITÉ CIBLE: ${personality.nom} (${personality.style})` : 'STYLE: Professionnel standard'}
${personality?.description ? `DESCRIPTION: ${personality.description}` : ''}
INTENSITÉ: ${config.intensity} (0.5=léger, 1.0=standard, 1.5=intensif)

CONTENUS À STYLISER:

${chunk.map((item, i) => `[${i + 1}] TAG: ${item.tag}
PROBLÈMES: ${item.styleIssues.join(', ')}
CONTENU: "${item.content}"`).join('\n\n')}

PROFIL PERSONNALITÉ ${personality?.nom || 'Standard'}:
${personality ? `- Style: ${personality.style}
- Niveau: ${personality.niveauTechnique || 'standard'}
- Vocabulaire préféré: ${personality.vocabulairePref || 'professionnel'}
- Connecteurs: ${personality.connecteursPref || 'variés'}
${personality.specificites ? `- Spécificités: ${personality.specificites}` : ''}` : '- Style professionnel web standard'}

OBJECTIFS STYLE:
- Appliquer personnalité ${personality?.nom || 'standard'} de façon naturelle
- Utiliser vocabulaire et expressions caractéristiques
- Maintenir cohérence de ton sur tout le contenu
- Adapter niveau technique selon profil (${personality?.niveauTechnique || 'standard'})
- Style web ${personality?.style || 'professionnel'} mais authentique

CONSIGNES STRICTES:
- NE CHANGE PAS le fond du message ni les informations factuelles
- GARDE même structure et longueur approximative (±15%)
- Applique SEULEMENT style et personnalité sur la forme
- RESPECTE impérativement le niveau ${personality?.niveauTechnique || 'standard'}
- ÉVITE exagération qui rendrait artificiel

TECHNIQUES STYLE:
${personality?.vocabulairePref ? `- Intégrer naturellement: ${personality.vocabulairePref}` : '- Vocabulaire professionnel équilibré'}
- Adapter registre de langue selon ${personality?.style || 'professionnel'}
- Expressions et tournures caractéristiques personnalité
- Ton cohérent: ${this.getExpectedTone(personality)} mais naturel
- Connecteurs préférés: ${personality?.connecteursPref || 'variés et naturels'}

FORMAT RÉPONSE:
[1] Contenu avec style personnalisé
[2] Contenu avec style personnalisé
etc...

IMPORTANT: Réponse DIRECTE par les contenus stylisés, pas d'explication.`;

    return prompt;
  }

  /**
   * Parser réponse style
   */
  parseStyleResponse(response, chunk) {
    const results = {};
    const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
    let match;
    let index = 0;
    
    while ((match = regex.exec(response)) && index < chunk.length) {
      let styledContent = match[2].trim();
      const element = chunk[index];
      
      // Nettoyer contenu stylisé
      styledContent = this.cleanStyleContent(styledContent);
      
      if (styledContent && styledContent.length > 10) {
        results[element.tag] = styledContent;
        logSh(`✅ Stylisé [${element.tag}]: "${styledContent.substring(0, 60)}..."`, 'DEBUG');
      } else {
        results[element.tag] = element.content; // Fallback
        logSh(`⚠️ Fallback style [${element.tag}]: amélioration invalide`, 'WARNING');
      }
      
      index++;
    }
    
    // Compléter les manquants
    while (index < chunk.length) {
      const element = chunk[index];
      results[element.tag] = element.content;
      index++;
    }
    
    return results;
  }

  /**
   * Nettoyer contenu style généré
   */
  cleanStyleContent(content) {
    if (!content) return content;
    
    // Supprimer préfixes indésirables
    content = content.replace(/^(voici\s+)?le\s+contenu\s+(stylisé|adapté|personnalisé)\s*[:.]?\s*/gi, '');
    content = content.replace(/^(avec\s+)?style\s+[^:]*\s*[:.]?\s*/gi, '');
    content = content.replace(/^(dans\s+le\s+style\s+de\s+)[^:]*[:.]?\s*/gi, '');
    
    // Nettoyer formatage
    content = content.replace(/\*\*[^*]+\*\*/g, ''); // Gras markdown
    content = content.replace(/\s{2,}/g, ' '); // Espaces multiples
    content = content.trim();
    
    return content;
  }
}

module.exports = { StyleLayer };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/SelectiveCore.js                  │
└────────────────────────────────────────────────────────────────────┘
*/

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

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { TrendManager } = require('../trend-prompts/TrendManager');

/**
 * MAIN ENTRY POINT - APPLICATION COUCHE SELECTIVE ENHANCEMENT
 * Input: contenu existant + configuration selective
 * Output: contenu avec couche selective appliquée
 */
async function applySelectiveLayer(existingContent, config = {}) {
  return await tracer.run('SelectiveCore.applySelectiveLayer()', async () => {
    const {
      layerType = 'technical', // 'technical' | 'transitions' | 'style' | 'all'
      llmProvider = 'auto',     // 'claude' | 'gpt4' | 'gemini' | 'mistral' | 'auto'
      analysisMode = true,      // Analyser avant d'appliquer
      preserveStructure = true,
      csvData = null,
      context = {},
      trendId = null,           // ID de tendance à appliquer
      trendManager = null       // Instance TrendManager (optionnel)
    } = config;

    // Initialiser TrendManager si tendance spécifiée
    let activeTrendManager = trendManager;
    if (trendId && !activeTrendManager) {
      activeTrendManager = new TrendManager();
      await activeTrendManager.setTrend(trendId);
    }

    await tracer.annotate({
      selectiveLayer: true,
      layerType,
      llmProvider,
      analysisMode,
      elementsCount: Object.keys(existingContent).length
    });

    const startTime = Date.now();
    logSh(`🔧 APPLICATION COUCHE SELECTIVE: ${layerType} (${llmProvider})`, 'INFO');
    logSh(`   📊 ${Object.keys(existingContent).length} éléments | Mode: ${analysisMode ? 'analysé' : 'direct'}`, 'INFO');

    try {
      let enhancedContent = {};
      let layerStats = {};

      // Sélection automatique du LLM si 'auto'
      const selectedLLM = selectOptimalLLM(layerType, llmProvider);
      
      // Application selon type de couche avec configuration tendance
      switch (layerType) {
        case 'technical':
          const technicalConfig = activeTrendManager ?
            activeTrendManager.getLayerConfig('technical', { ...config, llmProvider: selectedLLM }) :
            { ...config, llmProvider: selectedLLM };
          const technicalResult = await applyTechnicalEnhancement(existingContent, technicalConfig);
          enhancedContent = technicalResult.content;
          layerStats = technicalResult.stats;
          break;

        case 'transitions':
          const transitionConfig = activeTrendManager ?
            activeTrendManager.getLayerConfig('transitions', { ...config, llmProvider: selectedLLM }) :
            { ...config, llmProvider: selectedLLM };
          const transitionResult = await applyTransitionEnhancement(existingContent, transitionConfig);
          enhancedContent = transitionResult.content;
          layerStats = transitionResult.stats;
          break;

        case 'style':
          const styleConfig = activeTrendManager ?
            activeTrendManager.getLayerConfig('style', { ...config, llmProvider: selectedLLM }) :
            { ...config, llmProvider: selectedLLM };
          const styleResult = await applyStyleEnhancement(existingContent, styleConfig);
          enhancedContent = styleResult.content;
          layerStats = styleResult.stats;
          break;
          
        case 'all':
          const allResult = await applyAllSelectiveLayers(existingContent, config);
          enhancedContent = allResult.content;
          layerStats = allResult.stats;
          break;
          
        default:
          throw new Error(`Type de couche selective inconnue: ${layerType}`);
      }

      const duration = Date.now() - startTime;
      const stats = {
        layerType,
        llmProvider: selectedLLM,
        elementsProcessed: Object.keys(existingContent).length,
        elementsEnhanced: countEnhancedElements(existingContent, enhancedContent),
        duration,
        ...layerStats
      };

      logSh(`✅ COUCHE SELECTIVE APPLIQUÉE: ${stats.elementsEnhanced}/${stats.elementsProcessed} améliorés (${duration}ms)`, 'INFO');

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

      return {
        content: enhancedContent,
        stats,
        original: existingContent,
        config: { ...config, llmProvider: selectedLLM }
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ COUCHE SELECTIVE É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 });
}

/**
 * APPLICATION TECHNIQUE MODULAIRE
 */
async function applyTechnicalEnhancement(content, config = {}) {
  const { TechnicalLayer } = require('./TechnicalLayer');
  const layer = new TechnicalLayer();
  return await layer.apply(content, config);
}

/**
 * APPLICATION TRANSITIONS MODULAIRE
 */
async function applyTransitionEnhancement(content, config = {}) {
  const { TransitionLayer } = require('./TransitionLayer');
  const layer = new TransitionLayer();
  return await layer.apply(content, config);
}

/**
 * APPLICATION STYLE MODULAIRE
 */
async function applyStyleEnhancement(content, config = {}) {
  const { StyleLayer } = require('./StyleLayer');
  const layer = new StyleLayer();
  return await layer.apply(content, config);
}

/**
 * APPLICATION TOUTES COUCHES SÉQUENTIELLES
 */
async function applyAllSelectiveLayers(content, config = {}) {
  logSh(`🔄 Application séquentielle toutes couches selective`, 'DEBUG');
  
  let currentContent = content;
  const allStats = {
    steps: [],
    totalDuration: 0,
    totalEnhancements: 0
  };
  
  const steps = [
    { name: 'technical', llm: 'gpt4' },
    { name: 'transitions', llm: 'gemini' },
    { name: 'style', llm: 'mistral' }
  ];
  
  for (const step of steps) {
    try {
      logSh(`   🔧 Étape: ${step.name} (${step.llm})`, 'DEBUG');
      
      const stepResult = await applySelectiveLayer(currentContent, {
        ...config,
        layerType: step.name,
        llmProvider: step.llm
      });
      
      currentContent = stepResult.content;
      
      allStats.steps.push({
        name: step.name,
        llm: step.llm,
        ...stepResult.stats
      });
      
      allStats.totalDuration += stepResult.stats.duration;
      allStats.totalEnhancements += stepResult.stats.elementsEnhanced;
      
    } catch (error) {
      logSh(`   ❌ Étape ${step.name} échouée: ${error.message}`, 'ERROR');
      
      allStats.steps.push({
        name: step.name,
        llm: step.llm,
        error: error.message,
        duration: 0,
        elementsEnhanced: 0
      });
    }
  }
  
  return {
    content: currentContent,
    stats: allStats
  };
}

/**
 * ANALYSE BESOIN D'ENHANCEMENT
 */
async function analyzeEnhancementNeeds(content, config = {}) {
  logSh(`🔍 Analyse besoins selective enhancement`, 'DEBUG');
  
  const analysis = {
    technical: { needed: false, score: 0, elements: [] },
    transitions: { needed: false, score: 0, elements: [] },
    style: { needed: false, score: 0, elements: [] },
    recommendation: 'none'
  };
  
  // Analyser chaque élément
  Object.entries(content).forEach(([tag, text]) => {
    // Analyse technique (termes techniques manquants)
    const technicalNeed = assessTechnicalNeed(text, config.csvData);
    if (technicalNeed.score > 0.3) {
      analysis.technical.needed = true;
      analysis.technical.score += technicalNeed.score;
      analysis.technical.elements.push({ tag, score: technicalNeed.score, reason: technicalNeed.reason });
    }
    
    // Analyse transitions (fluidité)
    const transitionNeed = assessTransitionNeed(text);
    if (transitionNeed.score > 0.4) {
      analysis.transitions.needed = true;
      analysis.transitions.score += transitionNeed.score;
      analysis.transitions.elements.push({ tag, score: transitionNeed.score, reason: transitionNeed.reason });
    }
    
    // Analyse style (personnalité)
    const styleNeed = assessStyleNeed(text, config.csvData?.personality);
    if (styleNeed.score > 0.3) {
      analysis.style.needed = true;
      analysis.style.score += styleNeed.score;
      analysis.style.elements.push({ tag, score: styleNeed.score, reason: styleNeed.reason });
    }
  });
  
  // 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;
  
  // Recommandation
  const scores = [
    { type: 'technical', score: analysis.technical.score },
    { type: 'transitions', score: analysis.transitions.score },
    { type: 'style', score: analysis.style.score }
  ].sort((a, b) => b.score - a.score);
  
  if (scores[0].score > 0.6) {
    analysis.recommendation = scores[0].type;
  } else if (scores[0].score > 0.4) {
    analysis.recommendation = 'light_' + scores[0].type;
  }
  
  logSh(`   📊 Analyse: Tech=${analysis.technical.score.toFixed(2)} | Trans=${analysis.transitions.score.toFixed(2)} | Style=${analysis.style.score.toFixed(2)}`, 'DEBUG');
  logSh(`   💡 Recommandation: ${analysis.recommendation}`, 'DEBUG');
  
  return analysis;
}

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

/**
 * Sélectionner LLM optimal selon type de couche
 */
function selectOptimalLLM(layerType, llmProvider) {
  if (llmProvider !== 'auto') return llmProvider;
  
  const optimalMapping = {
    'technical': 'openai',    // OpenAI GPT-4 excellent pour précision technique
    'transitions': 'gemini',   // Gemini bon pour fluidité
    'style': 'mistral',       // Mistral excellent pour style personnalité
    'all': 'claude'           // Claude polyvalent pour tout
  };
  
  return optimalMapping[layerType] || 'claude';
}

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

/**
 * Évaluer besoin technique
 */
function assessTechnicalNeed(content, csvData) {
  let score = 0;
  let reason = [];
  
  // Manque de termes techniques spécifiques
  if (csvData?.mc0) {
    const technicalTerms = ['dibond', 'pmma', 'aluminium', 'fraisage', 'impression', 'gravure', 'découpe'];
    const contentLower = content.toLowerCase();
    const foundTerms = technicalTerms.filter(term => contentLower.includes(term));
    
    if (foundTerms.length === 0 && content.length > 100) {
      score += 0.4;
      reason.push('manque_termes_techniques');
    }
  }
  
  // Vocabulaire trop générique
  const genericWords = ['produit', 'solution', 'service', 'qualité', 'offre'];
  const genericCount = genericWords.filter(word => content.toLowerCase().includes(word)).length;
  
  if (genericCount > 2) {
    score += 0.3;
    reason.push('vocabulaire_générique');
  }
  
  // Manque de précision dimensionnelle/technique
  if (content.length > 50 && !(/\d+\s*(mm|cm|m|%|°)/.test(content))) {
    score += 0.2;
    reason.push('manque_précision_technique');
  }
  
  return { score: Math.min(1, score), reason: reason.join(',') };
}

/**
 * Évaluer besoin transitions
 */
function assessTransitionNeed(content) {
  let score = 0;
  let reason = [];
  
  const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 10);
  
  if (sentences.length < 2) return { score: 0, reason: '' };
  
  // Connecteurs répétitifs
  const connectors = ['par ailleurs', 'en effet', 'de plus', 'cependant'];
  let repetitiveConnectors = 0;
  
  connectors.forEach(connector => {
    const matches = (content.match(new RegExp(connector, 'gi')) || []);
    if (matches.length > 1) repetitiveConnectors++;
  });
  
  if (repetitiveConnectors > 1) {
    score += 0.4;
    reason.push('connecteurs_répétitifs');
  }
  
  // Transitions abruptes (phrases sans connecteurs logiques)
  let abruptTransitions = 0;
  for (let i = 1; i < sentences.length; i++) {
    const sentence = sentences[i].trim().toLowerCase();
    const hasConnector = connectors.some(conn => sentence.startsWith(conn)) ||
                        /^(puis|ensuite|également|aussi|donc|ainsi)/.test(sentence);
    
    if (!hasConnector && sentence.length > 30) {
      abruptTransitions++;
    }
  }
  
  if (abruptTransitions / sentences.length > 0.6) {
    score += 0.3;
    reason.push('transitions_abruptes');
  }
  
  return { score: Math.min(1, score), reason: reason.join(',') };
}

/**
 * Évaluer besoin style
 */
function assessStyleNeed(content, personality) {
  let score = 0;
  let reason = [];
  
  if (!personality) {
    score += 0.2;
    reason.push('pas_personnalité');
    return { score, reason: reason.join(',') };
  }
  
  // Style générique (pas de personnalité visible)
  const personalityWords = (personality.vocabulairePref || '').toLowerCase().split(',');
  const contentLower = content.toLowerCase();
  
  const personalityFound = personalityWords.some(word => 
    word.trim() && contentLower.includes(word.trim())
  );
  
  if (!personalityFound && content.length > 50) {
    score += 0.4;
    reason.push('style_générique');
  }
  
  // Niveau technique inadapté
  if (personality.niveauTechnique === 'accessible' && /\b(optimisation|implémentation|méthodologie)\b/i.test(content)) {
    score += 0.3;
    reason.push('trop_technique');
  }
  
  return { score: Math.min(1, score), reason: reason.join(',') };
}

module.exports = {
  applySelectiveLayer,              // ← MAIN ENTRY POINT MODULAIRE
  applyTechnicalEnhancement,
  applyTransitionEnhancement, 
  applyStyleEnhancement,
  applyAllSelectiveLayers,
  analyzeEnhancementNeeds,
  selectOptimalLLM
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/adversarial-generation/DetectorStrategies.js            │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// DETECTOR STRATEGIES - NIVEAU 3
// Responsabilité: Stratégies spécialisées par détecteur IA
// Anti-détection: Techniques ciblées contre chaque analyseur
// ========================================

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

/**
 * STRATÉGIES DÉTECTEUR PAR DÉTECTEUR
 * Chaque classe implémente une approche spécialisée
 */

class BaseDetectorStrategy {
  constructor(name) {
    this.name = name;
    this.effectiveness = 0.8;
    this.targetMetrics = [];
  }

  /**
   * Générer instructions spécifiques pour ce détecteur
   */
  generateInstructions(elementType, personality, csvData) {
    throw new Error('generateInstructions must be implemented by subclass');
  }

  /**
   * Obtenir instructions anti-détection (NOUVEAU pour modularité)
   */
  getInstructions(intensity = 1.0) {
    throw new Error('getInstructions must be implemented by subclass');
  }

  /**
   * Obtenir conseils d'amélioration (NOUVEAU pour modularité)
   */
  getEnhancementTips(intensity = 1.0) {
    throw new Error('getEnhancementTips must be implemented by subclass');
  }

  /**
   * Analyser efficacité contre ce détecteur
   */
  analyzeEffectiveness(content) {
    return {
      detector: this.name,
      effectiveness: this.effectiveness,
      metrics: this.analyzeContent(content)
    };
  }

  /**
   * Analyser contenu selon métriques de ce détecteur
   */
  analyzeContent(content) {
    return {
      wordCount: content.split(/\s+/).length,
      sentenceCount: content.split(/[.!?]+/).length
    };
  }
}

/**
 * STRATÉGIE ANTI-GPTZERO
 * Focus: Imprévisibilité et variation syntaxique
 */
class GPTZeroStrategy extends BaseDetectorStrategy {
  constructor() {
    super('GPTZero');
    this.effectiveness = 0.9;
    this.targetMetrics = ['perplexity', 'burstiness', 'unpredictability'];
    
    this.techniques = {
      syntaxVariation: {
        name: 'Variation syntaxique drastique',
        rules: [
          'Alterne phrases simples (5-8 mots) et complexes (25-35 mots)',
          'Utilise structures atypiques : inversion, anacoluthe, ellipse',
          'Intercale incises, parenthèses, tirets pour briser linéarité',
          'Varie types : déclarative → interrogative → exclamative'
        ]
      },
      lexicalUnpredictability: {
        name: 'Imprévisibilité lexicale',
        rules: [
          'Synonymes rares ou détournés : "performant" → "qui tient la route"',
          'Néologismes justifiés : "sur-mesurable" pour "très mesurable"',
          'Registres mélangés : soutenu puis familier dans même paragraphe',
          'Évite collocations attendues : "haute qualité" → "qualité qui dépote"'
        ]
      },
      narrativeDisruption: {
        name: 'Disruption narrative',
        rules: [
          'Apartés personnels : "(j\'ai testé, c\'est bluffant)"',
          'Questions rhétoriques inattendues au milieu des faits',
          'Changements de perspective soudains : technique → humain → commercial',
          'Digressions courtes puis retour au sujet'
        ]
      }
    };
  }

  generateInstructions(elementType, personality, csvData) {
    const instructions = [];
    
    instructions.push(`ANTI-GPTZERO - MAXIMUM IMPRÉVISIBILITÉ:`);
    
    // Techniques syntaxiques
    instructions.push(`\nSYNTAXE VARIABLE:`);
    this.techniques.syntaxVariation.rules.forEach(rule => {
      instructions.push(`• ${rule}`);
    });
    
    // Imprévisibilité lexicale
    instructions.push(`\nLEXIQUE IMPRÉVISIBLE:`);
    this.techniques.lexicalUnpredictability.rules.forEach(rule => {
      instructions.push(`• ${rule}`);
    });
    
    // Adaptation selon type élément
    if (elementType === 'titre_h1' || elementType === 'titre_h2') {
      instructions.push(`\nTITRES ANTI-GPTZERO:`);
      instructions.push(`• Évite formules attendues : "Guide complet" → "Le vrai topo sur"`);
      instructions.push(`• Structure atypique : question, exclamation, fragment`);
    } else if (elementType === 'texte') {
      instructions.push(`\nTEXTES ANTI-GPTZERO:`);
      this.techniques.narrativeDisruption.rules.forEach(rule => {
        instructions.push(`• ${rule}`);
      });
    }
    
    // Adaptation personnalité
    if (personality) {
      instructions.push(`\nAVEC STYLE ${personality.nom.toUpperCase()}:`);
      instructions.push(`• Pousse ${personality.style} vers extrêmes : plus marqué, moins lisse`);
      instructions.push(`• Accentue tics de langage : répétitions, expressions favorites`);
    }
    
    return instructions.join('\n');
  }

  /**
   * Instructions modulaires pour AdversarialCore
   */
  getInstructions(intensity = 1.0) {
    const baseRules = [
      'Surprends avec tournures inattendues et constructions atypiques',
      'Évite phrases trop prévisibles ou patterns répétitifs',
      'Utilise synonymes moins évidents et vocabulaire moins commun',
      'Varie drastiquement la complexité syntaxique entre phrases'
    ];

    const intensiveRules = [
      'Intercale observations personnelles ou détours narratifs',
      'Alterne registres de langue (soutenu → familier → technique)',
      'Brise la logique linéaire avec des parenthèses, incises, apartés',
      'Créé ruptures narratives et changements de perspective soudains'
    ];

    return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules;
  }

  /**
   * Conseils d'amélioration pour enhancement method
   */
  getEnhancementTips(intensity = 1.0) {
    return [
      'Remplace connecteurs prévisibles par variations inattendues',
      'Ajoute incises courtes pour briser la linéarité',
      'Varie longueurs phrases dans même paragraphe',
      'Utilise synonymes moins courants mais naturels',
      ...(intensity > 0.8 ? [
        'Insère questions rhétoriques ponctuelles', 
        'Ajoute nuances et hésitations authentiques'
      ] : [])
    ];
  }

  analyzeContent(content) {
    const baseMetrics = super.analyzeContent(content);
    
    // Analyse perplexité approximative
    const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 5);
    const sentenceLengths = sentences.map(s => s.split(/\s+/).length);
    
    // Variance longueur (proxy pour burstiness)
    const avgLength = sentenceLengths.reduce((a, b) => a + b, 0) / sentenceLengths.length;
    const variance = sentenceLengths.reduce((acc, len) => acc + Math.pow(len - avgLength, 2), 0) / sentenceLengths.length;
    const burstiness = Math.sqrt(variance) / avgLength;
    
    // Diversité lexicale (proxy pour imprévisibilité)
    const words = content.toLowerCase().split(/\s+/).filter(w => w.length > 2);
    const uniqueWords = [...new Set(words)];
    const lexicalDiversity = uniqueWords.length / words.length;
    
    return {
      ...baseMetrics,
      burstiness: Math.round(burstiness * 100) / 100,
      lexicalDiversity: Math.round(lexicalDiversity * 100) / 100,
      avgSentenceLength: Math.round(avgLength),
      gptZeroRiskLevel: this.calculateGPTZeroRisk(burstiness, lexicalDiversity)
    };
  }

  calculateGPTZeroRisk(burstiness, lexicalDiversity) {
    // Heuristique : GPTZero détecte uniformité faible + diversité faible
    const uniformityScore = Math.min(burstiness, 1) * 100;
    const diversityScore = lexicalDiversity * 100;
    const combinedScore = (uniformityScore + diversityScore) / 2;
    
    if (combinedScore > 70) return 'low';
    if (combinedScore > 40) return 'medium';
    return 'high';
  }
}

/**
 * STRATÉGIE ANTI-ORIGINALITY
 * Focus: Diversité sémantique et originalité
 */
class OriginalityStrategy extends BaseDetectorStrategy {
  constructor() {
    super('Originality');
    this.effectiveness = 0.85;
    this.targetMetrics = ['semantic_diversity', 'originality_score', 'vocabulary_range'];
    
    this.techniques = {
      semanticCreativity: {
        name: 'Créativité sémantique',
        rules: [
          'Métaphores inattendues : "cette plaque, c\'est le passeport de votre façade"',
          'Comparaisons originales : évite clichés, invente analogies',
          'Reformulations créatives : "résistant aux intempéries" → "qui brave les saisons"',
          'Néologismes justifiés et expressifs'
        ]
      },
      perspectiveShifting: {
        name: 'Changements de perspective',
        rules: [
          'Angles multiples sur même info : technique → esthétique → pratique',
          'Points de vue variés : fabricant, utilisateur, installateur, voisin',
          'Temporalités mélangées : présent, futur proche, retour d\'expérience',
          'Niveaux d\'abstraction : détail précis puis vue d\'ensemble'
        ]
      },
      linguisticInventiveness: {
        name: 'Inventivité linguistique',
        rules: [
          'Jeux de mots subtils et expressions détournées',
          'Régionalismes et références culturelles précises',
          'Vocabulaire technique humanisé avec créativité',
          'Rythmes et sonorités travaillés : allitérations, assonances'
        ]
      }
    };
  }

  generateInstructions(elementType, personality, csvData) {
    const instructions = [];
    
    instructions.push(`ANTI-ORIGINALITY - MAXIMUM CRÉATIVITÉ SÉMANTIQUE:`);
    
    // Créativité sémantique
    instructions.push(`\nCRÉATIVITÉ SÉMANTIQUE:`);
    this.techniques.semanticCreativity.rules.forEach(rule => {
      instructions.push(`• ${rule}`);
    });
    
    // Changements de perspective
    instructions.push(`\nPERSPECTIVES MULTIPLES:`);
    this.techniques.perspectiveShifting.rules.forEach(rule => {
      instructions.push(`• ${rule}`);
    });
    
    // Spécialisation par élément
    if (elementType === 'intro') {
      instructions.push(`\nINTROS ANTI-ORIGINALITY:`);
      instructions.push(`• Commence par angle totalement inattendu pour le sujet`);
      instructions.push(`• Évite intro-types, réinvente présentation du sujet`);
      instructions.push(`• Crée surprise puis retour naturel au cœur du sujet`);
    } else if (elementType.includes('faq')) {
      instructions.push(`\nFAQ ANTI-ORIGINALITY:`);
      instructions.push(`• Questions vraiment originales, pas standard secteur`);
      instructions.push(`• Réponses avec angles créatifs et exemples inédits`);
    }
    
    // Contexte métier créatif
    if (csvData && csvData.mc0) {
      instructions.push(`\nCRÉATIVITÉ CONTEXTUELLE ${csvData.mc0.toUpperCase()}:`);
      instructions.push(`• Réinvente façon de parler de ${csvData.mc0}`);
      instructions.push(`• Évite vocabulaire convenu du secteur, invente expressions`);
      instructions.push(`• Trouve analogies originales spécifiques à ${csvData.mc0}`);
    }
    
    // Inventivité linguistique
    instructions.push(`\nINVENTIVITÉ LINGUISTIQUE:`);
    this.techniques.linguisticInventiveness.rules.forEach(rule => {
      instructions.push(`• ${rule}`);
    });
    
    return instructions.join('\n');
  }

  /**
   * Instructions modulaires pour AdversarialCore
   */
  getInstructions(intensity = 1.0) {
    const baseRules = [
      'Vocabulaire TRÈS varié : évite répétitions même de synonymes',
      'Structures phrases délibérément irrégulières et asymétriques',
      'Changements angles fréquents : technique → personnel → général',
      'Créativité sémantique : métaphores, comparaisons inattendues'
    ];

    const intensiveRules = [
      'Évite formulations académiques ou trop structurées',
      'Intègre références culturelles, expressions régionales',
      'Subvertis les attentes : commence par la fin, questionne l\'évidence',
      'Réinvente façon de présenter informations basiques'
    ];

    return intensity >= 1.0 ? [...baseRules, ...intensiveRules] : baseRules;
  }

  /**
   * Conseils d'amélioration pour enhancement method
   */
  getEnhancementTips(intensity = 1.0) {
    return [
      'Trouve synonymes créatifs et expressions détournées',
      'Ajoute métaphores subtiles et comparaisons originales', 
      'Varie angles d\'approche dans même contenu',
      'Utilise vocabulaire technique humanisé',
      ...(intensity > 0.8 ? [
        'Insère références culturelles ou régionalismes',
        'Crée néologismes justifiés et expressifs'
      ] : [])
    ];
  }

  analyzeContent(content) {
    const baseMetrics = super.analyzeContent(content);
    
    // Analyse diversité sémantique
    const words = content.toLowerCase().split(/\s+/).filter(w => w.length > 3);
    const uniqueWords = [...new Set(words)];
    const semanticDiversity = uniqueWords.length / words.length;
    
    // Détection créativité (heuristique)
    const creativityIndicators = [
      'comme', 'tel', 'sorte de', 'façon de', 'manière de', // métaphores
      '(', ')', '"', // originalité structure
      '?', '!', // variation tonale
    ];
    
    const creativityCount = creativityIndicators.reduce((count, indicator) => {
      return count + (content.match(new RegExp(indicator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g')) || []).length;
    }, 0);
    
    const creativityScore = Math.min(100, (creativityCount / words.length) * 1000);
    
    return {
      ...baseMetrics,
      semanticDiversity: Math.round(semanticDiversity * 100) / 100,
      creativityScore: Math.round(creativityScore),
      uniqueWordRatio: Math.round((uniqueWords.length / words.length) * 100),
      originalityRiskLevel: this.calculateOriginalityRisk(semanticDiversity, creativityScore)
    };
  }

  calculateOriginalityRisk(semanticDiversity, creativityScore) {
    const diversityScore = semanticDiversity * 100;
    const combinedScore = (diversityScore + creativityScore) / 2;
    
    if (combinedScore > 60) return 'low';
    if (combinedScore > 35) return 'medium';
    return 'high';
  }
}

/**
 * STRATÉGIE GÉNÉRALE
 * Équilibre entre toutes les techniques
 */
class GeneralStrategy extends BaseDetectorStrategy {
  constructor() {
    super('General');
    this.effectiveness = 0.75;
    this.targetMetrics = ['overall_naturalness', 'human_likeness'];
  }

  generateInstructions(elementType, personality, csvData) {
    const instructions = [];
    
    instructions.push(`ANTI-DÉTECTION GÉNÉRALE - ÉQUILIBRE OPTIMAL:`);
    
    // Instructions générales équilibrées
    instructions.push(`\nNATUREL ET VARIÉ:`);
    instructions.push(`• Évite mots typiques IA : "optimal", "comprehensive", "seamless", "robust"`);
    instructions.push(`• Mélange phrases courtes (5-10 mots) et longues (15-25 mots) naturellement`);
    instructions.push(`• Utilise expressions idiomatiques françaises authentiques`);
    instructions.push(`• Intègre imperfections humaines : répétitions légères, hésitations`);
    instructions.push(`• Change angle ou ton 1-2 fois selon longueur du contenu`);
    
    // Adaptation personnalité équilibrée
    if (personality) {
      instructions.push(`\nSTYLE ${personality.nom} NATUREL:`);
      instructions.push(`• Applique style ${personality.style} de façon authentique, pas forcée`);
      instructions.push(`• Respecte vocabulaire naturel : ${personality.vocabulairePref || 'varié'}`);
      instructions.push(`• Utilise connecteurs variés : ${personality.connecteursPref || 'naturels'}`);
    }
    
    return instructions.join('\n');
  }

  /**
   * Instructions modulaires pour AdversarialCore
   */
  getInstructions(intensity = 1.0) {
    const baseRules = [
      'Évite ces mots typiques IA : "optimal", "comprehensive", "seamless", "robust", "leverage"',
      'Varie longueurs phrases : mélange phrases courtes (5-10 mots) ET longues (20-30 mots)',
      'Utilise expressions françaises familières et tournures idiomatiques',
      'Ajoute imperfections naturelles : répétitions légères, hésitations, reformulations'
    ];

    const intensiveRules = [
      'Change angle ou perspective 1-2 fois dans le texte',
      'Préfère synonymes moins évidents : "bon" plutôt qu\'excellent", "solide" plutôt qu\'optimisé"',
      'Intègre connecteurs variés et naturels selon le contexte',
      'Simule variation naturelle d\'humeur et d\'énergie rédactionnelle'
    ];

    return intensity >= 0.8 ? [...baseRules, ...intensiveRules] : baseRules;
  }

  /**
   * Conseils d'amélioration pour enhancement method
   */
  getEnhancementTips(intensity = 1.0) {
    return [
      'Remplace mots typiques IA par synonymes plus naturels',
      'Ajoute nuances et hésitations : "peut-être", "généralement", "souvent"',
      'Varie connecteurs pour éviter répétitions mécaniques',
      'Personnalise avec observations subjectives légères',
      ...(intensity > 0.7 ? [
        'Intègre "erreurs" humaines : corrections, précisions',
        'Simule changement léger de ton ou d\'énergie'
      ] : [])
    ];
  }

  analyzeContent(content) {
    const baseMetrics = super.analyzeContent(content);
    
    // Métrique naturalité générale
    const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 5);
    const avgWordsPerSentence = baseMetrics.wordCount / baseMetrics.sentenceCount;
    
    // Détection mots typiques IA
    const aiWords = ['optimal', 'comprehensive', 'seamless', 'robust', 'leverage'];
    const aiWordCount = aiWords.reduce((count, word) => {
      return count + (content.toLowerCase().match(new RegExp(`\\b${word}\\b`, 'g')) || []).length;
    }, 0);
    
    const aiWordDensity = aiWordCount / baseMetrics.wordCount * 100;
    const naturalness = Math.max(0, 100 - (aiWordDensity * 10) - Math.abs(avgWordsPerSentence - 15));
    
    return {
      ...baseMetrics,
      avgWordsPerSentence: Math.round(avgWordsPerSentence),
      aiWordCount,
      aiWordDensity: Math.round(aiWordDensity * 100) / 100,
      naturalnessScore: Math.round(naturalness),
      generalRiskLevel: naturalness > 70 ? 'low' : naturalness > 40 ? 'medium' : 'high'
    };
  }
}

/**
 * FACTORY POUR CRÉER STRATÉGIES
 */
class DetectorStrategyFactory {
  static strategies = {
    'general': GeneralStrategy,
    'gptZero': GPTZeroStrategy,
    'originality': OriginalityStrategy
  };

  static createStrategy(detectorName) {
    const StrategyClass = this.strategies[detectorName];
    if (!StrategyClass) {
      logSh(`⚠️ Stratégie inconnue: ${detectorName}, fallback vers général`, 'WARNING');
      return new GeneralStrategy();
    }
    return new StrategyClass();
  }

  static getSupportedDetectors() {
    return Object.keys(this.strategies).map(name => {
      const strategy = this.createStrategy(name);
      return {
        name,
        displayName: strategy.name,
        effectiveness: strategy.effectiveness,
        targetMetrics: strategy.targetMetrics
      };
    });
  }

  static analyzeContentAgainstAllDetectors(content) {
    const results = {};
    
    Object.keys(this.strategies).forEach(detectorName => {
      const strategy = this.createStrategy(detectorName);
      results[detectorName] = strategy.analyzeEffectiveness(content);
    });
    
    return results;
  }
}

/**
 * FONCTION UTILITAIRE - SÉLECTION STRATÉGIE OPTIMALE
 */
function selectOptimalStrategy(elementType, personality, previousResults = {}) {
  // Logique de sélection intelligente
  
  // Si résultats précédents disponibles, adapter
  if (previousResults.gptZero && previousResults.gptZero.effectiveness < 0.6) {
    return 'gptZero'; // Renforcer anti-GPTZero
  }
  
  if (previousResults.originality && previousResults.originality.effectiveness < 0.6) {
    return 'originality'; // Renforcer anti-Originality
  }
  
  // Sélection par type d'élément
  if (elementType === 'titre_h1' || elementType === 'titre_h2') {
    return 'gptZero'; // Titres bénéficient imprévisibilité
  }
  
  if (elementType === 'intro' || elementType === 'texte') {
    return 'originality'; // Corps bénéficie créativité sémantique
  }
  
  if (elementType.includes('faq')) {
    return 'general'; // FAQ équilibre naturalité
  }
  
  // Par personnalité
  if (personality) {
    if (personality.style === 'créatif' || personality.style === 'original') {
      return 'originality';
    }
    if (personality.style === 'technique' || personality.style === 'expert') {
      return 'gptZero';
    }
  }
  
  return 'general'; // Fallback
}

module.exports = {
  DetectorStrategyFactory,
  GPTZeroStrategy,
  OriginalityStrategy,  
  GeneralStrategy,
  selectOptimalStrategy,
  BaseDetectorStrategy
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/adversarial-generation/AdversarialCore.js               │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// 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 = {}
    } = config;

    await tracer.annotate({
      adversarialLayer: true,
      detectorTarget,
      intensity,
      method,
      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}`, 'INFO');

    try {
      // Initialiser stratégie détecteur  
      const strategy = DetectorStrategyFactory.createStrategy(detectorTarget);
      
      // Appliquer méthode adversariale choisie
      let adversarialContent = {};
      
      switch (method) {
        case 'regeneration':
          adversarialContent = await applyRegenerationMethod(existingContent, config, strategy);
          break;
        case 'enhancement':
          adversarialContent = await applyEnhancementMethod(existingContent, config, strategy);
          break;
        case 'hybrid':
          adversarialContent = await applyHybridMethod(existingContent, config, 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,
        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) {
  logSh(`🔄 Méthode régénération adversariale`, '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('claude', 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) {
  logSh(`🔧 Méthode enhancement adversarial`, '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('gpt4', 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
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/FatiguePatterns.js                     │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: FatiguePatterns.js
// RESPONSABILITÉ: Simulation fatigue cognitive
// Implémentation courbe fatigue exacte du plan.md
// ========================================

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

/**
 * PROFILS DE FATIGUE PAR PERSONNALITÉ
 * Basé sur les 15 personnalités du système
 */
const FATIGUE_PROFILES = {
  // Techniques - Résistent plus longtemps
  marc: { peakAt: 0.45, recovery: 0.85, intensity: 0.8 },
  amara: { peakAt: 0.43, recovery: 0.87, intensity: 0.7 },
  yasmine: { peakAt: 0.47, recovery: 0.83, intensity: 0.75 },
  fabrice: { peakAt: 0.44, recovery: 0.86, intensity: 0.8 },

  // Créatifs - Fatigue plus variable
  sophie: { peakAt: 0.55, recovery: 0.90, intensity: 1.0 },
  émilie: { peakAt: 0.52, recovery: 0.88, intensity: 0.9 },
  chloé: { peakAt: 0.58, recovery: 0.92, intensity: 1.1 },
  minh: { peakAt: 0.53, recovery: 0.89, intensity: 0.95 },

  // Commerciaux - Fatigue rapide mais récupération
  laurent: { peakAt: 0.40, recovery: 0.80, intensity: 1.2 },
  julie: { peakAt: 0.38, recovery: 0.78, intensity: 1.0 },

  // Terrain - Endurance élevée
  kévin: { peakAt: 0.35, recovery: 0.75, intensity: 0.6 },
  mamadou: { peakAt: 0.37, recovery: 0.77, intensity: 0.65 },
  linh: { peakAt: 0.36, recovery: 0.76, intensity: 0.7 },

  // Patrimoniaux - Fatigue progressive
  'pierre-henri': { peakAt: 0.48, recovery: 0.82, intensity: 0.85 },
  thierry: { peakAt: 0.46, recovery: 0.84, intensity: 0.8 },

  // Profil par défaut
  default: { peakAt: 0.50, recovery: 0.85, intensity: 1.0 }
};

/**
 * CALCUL FATIGUE COGNITIVE - FORMULE EXACTE DU PLAN
 * Peak à 50% de progression selon courbe sinusoïdale
 * @param {number} elementIndex - Position élément (0-based)
 * @param {number} totalElements - Nombre total d'éléments
 * @returns {number} - Niveau fatigue (0-0.8)
 */
function calculateFatigue(elementIndex, totalElements) {
  if (totalElements <= 1) return 0;
  
  const position = elementIndex / totalElements;
  const fatigueLevel = Math.sin(position * Math.PI) * 0.8; // Peak à 50%
  
  logSh(`🧠 Fatigue calculée: position=${position.toFixed(2)}, niveau=${fatigueLevel.toFixed(2)}`, 'DEBUG');
  
  return Math.max(0, fatigueLevel);
}

/**
 * OBTENIR PROFIL FATIGUE PAR PERSONNALITÉ
 * @param {string} personalityName - Nom personnalité
 * @returns {object} - Profil fatigue
 */
function getFatigueProfile(personalityName) {
  const normalizedName = personalityName?.toLowerCase() || 'default';
  const profile = FATIGUE_PROFILES[normalizedName] || FATIGUE_PROFILES.default;
  
  logSh(`🎭 Profil fatigue sélectionné pour ${personalityName}: peakAt=${profile.peakAt}, intensity=${profile.intensity}`, 'DEBUG');
  
  return profile;
}

/**
 * INJECTION MARQUEURS DE FATIGUE
 * @param {string} content - Contenu à modifier
 * @param {number} fatigueLevel - Niveau fatigue (0-0.8)
 * @param {object} options - Options { profile, intensity }
 * @returns {object} - { content, modifications }
 */
function injectFatigueMarkers(content, fatigueLevel, options = {}) {
  if (!content || fatigueLevel < 0.05) { // FIXÉ: Seuil beaucoup plus bas (était 0.2)
    return { content, modifications: 0 };
  }

  const profile = options.profile || FATIGUE_PROFILES.default;
  const baseIntensity = options.intensity || 1.0;
  
  // Intensité ajustée selon personnalité
  const adjustedIntensity = fatigueLevel * profile.intensity * baseIntensity;
  
  logSh(`💤 Injection fatigue: niveau=${fatigueLevel.toFixed(2)}, intensité=${adjustedIntensity.toFixed(2)}`, 'DEBUG');

  let modifiedContent = content;
  let modifications = 0;

  // ========================================
  // FATIGUE LÉGÈRE (0.05 - 0.4) - FIXÉ: Seuil plus bas
  // ========================================
  if (fatigueLevel >= 0.05 && fatigueLevel < 0.4) {
    const lightFatigueResult = applyLightFatigue(modifiedContent, adjustedIntensity);
    modifiedContent = lightFatigueResult.content;
    modifications += lightFatigueResult.count;
  }

  // ========================================
  // FATIGUE MODÉRÉE (0.4 - 0.6)
  // ========================================
  if (fatigueLevel >= 0.4 && fatigueLevel < 0.6) {
    const moderateFatigueResult = applyModerateFatigue(modifiedContent, adjustedIntensity);
    modifiedContent = moderateFatigueResult.content;
    modifications += moderateFatigueResult.count;
  }

  // ========================================
  // FATIGUE ÉLEVÉE (0.6+)
  // ========================================
  if (fatigueLevel >= 0.6) {
    const heavyFatigueResult = applyHeavyFatigue(modifiedContent, adjustedIntensity);
    modifiedContent = heavyFatigueResult.content;
    modifications += heavyFatigueResult.count;
  }

  logSh(`💤 Fatigue appliquée: ${modifications} modifications`, 'DEBUG');

  return {
    content: modifiedContent,
    modifications
  };
}

/**
 * FATIGUE LÉGÈRE - Connecteurs simplifiés
 */
function applyLightFatigue(content, intensity) {
  let modified = content;
  let count = 0;

  // Probabilité d'application basée sur l'intensité - ENCORE PLUS AGRESSIF
  const shouldApply = Math.random() < (intensity * 0.9); // FIXÉ: 90% chance d'appliquer
  if (!shouldApply) return { content: modified, count };

  // Simplification des connecteurs complexes - ÉLARGI
  const complexConnectors = [
    { from: /néanmoins/gi, to: 'cependant' },
    { from: /par conséquent/gi, to: 'donc' },
    { from: /ainsi que/gi, to: 'et' },
    { from: /en outre/gi, to: 'aussi' },
    { from: /de surcroît/gi, to: 'de plus' },
    // NOUVEAUX AJOUTS AGRESSIFS
    { from: /toutefois/gi, to: 'mais' },
    { from: /cependant/gi, to: 'mais bon' },
    { from: /par ailleurs/gi, to: 'sinon' },
    { from: /en effet/gi, to: 'effectivement' },
    { from: /de fait/gi, to: 'en fait' }
  ];

  complexConnectors.forEach(connector => {
    const matches = modified.match(connector.from);
    if (matches && Math.random() < 0.9) { // FIXÉ: 90% chance très agressive
      modified = modified.replace(connector.from, connector.to);
      count++;
    }
  });
  
  // AJOUT FIX: Si aucun connecteur complexe trouvé, appliquer une modification alternative
  if (count === 0 && Math.random() < 0.7) {
    // Injecter des simplifications basiques
    if (modified.includes(' et ') && Math.random() < 0.5) {
      modified = modified.replace(' et ', ' puis ');
      count++;
    }
  }

  return { content: modified, count };
}

/**
 * FATIGUE MODÉRÉE - Phrases plus courtes
 */
function applyModerateFatigue(content, intensity) {
  let modified = content;
  let count = 0;

  const shouldApply = Math.random() < (intensity * 0.5);
  if (!shouldApply) return { content: modified, count };

  // Découpage phrases longues (>120 caractères)
  const sentences = modified.split('. ');
  const processedSentences = sentences.map(sentence => {
    if (sentence.length > 120 && Math.random() < 0.3) { // 30% chance
      // Trouver un point de découpe logique
      const cutPoints = [', qui', ', que', ', dont', ' et ', ' car '];
      for (const cutPoint of cutPoints) {
        const cutIndex = sentence.indexOf(cutPoint);
        if (cutIndex > 30 && cutIndex < sentence.length - 30) {
          count++;
          return sentence.substring(0, cutIndex) + '. ' + 
                 sentence.substring(cutIndex + cutPoint.length);
        }
      }
    }
    return sentence;
  });

  modified = processedSentences.join('. ');

  // Vocabulaire plus simple
  const simplifications = [
    { from: /optimisation/gi, to: 'amélioration' },
    { from: /méthodologie/gi, to: 'méthode' },
    { from: /problématique/gi, to: 'problème' },
    { from: /spécifications/gi, to: 'détails' }
  ];

  simplifications.forEach(simpl => {
    if (modified.match(simpl.from) && Math.random() < 0.3) {
      modified = modified.replace(simpl.from, simpl.to);
      count++;
    }
  });

  return { content: modified, count };
}

/**
 * FATIGUE ÉLEVÉE - Répétitions et vocabulaire basique
 */
function applyHeavyFatigue(content, intensity) {
  let modified = content;
  let count = 0;

  const shouldApply = Math.random() < (intensity * 0.7);
  if (!shouldApply) return { content: modified, count };

  // Injection répétitions naturelles
  const repetitionWords = ['bien', 'très', 'vraiment', 'assez', 'plutôt'];
  const sentences = modified.split('. ');
  
  sentences.forEach((sentence, index) => {
    if (Math.random() < 0.2 && sentence.length > 50) { // 20% chance
      const word = repetitionWords[Math.floor(Math.random() * repetitionWords.length)];
      // Injecter le mot répétitif au milieu de la phrase
      const words = sentence.split(' ');
      const insertIndex = Math.floor(words.length / 2);
      words.splice(insertIndex, 0, word);
      sentences[index] = words.join(' ');
      count++;
    }
  });

  modified = sentences.join('. ');

  // Vocabulaire très basique
  const basicVocab = [
    { from: /excellente?/gi, to: 'bonne' },
    { from: /remarquable/gi, to: 'bien' },
    { from: /sophistiqué/gi, to: 'avancé' },
    { from: /performant/gi, to: 'efficace' },
    { from: /innovations?/gi, to: 'nouveautés' }
  ];

  basicVocab.forEach(vocab => {
    if (modified.match(vocab.from) && Math.random() < 0.4) {
      modified = modified.replace(vocab.from, vocab.to);
      count++;
    }
  });

  // Hésitations légères (rare)
  if (Math.random() < 0.1) { // 10% chance
    const hesitations = ['... enfin', '... disons', '... comment dire'];
    const hesitation = hesitations[Math.floor(Math.random() * hesitations.length)];
    const words = modified.split(' ');
    const insertIndex = Math.floor(words.length * 0.7); // Vers la fin
    words.splice(insertIndex, 0, hesitation);
    modified = words.join(' ');
    count++;
  }

  return { content: modified, count };
}

/**
 * RÉCUPÉRATION FATIGUE (pour les éléments en fin)
 * @param {string} content - Contenu à traiter
 * @param {number} recoveryLevel - Niveau récupération (0-1)
 * @returns {object} - { content, modifications }
 */
function applyFatigueRecovery(content, recoveryLevel) {
  if (recoveryLevel < 0.8) return { content, modifications: 0 };

  let modified = content;
  let count = 0;

  // Réintroduire vocabulaire plus sophistiqué
  const recoveryVocab = [
    { from: /\bbien\b/gi, to: 'excellent' },
    { from: /\befficace\b/gi, to: 'performant' },
    { from: /\bméthode\b/gi, to: 'méthodologie' }
  ];

  recoveryVocab.forEach(vocab => {
    if (modified.match(vocab.from) && Math.random() < 0.3) {
      modified = modified.replace(vocab.from, vocab.to);
      count++;
    }
  });

  return { content: modified, count };
}

// ============= EXPORTS =============
module.exports = {
  calculateFatigue,
  getFatigueProfile,
  injectFatigueMarkers,
  applyLightFatigue,
  applyModerateFatigue,
  applyHeavyFatigue,
  applyFatigueRecovery,
  FATIGUE_PROFILES
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/PersonalityErrors.js                   │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: PersonalityErrors.js  
// RESPONSABILITÉ: Erreurs cohérentes par personnalité
// 15 profils d'erreurs basés sur les personnalités système
// ========================================

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

/**
 * PATTERNS D'ERREURS PAR PERSONNALITÉ
 * Basé sur les 15 personnalités du BrainConfig
 * Chaque personnalité a ses tics linguistiques et erreurs typiques
 */
const PERSONALITY_ERROR_PATTERNS = {
  
  // ========================================
  // PERSONNALITÉS TECHNIQUES
  // ========================================
  marc: {
    name: 'Marc - Expert Technique',
    tendencies: ['sur-technicisation', 'anglicismes techniques', 'jargon professionnel'],
    repetitions: ['précis', 'efficace', 'optimal', 'performant', 'système'],
    syntaxErrors: [
      'phrases techniques non finies',
      'parenthèses explicatives excessives',
      'abréviations sans développement'
    ],
    vocabularyTics: ['niveau technique', 'en termes de', 'au niveau de'],
    anglicisms: ['upgrade', 'process', 'workflow', 'pipeline'],
    errorFrequency: 0.7 // Probabilité base
  },

  amara: {
    name: 'Amara - Ingénieure Système',
    tendencies: ['méthodologie rigide', 'références normes', 'vocabulaire industriel'],
    repetitions: ['conforme', 'standard', 'spécifications', 'protocole'],
    syntaxErrors: ['énumérations lourdes', 'références normatives'],
    vocabularyTics: ['selon les normes', 'conformément à', 'dans le respect de'],
    anglicisms: ['compliance', 'standard', 'guidelines'],
    errorFrequency: 0.6
  },

  yasmine: {
    name: 'Yasmine - GreenTech',
    tendencies: ['éco-vocabulaire répétitif', 'superlatifs environnementaux'],
    repetitions: ['durable', 'écologique', 'responsable', 'vert', 'bio'],
    syntaxErrors: ['accumulation adjectifs éco', 'phrases militantes'],
    vocabularyTics: ['respectueux de l\'environnement', 'développement durable'],
    anglicisms: ['green', 'eco-friendly', 'sustainable'],
    errorFrequency: 0.8
  },

  fabrice: {
    name: 'Fabrice - Métallurgie',  
    tendencies: ['vocabulaire métier spécialisé', 'références techniques'],
    repetitions: ['résistant', 'robuste', 'solide', 'qualité', 'finition'],
    syntaxErrors: ['termes techniques sans explication'],
    vocabularyTics: ['en terme de résistance', 'question de solidité'],
    anglicisms: ['coating', 'finish', 'design'],
    errorFrequency: 0.5
  },

  // ========================================
  // PERSONNALITÉS CRÉATIVES
  // ========================================
  sophie: {
    name: 'Sophie - Déco Design',
    tendencies: ['vocabulaire déco répétitif', 'superlatifs esthétiques'],
    repetitions: ['magnifique', 'élégant', 'harmonieux', 'raffiné', 'style'],
    syntaxErrors: ['accord couleurs/matières', 'accumulation adjectifs'],
    vocabularyTics: ['en terme de style', 'au niveau esthétique', 'côté design'],
    anglicisms: ['design', 'style', 'trendy', 'vintage'],
    errorFrequency: 0.9
  },

  émilie: {
    name: 'Émilie - Digital Native',
    tendencies: ['anglicismes numériques', 'vocabulaire web'],
    repetitions: ['digital', 'online', 'connecté', 'smart', 'moderne'],
    syntaxErrors: ['néologismes numériques'],
    vocabularyTics: ['au niveau digital', 'côté technologique'],
    anglicisms: ['user-friendly', 'responsive', 'digital', 'smart'],
    errorFrequency: 1.0
  },

  chloé: {
    name: 'Chloé - Content Creator',
    tendencies: ['ton familier', 'expressions actuelles', 'anglicismes réseaux'],
    repetitions: ['super', 'génial', 'top', 'incontournable', 'tendance'],
    syntaxErrors: ['familiarités', 'expressions jeunes'],
    vocabularyTics: ['c\'est vraiment', 'on va dire que', 'du coup'],
    anglicisms: ['content', 'trending', 'viral', 'lifestyle'],
    errorFrequency: 1.1
  },

  minh: {
    name: 'Minh - Designer Industriel',
    tendencies: ['références design', 'vocabulaire forme/fonction'],
    repetitions: ['fonctionnel', 'ergonomique', 'esthétique', 'innovant'],
    syntaxErrors: ['descriptions techniques design'],
    vocabularyTics: ['en terme de design', 'niveau ergonomie'],
    anglicisms: ['design', 'user experience', 'ergonomic'],
    errorFrequency: 0.7
  },

  // ========================================
  // PERSONNALITÉS COMMERCIALES
  // ========================================
  laurent: {
    name: 'Laurent - Commercial BtoB',
    tendencies: ['vocabulaire vente', 'superlatifs commerciaux'],
    repetitions: ['excellent', 'exceptionnel', 'unique', 'incontournable'],
    syntaxErrors: ['promesses excessives', 'superlatifs empilés'],
    vocabularyTics: ['c\'est vraiment', 'je vous garantis', 'sans aucun doute'],
    anglicisms: ['business', 'deal', 'top niveau'],
    errorFrequency: 1.2
  },

  julie: {
    name: 'Julie - Architecture Commerciale',
    tendencies: ['vocabulaire technique commercial', 'références projets'],
    repetitions: ['projet', 'réalisation', 'conception', 'sur-mesure'],
    syntaxErrors: ['énumérations projets'],
    vocabularyTics: ['dans le cadre de', 'au niveau projet'],
    anglicisms: ['design', 'custom', 'high-end'],
    errorFrequency: 0.8
  },

  // ========================================
  // PERSONNALITÉS TERRAIN
  // ========================================
  kévin: {
    name: 'Kévin - Homme de Terrain',
    tendencies: ['expressions familières', 'vocabulaire pratique'],
    repetitions: ['pratique', 'concret', 'simple', 'direct', 'efficace'],
    syntaxErrors: ['tournures familières', 'expressions populaires'],
    vocabularyTics: ['franchement', 'concrètement', 'dans les faits'],
    anglicisms: ['basique', 'standard'],
    errorFrequency: 0.6
  },

  mamadou: {
    name: 'Mamadou - Artisan Expérimenté',
    tendencies: ['références tradition', 'vocabulaire métier'],
    repetitions: ['traditionnel', 'artisanal', 'savoir-faire', 'qualité'],
    syntaxErrors: ['expressions métier', 'références tradition'],
    vocabularyTics: ['comme on dit', 'dans le métier', 'selon l\'expérience'],
    anglicisms: [], // Évite les anglicismes
    errorFrequency: 0.4
  },

  linh: {
    name: 'Linh - Production Industrielle',
    tendencies: ['vocabulaire production', 'références process'],
    repetitions: ['production', 'fabrication', 'process', 'qualité', 'série'],
    syntaxErrors: ['termes production techniques'],
    vocabularyTics: ['au niveau production', 'côté fabrication'],
    anglicisms: ['process', 'manufacturing', 'quality'],
    errorFrequency: 0.5
  },

  // ========================================
  // PERSONNALITÉS PATRIMOINE
  // ========================================
  'pierre-henri': {
    name: 'Pierre-Henri - Patrimoine Classique',
    tendencies: ['vocabulaire soutenu', 'références historiques'],
    repetitions: ['traditionnel', 'authentique', 'noble', 'raffinement', 'héritage'],
    syntaxErrors: ['formulations recherchées', 'références culturelles'],
    vocabularyTics: ['il convient de', 'il est à noter que', 'dans la tradition'],
    anglicisms: [], // Évite complètement
    errorFrequency: 0.3
  },

  thierry: {
    name: 'Thierry - Créole Authentique',
    tendencies: ['expressions créoles', 'tournures locales'],
    repetitions: ['authentique', 'local', 'tradition', 'racines'],
    syntaxErrors: ['tournures créoles', 'expressions locales'],
    vocabularyTics: ['comme on dit chez nous', 'dans nos traditions'],
    anglicisms: [], // Privilégie le français local
    errorFrequency: 0.8
  }
};

/**
 * OBTENIR PROFIL D'ERREURS PAR PERSONNALITÉ
 * @param {string} personalityName - Nom personnalité
 * @returns {object} - Profil d'erreurs
 */
function getPersonalityErrorPatterns(personalityName) {
  const normalizedName = personalityName?.toLowerCase() || 'default';
  const profile = PERSONALITY_ERROR_PATTERNS[normalizedName];
  
  if (!profile) {
    logSh(`⚠️ Profil erreurs non trouvé pour ${personalityName}, utilisation profil générique`, 'WARNING');
    return createGenericErrorProfile();
  }
  
  logSh(`🎭 Profil erreurs sélectionné pour ${personalityName}: ${profile.name}`, 'DEBUG');
  return profile;
}

/**
 * PROFIL D'ERREURS GÉNÉRIQUE
 */
function createGenericErrorProfile() {
  return {
    name: 'Profil Générique',
    tendencies: ['répétitions standard', 'vocabulaire neutre'],
    repetitions: ['bien', 'bon', 'intéressant', 'important'],
    syntaxErrors: ['phrases standards'],
    vocabularyTics: ['en effet', 'par ailleurs', 'de plus'],
    anglicisms: [],
    errorFrequency: 0.5
  };
}

/**
 * INJECTION ERREURS PERSONNALITÉ
 * @param {string} content - Contenu à modifier
 * @param {object} personalityProfile - Profil personnalité 
 * @param {number} intensity - Intensité (0-2.0)
 * @returns {object} - { content, modifications }
 */
function injectPersonalityErrors(content, personalityProfile, intensity = 1.0) {
  if (!content || !personalityProfile) {
    return { content, modifications: 0 };
  }

  logSh(`🎭 Injection erreurs personnalité: ${personalityProfile.name}`, 'DEBUG');

  let modifiedContent = content;
  let modifications = 0;

  // Probabilité d'application basée sur l'intensité et la fréquence du profil
  const baseFrequency = personalityProfile.errorFrequency || 0.5;
  const adjustedProbability = Math.min(1.0, baseFrequency * intensity);

  logSh(`🎯 Probabilité erreurs: ${adjustedProbability.toFixed(2)} (base: ${baseFrequency}, intensité: ${intensity})`, 'DEBUG');

  // ========================================
  // 1. RÉPÉTITIONS CARACTÉRISTIQUES
  // ========================================
  const repetitionResult = injectRepetitions(modifiedContent, personalityProfile, adjustedProbability);
  modifiedContent = repetitionResult.content;
  modifications += repetitionResult.count;

  // ========================================
  // 2. TICS VOCABULAIRE
  // ========================================
  const vocabularyResult = injectVocabularyTics(modifiedContent, personalityProfile, adjustedProbability);
  modifiedContent = vocabularyResult.content;
  modifications += vocabularyResult.count;

  // ========================================  
  // 3. ANGLICISMES (SI APPLICABLE)
  // ========================================
  if (personalityProfile.anglicisms && personalityProfile.anglicisms.length > 0) {
    const anglicismResult = injectAnglicisms(modifiedContent, personalityProfile, adjustedProbability * 0.3);
    modifiedContent = anglicismResult.content;
    modifications += anglicismResult.count;
  }

  // ========================================
  // 4. ERREURS SYNTAXIQUES TYPIQUES
  // ========================================
  const syntaxResult = injectSyntaxErrors(modifiedContent, personalityProfile, adjustedProbability * 0.2);
  modifiedContent = syntaxResult.content;
  modifications += syntaxResult.count;

  logSh(`🎭 Erreurs personnalité injectées: ${modifications} modifications`, 'DEBUG');

  return {
    content: modifiedContent,
    modifications
  };
}

/**
 * INJECTION RÉPÉTITIONS CARACTÉRISTIQUES
 */
function injectRepetitions(content, profile, probability) {
  let modified = content;
  let count = 0;

  if (!profile.repetitions || profile.repetitions.length === 0) {
    return { content: modified, count };
  }

  // Sélectionner 1-3 mots répétitifs pour ce contenu - FIXÉ: Plus de mots
  const selectedWords = profile.repetitions
    .sort(() => 0.5 - Math.random())
    .slice(0, Math.random() < 0.5 ? 2 : 3); // FIXÉ: Au moins 2 mots sélectionnés

  selectedWords.forEach(word => {
    if (Math.random() < probability) {
      // Chercher des endroits appropriés pour injecter le mot
      const sentences = modified.split('. ');
      const targetSentenceIndex = Math.floor(Math.random() * sentences.length);
      
      if (sentences[targetSentenceIndex] && 
          sentences[targetSentenceIndex].length > 30 &&
          !sentences[targetSentenceIndex].toLowerCase().includes(word.toLowerCase())) {
        
        // Injecter le mot de façon naturelle
        const words = sentences[targetSentenceIndex].split(' ');
        const insertIndex = Math.floor(words.length * (0.3 + Math.random() * 0.4)); // 30-70% de la phrase
        
        // Adaptations contextuelles
        const adaptedWord = adaptWordToContext(word, words[insertIndex] || '');
        words.splice(insertIndex, 0, adaptedWord);
        
        sentences[targetSentenceIndex] = words.join(' ');
        modified = sentences.join('. ');
        count++;
        
        logSh(`   📝 Répétition injectée: "${adaptedWord}" dans phrase ${targetSentenceIndex + 1}`, 'DEBUG');
      }
    }
  });

  return { content: modified, count };
}

/**
 * INJECTION TICS VOCABULAIRE
 */
function injectVocabularyTics(content, profile, probability) {
  let modified = content;
  let count = 0;

  if (!profile.vocabularyTics || profile.vocabularyTics.length === 0) {
    return { content: modified, count };
  }

  const selectedTics = profile.vocabularyTics.slice(0, 1); // Un seul tic par contenu

  selectedTics.forEach(tic => {
    if (Math.random() < probability * 0.8) { // Probabilité réduite pour les tics
      // Remplacer des connecteurs standards par le tic
      const standardConnectors = ['par ailleurs', 'de plus', 'également', 'aussi'];
      
      standardConnectors.forEach(connector => {
        const regex = new RegExp(`\\b${connector}\\b`, 'gi');
        if (modified.match(regex) && Math.random() < 0.4) {
          modified = modified.replace(regex, tic);
          count++;
          logSh(`   🗣️ Tic vocabulaire: "${connector}" → "${tic}"`, 'DEBUG');
        }
      });
    }
  });

  return { content: modified, count };
}

/**
 * INJECTION ANGLICISMES
 */
function injectAnglicisms(content, profile, probability) {
  let modified = content;
  let count = 0;

  if (!profile.anglicisms || profile.anglicisms.length === 0) {
    return { content: modified, count };
  }

  // Remplacements français → anglais
  const replacements = {
    'processus': 'process',
    'conception': 'design', 
    'flux de travail': 'workflow',
    'mise à jour': 'upgrade',
    'contenu': 'content',
    'tendance': 'trending',
    'intelligent': 'smart',
    'numérique': 'digital'
  };

  Object.entries(replacements).forEach(([french, english]) => {
    if (profile.anglicisms.includes(english) && Math.random() < probability) {
      const regex = new RegExp(`\\b${french}\\b`, 'gi');
      if (modified.match(regex)) {
        modified = modified.replace(regex, english);
        count++;
        logSh(`   🇬🇧 Anglicisme: "${french}" → "${english}"`, 'DEBUG');
      }
    }
  });

  return { content: modified, count };
}

/**
 * INJECTION ERREURS SYNTAXIQUES
 */
function injectSyntaxErrors(content, profile, probability) {
  let modified = content;
  let count = 0;

  if (Math.random() > probability) {
    return { content: modified, count };
  }

  // Erreurs syntaxiques légères selon la personnalité
  if (profile.name.includes('Marc') || profile.name.includes('Technique')) {
    // Parenthèses techniques excessives
    if (Math.random() < 0.3) {
      modified = modified.replace(/(\w+)/, '$1 (système)');
      count++;
      logSh(`   🔧 Erreur technique: parenthèses ajoutées`, 'DEBUG');
    }
  }

  if (profile.name.includes('Sophie') || profile.name.includes('Déco')) {
    // Accumulation d'adjectifs
    if (Math.random() < 0.3) {
      modified = modified.replace(/élégant/gi, 'élégant et raffiné');
      count++;
      logSh(`   🎨 Erreur déco: adjectifs accumulés`, 'DEBUG');
    }
  }

  if (profile.name.includes('Laurent') || profile.name.includes('Commercial')) {
    // Superlatifs empilés
    if (Math.random() < 0.3) {
      modified = modified.replace(/excellent/gi, 'vraiment excellent');
      count++;
      logSh(`   💼 Erreur commerciale: superlatifs empilés`, 'DEBUG');
    }
  }

  return { content: modified, count };
}

/**
 * ADAPTATION CONTEXTUELLE DES MOTS
 */
function adaptWordToContext(word, contextWord) {
  // Accords basiques
  const contextLower = contextWord.toLowerCase();
  
  // Accords féminins simples
  if (contextLower.includes('la ') || contextLower.endsWith('e')) {
    if (word === 'bon') return 'bonne';
    if (word === 'précis') return 'précise';
  }
  
  return word;
}

// ============= EXPORTS =============
module.exports = {
  getPersonalityErrorPatterns,
  injectPersonalityErrors,
  injectRepetitions,
  injectVocabularyTics,
  injectAnglicisms,
  injectSyntaxErrors,
  createGenericErrorProfile,
  adaptWordToContext,
  PERSONALITY_ERROR_PATTERNS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/TemporalStyles.js                      │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: TemporalStyles.js
// RESPONSABILITÉ: Variations temporelles d'écriture
// Simulation comportement humain selon l'heure
// ========================================

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

/**
 * STYLES TEMPORELS PAR TRANCHES HORAIRES
 * Simule l'énergie et style d'écriture selon l'heure
 */
const TEMPORAL_STYLES = {
  
  // ========================================
  // MATIN (6h-11h) - Énergique et Direct
  // ========================================
  morning: {
    period: 'matin',
    timeRange: [6, 11],
    energy: 'high',
    characteristics: {
      sentenceLength: 'short',        // Phrases plus courtes
      vocabulary: 'dynamic',          // Mots énergiques
      connectors: 'direct',           // Connecteurs simples
      rhythm: 'fast'                  // Rythme soutenu
    },
    vocabularyPreferences: {
      energy: ['dynamique', 'efficace', 'rapide', 'direct', 'actif', 'performant'],
      connectors: ['donc', 'puis', 'ensuite', 'maintenant', 'immédiatement'],
      modifiers: ['très', 'vraiment', 'particulièrement', 'nettement'],
      actions: ['optimiser', 'accélérer', 'améliorer', 'développer', 'créer']
    },
    styleTendencies: {
      shortSentencesBias: 0.7,        // 70% chance phrases courtes
      directConnectorsBias: 0.8,      // 80% connecteurs simples
      energyWordsBias: 0.6           // 60% mots énergiques
    }
  },

  // ========================================
  // APRÈS-MIDI (12h-17h) - Équilibré et Professionnel
  // ========================================
  afternoon: {
    period: 'après-midi',
    timeRange: [12, 17],
    energy: 'medium',
    characteristics: {
      sentenceLength: 'medium',       // Phrases équilibrées
      vocabulary: 'professional',     // Vocabulaire standard
      connectors: 'balanced',         // Connecteurs variés
      rhythm: 'steady'                // Rythme régulier
    },
    vocabularyPreferences: {
      energy: ['professionnel', 'efficace', 'qualité', 'standard', 'adapté'],
      connectors: ['par ailleurs', 'de plus', 'également', 'ainsi', 'cependant'],
      modifiers: ['assez', 'plutôt', 'relativement', 'suffisamment'],
      actions: ['réaliser', 'développer', 'analyser', 'étudier', 'concevoir']
    },
    styleTendencies: {
      shortSentencesBias: 0.4,        // 40% phrases courtes
      directConnectorsBias: 0.5,      // 50% connecteurs simples
      energyWordsBias: 0.3           // 30% mots énergiques
    }
  },

  // ========================================
  // SOIR (18h-23h) - Détendu et Réflexif
  // ========================================
  evening: {
    period: 'soir',
    timeRange: [18, 23],
    energy: 'low',
    characteristics: {
      sentenceLength: 'long',         // Phrases plus longues
      vocabulary: 'nuanced',          // Vocabulaire nuancé
      connectors: 'complex',          // Connecteurs élaborés
      rhythm: 'relaxed'               // Rythme posé
    },
    vocabularyPreferences: {
      energy: ['approfondi', 'réfléchi', 'considéré', 'nuancé', 'détaillé'],
      connectors: ['néanmoins', 'cependant', 'par conséquent', 'en outre', 'toutefois'],
      modifiers: ['quelque peu', 'relativement', 'dans une certaine mesure', 'assez'],
      actions: ['examiner', 'considérer', 'réfléchir', 'approfondir', 'explorer']
    },
    styleTendencies: {
      shortSentencesBias: 0.2,        // 20% phrases courtes
      directConnectorsBias: 0.2,      // 20% connecteurs simples
      energyWordsBias: 0.1           // 10% mots énergiques
    }
  },

  // ========================================
  // NUIT (0h-5h) - Fatigue et Simplicité
  // ========================================
  night: {
    period: 'nuit',
    timeRange: [0, 5],
    energy: 'very_low',
    characteristics: {
      sentenceLength: 'short',        // Phrases courtes par fatigue
      vocabulary: 'simple',           // Vocabulaire basique
      connectors: 'minimal',          // Connecteurs rares
      rhythm: 'slow'                  // Rythme lent
    },
    vocabularyPreferences: {
      energy: ['simple', 'basique', 'standard', 'normal', 'classique'],
      connectors: ['et', 'mais', 'ou', 'donc', 'puis'],
      modifiers: ['assez', 'bien', 'pas mal', 'correct'],
      actions: ['faire', 'utiliser', 'prendre', 'mettre', 'avoir']
    },
    styleTendencies: {
      shortSentencesBias: 0.8,        // 80% phrases courtes
      directConnectorsBias: 0.9,      // 90% connecteurs simples
      energyWordsBias: 0.1           // 10% mots énergiques
    }
  }
};

/**
 * DÉTERMINER STYLE TEMPOREL SELON L'HEURE
 * @param {number} currentHour - Heure actuelle (0-23)
 * @returns {object} - Style temporel correspondant
 */
function getTemporalStyle(currentHour) {
  // Validation heure
  const hour = Math.max(0, Math.min(23, Math.floor(currentHour || new Date().getHours())));
  
  logSh(`⏰ Détermination style temporel pour ${hour}h`, 'DEBUG');

  // Déterminer période
  let selectedStyle;
  
  if (hour >= 6 && hour <= 11) {
    selectedStyle = TEMPORAL_STYLES.morning;
  } else if (hour >= 12 && hour <= 17) {
    selectedStyle = TEMPORAL_STYLES.afternoon;
  } else if (hour >= 18 && hour <= 23) {
    selectedStyle = TEMPORAL_STYLES.evening;
  } else {
    selectedStyle = TEMPORAL_STYLES.night;
  }

  logSh(`⏰ Style temporel sélectionné: ${selectedStyle.period} (énergie: ${selectedStyle.energy})`, 'DEBUG');

  return {
    ...selectedStyle,
    currentHour: hour,
    timestamp: new Date().toISOString()
  };
}

/**
 * APPLICATION STYLE TEMPOREL
 * @param {string} content - Contenu à modifier
 * @param {object} temporalStyle - Style temporel à appliquer
 * @param {object} options - Options { intensity }
 * @returns {object} - { content, modifications }
 */
function applyTemporalStyle(content, temporalStyle, options = {}) {
  if (!content || !temporalStyle) {
    return { content, modifications: 0 };
  }

  const intensity = options.intensity || 1.0;
  
  logSh(`⏰ Application style temporel: ${temporalStyle.period} (intensité: ${intensity})`, 'DEBUG');

  let modifiedContent = content;
  let modifications = 0;

  // ========================================
  // 1. AJUSTEMENT LONGUEUR PHRASES
  // ========================================
  const sentenceResult = adjustSentenceLength(modifiedContent, temporalStyle, intensity);
  modifiedContent = sentenceResult.content;
  modifications += sentenceResult.count;

  // ========================================
  // 2. ADAPTATION VOCABULAIRE
  // ========================================
  const vocabularyResult = adaptVocabulary(modifiedContent, temporalStyle, intensity);
  modifiedContent = vocabularyResult.content;
  modifications += vocabularyResult.count;

  // ========================================
  // 3. MODIFICATION CONNECTEURS
  // ========================================
  const connectorResult = adjustConnectors(modifiedContent, temporalStyle, intensity);
  modifiedContent = connectorResult.content;
  modifications += connectorResult.count;

  // ========================================
  // 4. AJUSTEMENT RYTHME
  // ========================================
  const rhythmResult = adjustRhythm(modifiedContent, temporalStyle, intensity);
  modifiedContent = rhythmResult.content;
  modifications += rhythmResult.count;

  logSh(`⏰ Style temporel appliqué: ${modifications} modifications`, 'DEBUG');

  return {
    content: modifiedContent,
    modifications
  };
}

/**
 * AJUSTEMENT LONGUEUR PHRASES
 */
function adjustSentenceLength(content, temporalStyle, intensity) {
  let modified = content;
  let count = 0;

  const bias = temporalStyle.styleTendencies.shortSentencesBias * intensity;
  const sentences = modified.split('. ');

  // Probabilité d'appliquer les modifications
  if (Math.random() > intensity * 0.9) { // FIXÉ: Presque toujours appliquer (était 0.7)
    return { content: modified, count };
  }

  const processedSentences = sentences.map(sentence => {
    if (sentence.length < 20) return sentence; // Ignorer phrases très courtes
    
    // Style MATIN/NUIT - Raccourcir phrases longues
    if ((temporalStyle.period === 'matin' || temporalStyle.period === 'nuit') && 
        sentence.length > 100 && Math.random() < bias) {
      
      // Chercher point de coupe naturel
      const cutPoints = [', qui', ', que', ', dont', ' et ', ' car ', ' mais '];
      for (const cutPoint of cutPoints) {
        const cutIndex = sentence.indexOf(cutPoint);
        if (cutIndex > 30 && cutIndex < sentence.length - 30) {
          count++;
          logSh(`   ✂️ Phrase raccourcie (${temporalStyle.period}): ${sentence.length} → ${cutIndex} chars`, 'DEBUG');
          return sentence.substring(0, cutIndex) + '. ' + 
                 sentence.substring(cutIndex + cutPoint.length);
        }
      }
    }
    
    // Style SOIR - Allonger phrases courtes
    if (temporalStyle.period === 'soir' && 
        sentence.length > 30 && sentence.length < 80 && 
        Math.random() < (1 - bias)) {
      
      // Ajouter développements
      const developments = [
        ', ce qui constitue un avantage notable',
        ', permettant ainsi d\'optimiser les résultats',
        ', dans une démarche d\'amélioration continue',
        ', contribuant à l\'efficacité globale'
      ];
      
      const development = developments[Math.floor(Math.random() * developments.length)];
      count++;
      logSh(`   📝 Phrase allongée (soir): ${sentence.length} → ${sentence.length + development.length} chars`, 'DEBUG');
      return sentence + development;
    }

    return sentence;
  });

  modified = processedSentences.join('. ');
  return { content: modified, count };
}

/**
 * ADAPTATION VOCABULAIRE
 */
function adaptVocabulary(content, temporalStyle, intensity) {
  let modified = content;
  let count = 0;

  const vocabularyPrefs = temporalStyle.vocabularyPreferences;
  const energyBias = temporalStyle.styleTendencies.energyWordsBias * intensity;

  // Probabilité d'appliquer
  if (Math.random() > intensity * 0.9) { // FIXÉ: Presque toujours appliquer (était 0.6)
    return { content: modified, count };
  }

  // Remplacements selon période
  const replacements = buildVocabularyReplacements(temporalStyle.period, vocabularyPrefs);

  replacements.forEach(replacement => {
    if (Math.random() < Math.max(0.6, energyBias)) { // FIXÉ: Minimum 60% chance
      const regex = new RegExp(`\\b${replacement.from}\\b`, 'gi');
      if (modified.match(regex)) {
        modified = modified.replace(regex, replacement.to);
        count++;
        logSh(`   📚 Vocabulaire adapté (${temporalStyle.period}): "${replacement.from}" → "${replacement.to}"`, 'DEBUG');
      }
    }
  });
  
  // AJOUT FIX: Si aucun remplacement, forcer au moins une modification temporelle basique
  if (count === 0 && Math.random() < 0.5) {
    // Modification basique selon période
    if (temporalStyle.period === 'matin' && modified.includes('utiliser')) {
      modified = modified.replace(/\butiliser\b/gi, 'optimiser');
      count++;
      logSh(`   📚 Modification temporelle forcée: utiliser → optimiser`, 'DEBUG');
    }
  }

  return { content: modified, count };
}

/**
 * CONSTRUCTION REMPLACEMENTS VOCABULAIRE
 */
function buildVocabularyReplacements(period, vocabPrefs) {
  const replacements = [];

  switch (period) {
    case 'matin':
      replacements.push(
        { from: 'bon', to: 'excellent' },
        { from: 'intéressant', to: 'dynamique' },
        { from: 'utiliser', to: 'optimiser' },
        { from: 'faire', to: 'créer' }
      );
      break;

    case 'soir':
      replacements.push(
        { from: 'bon', to: 'considérable' },
        { from: 'faire', to: 'examiner' },
        { from: 'utiliser', to: 'exploiter' },
        { from: 'voir', to: 'considérer' }
      );
      break;

    case 'nuit':
      replacements.push(
        { from: 'excellent', to: 'bien' },
        { from: 'optimiser', to: 'utiliser' },
        { from: 'considérable', to: 'correct' },
        { from: 'examiner', to: 'regarder' }
      );
      break;

    default: // après-midi
      // Vocabulaire équilibré - pas de remplacements drastiques
      break;
  }

  return replacements;
}

/**
 * AJUSTEMENT CONNECTEURS
 */
function adjustConnectors(content, temporalStyle, intensity) {
  let modified = content;
  let count = 0;

  const connectorBias = temporalStyle.styleTendencies.directConnectorsBias * intensity;
  const preferredConnectors = temporalStyle.vocabularyPreferences.connectors;

  if (Math.random() > intensity * 0.5) {
    return { content: modified, count };
  }

  // Connecteurs selon période
  const connectorMappings = {
    matin: [
      { from: /par conséquent/gi, to: 'donc' },
      { from: /néanmoins/gi, to: 'mais' },
      { from: /en outre/gi, to: 'aussi' }
    ],
    soir: [
      { from: /donc/gi, to: 'par conséquent' },
      { from: /mais/gi, to: 'néanmoins' },
      { from: /aussi/gi, to: 'en outre' }
    ],
    nuit: [
      { from: /par conséquent/gi, to: 'donc' },
      { from: /néanmoins/gi, to: 'mais' },
      { from: /cependant/gi, to: 'mais' }
    ]
  };

  const mappings = connectorMappings[temporalStyle.period] || [];

  mappings.forEach(mapping => {
    if (Math.random() < connectorBias) {
      if (modified.match(mapping.from)) {
        modified = modified.replace(mapping.from, mapping.to);
        count++;
        logSh(`   🔗 Connecteur adapté (${temporalStyle.period}): "${mapping.from}" → "${mapping.to}"`, 'DEBUG');
      }
    }
  });

  return { content: modified, count };
}

/**
 * AJUSTEMENT RYTHME
 */
function adjustRhythm(content, temporalStyle, intensity) {
  let modified = content;
  let count = 0;

  // Le rythme affecte la ponctuation et les pauses
  if (Math.random() > intensity * 0.3) {
    return { content: modified, count };
  }

  switch (temporalStyle.characteristics.rhythm) {
    case 'fast': // Matin - moins de virgules, plus direct
      if (Math.random() < 0.4) {
        // Supprimer quelques virgules non essentielles
        const originalCommas = (modified.match(/,/g) || []).length;
        modified = modified.replace(/, qui /gi, ' qui ');
        modified = modified.replace(/, que /gi, ' que ');
        const newCommas = (modified.match(/,/g) || []).length;
        count = originalCommas - newCommas;
        if (count > 0) {
          logSh(`   ⚡ Rythme accéléré: ${count} virgules supprimées`, 'DEBUG');
        }
      }
      break;

    case 'relaxed': // Soir - plus de pauses
      if (Math.random() < 0.3) {
        // Ajouter quelques pauses réflexives
        modified = modified.replace(/\. ([A-Z])/g, '. Ainsi, $1');
        count++;
        logSh(`   🧘 Rythme ralenti: pauses ajoutées`, 'DEBUG');
      }
      break;

    case 'slow': // Nuit - simplification
      if (Math.random() < 0.5) {
        // Simplifier structures complexes
        modified = modified.replace(/ ; /g, '. ');
        count++;
        logSh(`   😴 Rythme simplifié: structures allégées`, 'DEBUG');
      }
      break;
  }

  return { content: modified, count };
}

/**
 * ANALYSE COHÉRENCE TEMPORELLE
 * @param {string} content - Contenu à analyser
 * @param {object} temporalStyle - Style appliqué
 * @returns {object} - Métriques de cohérence
 */
function analyzeTemporalCoherence(content, temporalStyle) {
  const sentences = content.split('. ');
  const avgSentenceLength = sentences.reduce((sum, s) => sum + s.length, 0) / sentences.length;
  
  const energyWords = temporalStyle.vocabularyPreferences.energy;
  const energyWordCount = energyWords.reduce((count, word) => {
    const regex = new RegExp(`\\b${word}\\b`, 'gi');
    return count + (content.match(regex) || []).length;
  }, 0);

  return {
    avgSentenceLength,
    energyWordDensity: energyWordCount / sentences.length,
    period: temporalStyle.period,
    coherenceScore: calculateCoherenceScore(avgSentenceLength, temporalStyle),
    expectedCharacteristics: temporalStyle.characteristics
  };
}

/**
 * CALCUL SCORE COHÉRENCE
 */
function calculateCoherenceScore(avgLength, temporalStyle) {
  let score = 1.0;

  // Vérifier cohérence longueur phrases avec période
  const expectedLength = {
    'matin': { min: 40, max: 80 },
    'après-midi': { min: 60, max: 120 },
    'soir': { min: 80, max: 150 },
    'nuit': { min: 30, max: 70 }
  };

  const expected = expectedLength[temporalStyle.period];
  if (expected) {
    if (avgLength < expected.min || avgLength > expected.max) {
      score *= 0.7;
    }
  }

  return Math.max(0, Math.min(1, score));
}

// ============= EXPORTS =============
module.exports = {
  getTemporalStyle,
  applyTemporalStyle,
  adjustSentenceLength,
  adaptVocabulary,
  adjustConnectors,
  adjustRhythm,
  analyzeTemporalCoherence,
  calculateCoherenceScore,
  buildVocabularyReplacements,
  TEMPORAL_STYLES
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/HumanSimulationUtils.js                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: HumanSimulationUtils.js
// RESPONSABILITÉ: Utilitaires partagés Human Simulation
// Fonctions d'analyse, validation et helpers
// ========================================

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

/**
 * SEUILS DE QUALITÉ
 */
const QUALITY_THRESHOLDS = {
  readability: {
    minimum: 0.3,    // FIXÉ: Plus permissif (était 0.6)
    good: 0.6,
    excellent: 0.8
  },
  keywordPreservation: {
    minimum: 0.7,    // FIXÉ: Plus permissif (était 0.8)
    good: 0.9,
    excellent: 0.95
  },
  similarity: {
    minimum: 0.5,    // FIXÉ: Plus permissif (était 0.7)
    maximum: 1.0     // FIXÉ: Accepter même contenu identique (était 0.95)
  }
};

/**
 * MOTS-CLÉS À PRÉSERVER ABSOLUMENT
 */
const CRITICAL_KEYWORDS = [
  // Mots-clés SEO génériques
  'plaque', 'personnalisée', 'gravure', 'métal', 'bois', 'acrylique',
  'design', 'qualité', 'fabrication', 'artisanal', 'sur-mesure',
  // Termes techniques importants
  'laser', 'CNC', 'impression', 'découpe', 'finition', 'traitement',
  // Termes commerciaux
  'prix', 'tarif', 'devis', 'livraison', 'garantie', 'service'
];

/**
 * ANALYSE COMPLEXITÉ CONTENU
 * @param {object} content - Contenu à analyser
 * @returns {object} - Métriques de complexité
 */
function analyzeContentComplexity(content) {
  logSh('🔍 Analyse complexité contenu', 'DEBUG');

  const contentArray = Object.values(content).filter(c => typeof c === 'string');
  const totalText = contentArray.join(' ');
  
  // Métriques de base
  const totalWords = totalText.split(/\s+/).length;
  const totalSentences = totalText.split(/[.!?]+/).length;
  const totalParagraphs = contentArray.length;
  
  // Complexité lexicale
  const uniqueWords = new Set(totalText.toLowerCase().split(/\s+/)).size;
  const lexicalDiversity = uniqueWords / totalWords;
  
  // Longueur moyenne des phrases
  const avgSentenceLength = totalWords / totalSentences;
  
  // Complexité syntaxique (approximative)
  const complexConnectors = (totalText.match(/néanmoins|cependant|par conséquent|en outre|toutefois/gi) || []).length;
  const syntacticComplexity = complexConnectors / totalSentences;
  
  // Score global de complexité
  const complexityScore = (
    (lexicalDiversity * 0.4) +
    (Math.min(avgSentenceLength / 100, 1) * 0.3) +
    (syntacticComplexity * 0.3)
  );

  const complexity = {
    totalWords,
    totalSentences,
    totalParagraphs,
    avgSentenceLength,
    lexicalDiversity,
    syntacticComplexity,
    complexityScore,
    level: complexityScore > 0.7 ? 'high' : complexityScore > 0.4 ? 'medium' : 'low'
  };

  logSh(`   📊 Complexité: ${complexity.level} (score: ${complexityScore.toFixed(2)})`, 'DEBUG');
  logSh(`   📝 ${totalWords} mots, ${totalSentences} phrases, diversité: ${lexicalDiversity.toFixed(2)}`, 'DEBUG');

  return complexity;
}

/**
 * CALCUL SCORE LISIBILITÉ
 * Approximation de l'index Flesch-Kincaid adapté au français
 * @param {string} text - Texte à analyser
 * @returns {number} - Score lisibilité (0-1)
 */
function calculateReadabilityScore(text) {
  if (!text || text.trim().length === 0) {
    return 0;
  }

  // Nettoyage du texte
  const cleanText = text.replace(/[^\w\s.!?]/gi, '');
  
  // Comptages de base
  const sentences = cleanText.split(/[.!?]+/).filter(s => s.trim().length > 0);
  const words = cleanText.split(/\s+/).filter(w => w.length > 0);
  const syllables = countSyllables(cleanText);

  if (sentences.length === 0 || words.length === 0) {
    return 0;
  }

  // Métriques Flesch-Kincaid adaptées français
  const avgWordsPerSentence = words.length / sentences.length;
  const avgSyllablesPerWord = syllables / words.length;
  
  // Formule adaptée (plus clémente que l'originale)
  const fleschScore = 206.835 - (1.015 * avgWordsPerSentence) - (84.6 * avgSyllablesPerWord);
  
  // Normalisation 0-1 (100 = parfait en Flesch)
  const normalizedScore = Math.max(0, Math.min(1, fleschScore / 100));
  
  logSh(`   📖 Lisibilité: ${normalizedScore.toFixed(2)} (mots/phrase: ${avgWordsPerSentence.toFixed(1)}, syll/mot: ${avgSyllablesPerWord.toFixed(1)})`, 'DEBUG');

  return normalizedScore;
}

/**
 * COMPTAGE SYLLABES (APPROXIMATIF FRANÇAIS)
 */
function countSyllables(text) {
  // Approximation pour le français
  const vowels = /[aeiouyàáâäèéêëìíîïòóôöùúûü]/gi;
  const vowelGroups = text.match(vowels) || [];
  
  // Approximation: 1 groupe de voyelles ≈ 1 syllabe
  // Ajustements pour le français
  let syllables = vowelGroups.length;
  
  // Corrections courantes
  const corrections = [
    { pattern: /ion/gi, adjustment: 0 },      // "tion" = 1 syllabe, pas 2
    { pattern: /ieu/gi, adjustment: -1 },     // "ieux" = 1 syllabe
    { pattern: /eau/gi, adjustment: -1 },     // "eau" = 1 syllabe
    { pattern: /ai/gi, adjustment: -1 },      // "ai" = 1 syllabe
    { pattern: /ou/gi, adjustment: -1 },      // "ou" = 1 syllabe
    { pattern: /e$/gi, adjustment: -0.5 }     // "e" final muet
  ];

  corrections.forEach(correction => {
    const matches = text.match(correction.pattern) || [];
    syllables += matches.length * correction.adjustment;
  });

  return Math.max(1, Math.round(syllables));
}

/**
 * PRÉSERVATION MOTS-CLÉS
 * @param {string} originalText - Texte original
 * @param {string} modifiedText - Texte modifié
 * @returns {number} - Score préservation (0-1)
 */
function preserveKeywords(originalText, modifiedText) {
  if (!originalText || !modifiedText) {
    return 0;
  }

  const originalLower = originalText.toLowerCase();
  const modifiedLower = modifiedText.toLowerCase();

  // Extraire mots-clés du texte original
  const originalKeywords = extractKeywords(originalLower);
  
  // Vérifier préservation
  let preservedCount = 0;
  let criticalPreservedCount = 0;
  let criticalTotalCount = 0;

  originalKeywords.forEach(keyword => {
    const isCritical = CRITICAL_KEYWORDS.some(ck => 
      keyword.toLowerCase().includes(ck.toLowerCase()) || 
      ck.toLowerCase().includes(keyword.toLowerCase())
    );
    
    if (isCritical) {
      criticalTotalCount++;
    }

    // Vérifier présence dans texte modifié
    const keywordRegex = new RegExp(`\\b${keyword}\\b`, 'gi');
    if (modifiedLower.match(keywordRegex)) {
      preservedCount++;
      if (isCritical) {
        criticalPreservedCount++;
      }
    }
  });

  // Score avec bonus pour mots-clés critiques
  const basicPreservation = preservedCount / Math.max(1, originalKeywords.length);
  const criticalPreservation = criticalTotalCount > 0 ? 
    criticalPreservedCount / criticalTotalCount : 1.0;

  const finalScore = (basicPreservation * 0.6) + (criticalPreservation * 0.4);

  logSh(`   🔑 Mots-clés: ${preservedCount}/${originalKeywords.length} préservés (${criticalPreservedCount}/${criticalTotalCount} critiques)`, 'DEBUG');
  logSh(`   🎯 Score préservation: ${finalScore.toFixed(2)}`, 'DEBUG');

  return finalScore;
}

/**
 * EXTRACTION MOTS-CLÉS SIMPLES
 */
function extractKeywords(text) {
  // Mots de plus de 3 caractères, non vides
  const words = text.match(/\b\w{4,}\b/g) || [];
  
  // Filtrer mots courants français
  const stopWords = [
    'avec', 'dans', 'pour', 'cette', 'sont', 'tout', 'mais', 'plus', 'très',
    'bien', 'encore', 'aussi', 'comme', 'après', 'avant', 'entre', 'depuis'
  ];

  const keywords = words
    .filter(word => !stopWords.includes(word.toLowerCase()))
    .filter((word, index, array) => array.indexOf(word) === index) // Unique
    .slice(0, 20); // Limiter à 20 mots-clés

  return keywords;
}

/**
 * VALIDATION QUALITÉ SIMULATION
 * @param {string} originalContent - Contenu original
 * @param {string} simulatedContent - Contenu simulé
 * @param {number} qualityThreshold - Seuil qualité minimum
 * @returns {object} - Résultat validation
 */
function validateSimulationQuality(originalContent, simulatedContent, qualityThreshold = 0.7) {
  if (!originalContent || !simulatedContent) {
    return { acceptable: false, reason: 'Contenu manquant' };
  }

  logSh('🎯 Validation qualité simulation', 'DEBUG');

  // Métriques de qualité
  const readabilityScore = calculateReadabilityScore(simulatedContent);
  const keywordScore = preserveKeywords(originalContent, simulatedContent);
  const similarityScore = calculateSimilarity(originalContent, simulatedContent);

  // Score global pondéré
  const globalScore = (
    readabilityScore * 0.4 +
    keywordScore * 0.4 +
    (similarityScore > QUALITY_THRESHOLDS.similarity.minimum && 
     similarityScore < QUALITY_THRESHOLDS.similarity.maximum ? 0.2 : 0)
  );

  const acceptable = globalScore >= qualityThreshold;
  
  const validation = {
    acceptable,
    globalScore,
    readabilityScore,
    keywordScore,
    similarityScore,
    reason: acceptable ? 'Qualité acceptable' : determineQualityIssue(readabilityScore, keywordScore, similarityScore),
    details: {
      readabilityOk: readabilityScore >= QUALITY_THRESHOLDS.readability.minimum,
      keywordsOk: keywordScore >= QUALITY_THRESHOLDS.keywordPreservation.minimum,
      similarityOk: similarityScore >= QUALITY_THRESHOLDS.similarity.minimum && 
                    similarityScore <= QUALITY_THRESHOLDS.similarity.maximum
    }
  };

  logSh(`   🎯 Validation: ${acceptable ? 'ACCEPTÉ' : 'REJETÉ'} (score: ${globalScore.toFixed(2)})`, acceptable ? 'INFO' : 'WARNING');
  logSh(`   📊 Lisibilité: ${readabilityScore.toFixed(2)} | Mots-clés: ${keywordScore.toFixed(2)} | Similarité: ${similarityScore.toFixed(2)}`, 'DEBUG');

  return validation;
}

/**
 * CALCUL SIMILARITÉ APPROXIMATIVE
 */
function calculateSimilarity(text1, text2) {
  // Similarité basée sur les mots partagés (simple mais efficace)
  const words1 = new Set(text1.toLowerCase().split(/\s+/));
  const words2 = new Set(text2.toLowerCase().split(/\s+/));
  
  const intersection = new Set([...words1].filter(word => words2.has(word)));
  const union = new Set([...words1, ...words2]);
  
  return intersection.size / union.size;
}

/**
 * DÉTERMINER PROBLÈME QUALITÉ
 */
function determineQualityIssue(readabilityScore, keywordScore, similarityScore) {
  if (readabilityScore < QUALITY_THRESHOLDS.readability.minimum) {
    return 'Lisibilité insuffisante';
  }
  if (keywordScore < QUALITY_THRESHOLDS.keywordPreservation.minimum) {
    return 'Mots-clés mal préservés';
  }
  if (similarityScore < QUALITY_THRESHOLDS.similarity.minimum) {
    return 'Trop différent de l\'original';
  }
  if (similarityScore > QUALITY_THRESHOLDS.similarity.maximum) {
    return 'Pas assez modifié';
  }
  return 'Score global insuffisant';
}

/**
 * GÉNÉRATION RAPPORT QUALITÉ DÉTAILLÉ
 * @param {object} content - Contenu à analyser
 * @param {object} simulationStats - Stats simulation
 * @returns {object} - Rapport détaillé
 */
function generateQualityReport(content, simulationStats) {
  const report = {
    timestamp: new Date().toISOString(),
    contentAnalysis: analyzeContentComplexity(content),
    simulationStats,
    qualityMetrics: {},
    recommendations: []
  };

  // Analyse par élément
  Object.entries(content).forEach(([key, elementContent]) => {
    if (typeof elementContent === 'string') {
      const readability = calculateReadabilityScore(elementContent);
      const complexity = analyzeContentComplexity({ [key]: elementContent });
      
      report.qualityMetrics[key] = {
        readability,
        complexity: complexity.complexityScore,
        wordCount: elementContent.split(/\s+/).length
      };
    }
  });

  // Recommandations automatiques
  if (report.contentAnalysis.complexityScore > 0.8) {
    report.recommendations.push('Simplifier le vocabulaire pour améliorer la lisibilité');
  }
  
  if (simulationStats.fatigueModifications < 1) {
    report.recommendations.push('Augmenter l\'intensité de simulation fatigue');
  }

  return report;
}

/**
 * HELPERS STATISTIQUES
 */
function calculateStatistics(values) {
  const sorted = values.slice().sort((a, b) => a - b);
  const length = values.length;
  
  return {
    mean: values.reduce((sum, val) => sum + val, 0) / length,
    median: length % 2 === 0 ? 
      (sorted[length / 2 - 1] + sorted[length / 2]) / 2 : 
      sorted[Math.floor(length / 2)],
    min: sorted[0],
    max: sorted[length - 1],
    stdDev: calculateStandardDeviation(values)
  };
}

function calculateStandardDeviation(values) {
  const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
  const squaredDifferences = values.map(val => Math.pow(val - mean, 2));
  const variance = squaredDifferences.reduce((sum, val) => sum + val, 0) / values.length;
  return Math.sqrt(variance);
}

// ============= EXPORTS =============
module.exports = {
  analyzeContentComplexity,
  calculateReadabilityScore,
  preserveKeywords,
  validateSimulationQuality,
  generateQualityReport,
  calculateStatistics,
  calculateStandardDeviation,
  countSyllables,
  extractKeywords,
  calculateSimilarity,
  determineQualityIssue,
  QUALITY_THRESHOLDS,
  CRITICAL_KEYWORDS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/HumanSimulationCore.js                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: HumanSimulationCore.js
// RESPONSABILITÉ: Orchestrateur principal Human Simulation
// Niveau 5: Temporal & Personality Injection
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { calculateFatigue, injectFatigueMarkers, getFatigueProfile } = require('./FatiguePatterns');
const { injectPersonalityErrors, getPersonalityErrorPatterns } = require('./PersonalityErrors');
const { applyTemporalStyle, getTemporalStyle } = require('./TemporalStyles');
const { 
  analyzeContentComplexity, 
  calculateReadabilityScore, 
  preserveKeywords,
  validateSimulationQuality 
} = require('./HumanSimulationUtils');

/**
 * CONFIGURATION PAR DÉFAUT
 */
const DEFAULT_CONFIG = {
  fatigueEnabled: true,
  personalityErrorsEnabled: true,
  temporalStyleEnabled: true,
  imperfectionIntensity: 0.8,       // FIXÉ: Plus d'intensité (était 0.3)
  naturalRepetitions: true,
  qualityThreshold: 0.4,            // FIXÉ: Seuil plus bas (était 0.7)
  maxModificationsPerElement: 5     // FIXÉ: Plus de modifs possibles (était 3)
};

/**
 * ORCHESTRATEUR PRINCIPAL - Human Simulation Layer
 * @param {object} content - Contenu généré à simuler
 * @param {object} options - Options de simulation
 * @returns {object} - { content, stats, fallback }
 */
async function applyHumanSimulationLayer(content, options = {}) {
  return await tracer.run('HumanSimulationCore.applyHumanSimulationLayer()', async () => {
    const startTime = Date.now();
    
    await tracer.annotate({
      contentKeys: Object.keys(content).length,
      elementIndex: options.elementIndex,
      totalElements: options.totalElements,
      currentHour: options.currentHour,
      personality: options.csvData?.personality?.nom
    });

    logSh(`🧠 HUMAN SIMULATION - Début traitement`, 'INFO');
    logSh(`   📊 ${Object.keys(content).length} éléments | Position: ${options.elementIndex}/${options.totalElements}`, 'DEBUG');

    try {
      // Configuration fusionnée
      const config = { ...DEFAULT_CONFIG, ...options };
      
      // Stats de simulation
      const simulationStats = {
        elementsProcessed: 0,
        fatigueModifications: 0,
        personalityModifications: 0,
        temporalModifications: 0,
        totalModifications: 0,
        qualityScore: 0,
        fallbackUsed: false
      };

      // Contenu simulé
      let simulatedContent = { ...content };
      
      // ========================================
      // 1. ANALYSE CONTEXTE GLOBAL
      // ========================================
      const globalContext = await analyzeGlobalContext(content, config);
      logSh(`   🔍 Contexte: fatigue=${globalContext.fatigueLevel.toFixed(2)}, heure=${globalContext.currentHour}h, personnalité=${globalContext.personalityName}`, 'DEBUG');

      // ========================================
      // 2. TRAITEMENT PAR ÉLÉMENT
      // ========================================
      for (const [elementKey, elementContent] of Object.entries(content)) {
        await tracer.run(`HumanSimulation.processElement(${elementKey})`, async () => {
          
          logSh(`   🎯 Traitement élément: ${elementKey}`, 'DEBUG');
          
          let processedContent = elementContent;
          let elementModifications = 0;

          try {
            // 2a. Simulation Fatigue Cognitive
            if (config.fatigueEnabled && globalContext.fatigueLevel > 0.1) { // FIXÉ: Seuil plus bas (était 0.3)
              const fatigueResult = await applyFatigueSimulation(processedContent, globalContext, config);
              processedContent = fatigueResult.content;
              elementModifications += fatigueResult.modifications;
              simulationStats.fatigueModifications += fatigueResult.modifications;
              
              logSh(`     💤 Fatigue: ${fatigueResult.modifications} modifications (niveau: ${globalContext.fatigueLevel.toFixed(2)})`, 'DEBUG');
            }

            // 2b. Erreurs Personnalité
            if (config.personalityErrorsEnabled && globalContext.personalityProfile) {
              const personalityResult = await applyPersonalitySimulation(processedContent, globalContext, config);
              processedContent = personalityResult.content;
              elementModifications += personalityResult.modifications;
              simulationStats.personalityModifications += personalityResult.modifications;
              
              logSh(`     🎭 Personnalité: ${personalityResult.modifications} erreurs injectées`, 'DEBUG');
            }

            // 2c. Style Temporel
            if (config.temporalStyleEnabled && globalContext.temporalStyle) {
              const temporalResult = await applyTemporalSimulation(processedContent, globalContext, config);
              processedContent = temporalResult.content;
              elementModifications += temporalResult.modifications;
              simulationStats.temporalModifications += temporalResult.modifications;
              
              logSh(`     ⏰ Temporel: ${temporalResult.modifications} ajustements (${globalContext.temporalStyle.period})`, 'DEBUG');
            }

            // 2d. Validation Qualité
            const qualityCheck = validateSimulationQuality(elementContent, processedContent, config.qualityThreshold);
            
            if (qualityCheck.acceptable) {
              simulatedContent[elementKey] = processedContent;
              simulationStats.elementsProcessed++;
              simulationStats.totalModifications += elementModifications;
              
              logSh(`     ✅ Élément simulé: ${elementModifications} modifications totales`, 'DEBUG');
            } else {
              // Fallback: garder contenu original
              simulatedContent[elementKey] = elementContent;
              simulationStats.fallbackUsed = true;
              
              logSh(`     ⚠️ Qualité insuffisante, fallback vers contenu original`, 'WARNING');
            }

          } catch (elementError) {
            logSh(`     ❌ Erreur simulation élément ${elementKey}: ${elementError.message}`, 'WARNING');
            simulatedContent[elementKey] = elementContent; // Fallback
            simulationStats.fallbackUsed = true;
          }

        }, { elementKey, originalLength: elementContent?.length });
      }

      // ========================================
      // 3. CALCUL SCORE QUALITÉ GLOBAL
      // ========================================
      simulationStats.qualityScore = calculateGlobalQualityScore(content, simulatedContent);
      
      // ========================================
      // 4. RÉSULTATS FINAUX
      // ========================================
      const duration = Date.now() - startTime;
      const success = simulationStats.elementsProcessed > 0 && !simulationStats.fallbackUsed;

      logSh(`🧠 HUMAN SIMULATION - Terminé (${duration}ms)`, 'INFO');
      logSh(`   ✅ ${simulationStats.elementsProcessed}/${Object.keys(content).length} éléments simulés`, 'INFO');
      logSh(`   📊 ${simulationStats.fatigueModifications} fatigue | ${simulationStats.personalityModifications} personnalité | ${simulationStats.temporalModifications} temporel`, 'INFO');
      logSh(`   🎯 Score qualité: ${simulationStats.qualityScore.toFixed(2)} | Fallback: ${simulationStats.fallbackUsed ? 'OUI' : 'NON'}`, 'INFO');

      await tracer.event('Human Simulation terminée', {
        success,
        duration,
        stats: simulationStats
      });

      return {
        content: simulatedContent,
        stats: simulationStats,
        fallback: simulationStats.fallbackUsed,
        qualityScore: simulationStats.qualityScore,
        duration
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ HUMAN SIMULATION ÉCHOUÉE (${duration}ms): ${error.message}`, 'ERROR');
      
      await tracer.event('Human Simulation échouée', {
        error: error.message,
        duration,
        contentKeys: Object.keys(content).length
      });

      // Fallback complet
      return {
        content,
        stats: { fallbackUsed: true, error: error.message },
        fallback: true,
        qualityScore: 0,
        duration
      };
    }

  }, { 
    contentElements: Object.keys(content).length,
    elementIndex: options.elementIndex,
    personality: options.csvData?.personality?.nom 
  });
}

/**
 * ANALYSE CONTEXTE GLOBAL
 */
async function analyzeGlobalContext(content, config) {
  const elementIndex = config.elementIndex || 0;
  const totalElements = config.totalElements || Object.keys(content).length;
  const currentHour = config.currentHour || new Date().getHours();
  const personality = config.csvData?.personality;

  return {
    fatigueLevel: calculateFatigue(elementIndex, totalElements),
    fatigueProfile: personality ? getFatigueProfile(personality.nom) : null,
    personalityName: personality?.nom || 'unknown',
    personalityProfile: personality ? getPersonalityErrorPatterns(personality.nom) : null,
    temporalStyle: getTemporalStyle(currentHour),
    currentHour,
    elementIndex,
    totalElements,
    contentComplexity: analyzeContentComplexity(content)
  };
}

/**
 * APPLICATION SIMULATION FATIGUE
 */
async function applyFatigueSimulation(content, globalContext, config) {
  const fatigueResult = injectFatigueMarkers(content, globalContext.fatigueLevel, {
    profile: globalContext.fatigueProfile,
    intensity: config.imperfectionIntensity
  });

  return {
    content: fatigueResult.content,
    modifications: fatigueResult.modifications || 0
  };
}

/**
 * APPLICATION SIMULATION PERSONNALITÉ
 */
async function applyPersonalitySimulation(content, globalContext, config) {
  const personalityResult = injectPersonalityErrors(
    content, 
    globalContext.personalityProfile, 
    config.imperfectionIntensity
  );

  return {
    content: personalityResult.content,
    modifications: personalityResult.modifications || 0
  };
}

/**
 * APPLICATION SIMULATION TEMPORELLE
 */
async function applyTemporalSimulation(content, globalContext, config) {
  const temporalResult = applyTemporalStyle(content, globalContext.temporalStyle, {
    intensity: config.imperfectionIntensity
  });

  return {
    content: temporalResult.content,
    modifications: temporalResult.modifications || 0
  };
}

/**
 * CALCUL SCORE QUALITÉ GLOBAL
 */
function calculateGlobalQualityScore(originalContent, simulatedContent) {
  let totalScore = 0;
  let elementCount = 0;

  for (const [key, original] of Object.entries(originalContent)) {
    const simulated = simulatedContent[key];
    if (simulated) {
      const elementScore = calculateReadabilityScore(simulated) * 0.7 + 
                          preserveKeywords(original, simulated) * 0.3;
      totalScore += elementScore;
      elementCount++;
    }
  }

  return elementCount > 0 ? totalScore / elementCount : 0;
}

// ============= EXPORTS =============
module.exports = {
  applyHumanSimulationLayer,
  analyzeGlobalContext,
  applyFatigueSimulation,
  applyPersonalitySimulation,
  applyTemporalSimulation,
  calculateGlobalQualityScore,
  DEFAULT_CONFIG
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pattern-breaking/SyntaxVariations.js                    │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: SyntaxVariations.js
// RESPONSABILITÉ: Variations syntaxiques pour casser patterns LLM
// Techniques: découpage, fusion, restructuration phrases
// ========================================

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

/**
 * PATTERNS SYNTAXIQUES TYPIQUES LLM À ÉVITER
 */
const LLM_SYNTAX_PATTERNS = {
  // Structures trop prévisibles
  repetitiveStarts: [
    /^Il est important de/gi,
    /^Il convient de/gi,
    /^Il faut noter que/gi,
    /^Dans ce contexte/gi,
    /^Par ailleurs/gi
  ],
  
  // Phrases trop parfaites
  perfectStructures: [
    /^De plus, .+ En outre, .+ Enfin,/gi,
    /^Premièrement, .+ Deuxièmement, .+ Troisièmement,/gi
  ],
  
  // Longueurs trop régulières (détection pattern)
  uniformLengths: true // Détecté dynamiquement
};

/**
 * VARIATION STRUCTURES SYNTAXIQUES - FONCTION PRINCIPALE
 * @param {string} text - Texte à varier
 * @param {number} intensity - Intensité variation (0-1)
 * @param {object} options - Options { preserveReadability, maxModifications }
 * @returns {object} - { content, modifications, stats }
 */
function varyStructures(text, intensity = 0.3, options = {}) {
  if (!text || text.trim().length === 0) {
    return { content: text, modifications: 0 };
  }

  const config = {
    preserveReadability: true,
    maxModifications: 3,
    ...options
  };

  logSh(`📝 Variation syntaxique: intensité ${intensity}, préservation: ${config.preserveReadability}`, 'DEBUG');

  let modifiedText = text;
  let totalModifications = 0;
  const stats = {
    sentencesSplit: 0,
    sentencesMerged: 0,
    structuresReorganized: 0,
    repetitiveStartsFixed: 0
  };

  try {
    // 1. Analyser structure phrases
    const sentences = analyzeSentenceStructure(modifiedText);
    logSh(`   📊 ${sentences.length} phrases analysées`, 'DEBUG');

    // 2. Découper phrases longues
    if (Math.random() < intensity) {
      const splitResult = splitLongSentences(modifiedText, intensity);
      modifiedText = splitResult.content;
      totalModifications += splitResult.modifications;
      stats.sentencesSplit = splitResult.modifications;
    }

    // 3. Fusionner phrases courtes
    if (Math.random() < intensity * 0.7) {
      const mergeResult = mergeShorter(modifiedText, intensity);
      modifiedText = mergeResult.content;
      totalModifications += mergeResult.modifications;
      stats.sentencesMerged = mergeResult.modifications;
    }

    // 4. Réorganiser structures prévisibles
    if (Math.random() < intensity * 0.8) {
      const reorganizeResult = reorganizeStructures(modifiedText, intensity);
      modifiedText = reorganizeResult.content;
      totalModifications += reorganizeResult.modifications;
      stats.structuresReorganized = reorganizeResult.modifications;
    }

    // 5. Corriger débuts répétitifs
    if (Math.random() < intensity * 0.6) {
      const repetitiveResult = fixRepetitiveStarts(modifiedText);
      modifiedText = repetitiveResult.content;
      totalModifications += repetitiveResult.modifications;
      stats.repetitiveStartsFixed = repetitiveResult.modifications;
    }

    // 6. Limitation sécurité
    if (totalModifications > config.maxModifications) {
      logSh(`   ⚠️ Limitation appliquée: ${totalModifications} → ${config.maxModifications} modifications`, 'DEBUG');
      totalModifications = config.maxModifications;
    }

    logSh(`📝 Syntaxe modifiée: ${totalModifications} changements (${stats.sentencesSplit} splits, ${stats.sentencesMerged} merges)`, 'DEBUG');

  } catch (error) {
    logSh(`❌ Erreur variation syntaxique: ${error.message}`, 'WARNING');
    return { content: text, modifications: 0, stats: {} };
  }

  return {
    content: modifiedText,
    modifications: totalModifications,
    stats
  };
}

/**
 * ANALYSE STRUCTURE PHRASES
 */
function analyzeSentenceStructure(text) {
  const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
  
  return sentences.map((sentence, index) => ({
    index,
    content: sentence.trim(),
    length: sentence.trim().length,
    wordCount: sentence.trim().split(/\s+/).length,
    isLong: sentence.trim().length > 120,
    isShort: sentence.trim().length < 40,
    hasComplexStructure: sentence.includes(',') && sentence.includes(' qui ') || sentence.includes(' que ')
  }));
}

/**
 * DÉCOUPAGE PHRASES LONGUES
 */
function splitLongSentences(text, intensity) {
  let modified = text;
  let modifications = 0;

  const sentences = modified.split('. ');
  const processedSentences = sentences.map(sentence => {
    
    // Phrases longues (>100 chars) et probabilité selon intensité - PLUS AGRESSIF
    if (sentence.length > 100 && Math.random() < (intensity * 0.6)) {
      
      // Points de découpe naturels
      const cutPoints = [
        { pattern: /, qui (.+)/, replacement: '. Celui-ci $1' },
        { pattern: /, que (.+)/, replacement: '. Cela $1' },
        { pattern: /, dont (.+)/, replacement: '. Celui-ci $1' },
        { pattern: / et (.{30,})/, replacement: '. De plus, $1' },
        { pattern: /, car (.+)/, replacement: '. En effet, $1' },
        { pattern: /, mais (.+)/, replacement: '. Cependant, $1' }
      ];

      for (const cutPoint of cutPoints) {
        if (sentence.match(cutPoint.pattern)) {
          const newSentence = sentence.replace(cutPoint.pattern, cutPoint.replacement);
          if (newSentence !== sentence) {
            modifications++;
            logSh(`     ✂️ Phrase découpée: ${sentence.length} → ${newSentence.length} chars`, 'DEBUG');
            return newSentence;
          }
        }
      }
    }
    
    return sentence;
  });

  return {
    content: processedSentences.join('. '),
    modifications
  };
}

/**
 * FUSION PHRASES COURTES
 */
function mergeShorter(text, intensity) {
  let modified = text;
  let modifications = 0;

  const sentences = modified.split('. ');
  const processedSentences = [];
  
  for (let i = 0; i < sentences.length; i++) {
    const current = sentences[i];
    const next = sentences[i + 1];
    
    // Si phrase courte (<50 chars) et phrase suivante existe - PLUS AGRESSIF
    if (current && current.length < 50 && next && next.length < 70 && Math.random() < (intensity * 0.5)) {
      
      // Connecteurs pour fusion naturelle
      const connectors = [', de plus,', ', également,', ', aussi,', ' et'];
      const connector = connectors[Math.floor(Math.random() * connectors.length)];
      
      const merged = current + connector + ' ' + next.toLowerCase();
      processedSentences.push(merged);
      modifications++;
      
      logSh(`     🔗 Phrases fusionnées: ${current.length} + ${next.length} → ${merged.length} chars`, 'DEBUG');
      
      i++; // Passer la phrase suivante car fusionnée
    } else {
      processedSentences.push(current);
    }
  }

  return {
    content: processedSentences.join('. '),
    modifications
  };
}

/**
 * RÉORGANISATION STRUCTURES PRÉVISIBLES
 */
function reorganizeStructures(text, intensity) {
  let modified = text;
  let modifications = 0;

  // Détecter énumérations prévisibles
  const enumerationPatterns = [
    {
      pattern: /Premièrement, (.+?)\. Deuxièmement, (.+?)\. Troisièmement, (.+?)\./gi,
      replacement: 'D\'abord, $1. Ensuite, $2. Enfin, $3.'
    },
    {
      pattern: /D\'une part, (.+?)\. D\'autre part, (.+?)\./gi,
      replacement: 'Tout d\'abord, $1. Par ailleurs, $2.'
    },
    {
      pattern: /En premier lieu, (.+?)\. En second lieu, (.+?)\./gi,
      replacement: 'Dans un premier temps, $1. Puis, $2.'
    }
  ];

  enumerationPatterns.forEach(pattern => {
    if (modified.match(pattern.pattern) && Math.random() < intensity) {
      modified = modified.replace(pattern.pattern, pattern.replacement);
      modifications++;
      logSh(`     🔄 Structure réorganisée: énumération variée`, 'DEBUG');
    }
  });

  return {
    content: modified,
    modifications
  };
}

/**
 * CORRECTION DÉBUTS RÉPÉTITIFS
 */
function fixRepetitiveStarts(text) {
  let modified = text;
  let modifications = 0;

  const sentences = modified.split('. ');
  const startWords = [];
  
  // Analyser débuts de phrases
  sentences.forEach(sentence => {
    const words = sentence.trim().split(/\s+/);
    if (words.length > 0) {
      startWords.push(words[0].toLowerCase());
    }
  });

  // Détecter répétitions
  const startCounts = {};
  startWords.forEach(word => {
    startCounts[word] = (startCounts[word] || 0) + 1;
  });

  // Remplacer débuts répétitifs
  const alternatives = {
    'il': ['Cet élément', 'Cette solution', 'Ce produit'],
    'cette': ['Cette option', 'Cette approche', 'Cette méthode'],
    'pour': ['Afin de', 'Dans le but de', 'En vue de'],
    'avec': ['Grâce à', 'Au moyen de', 'En utilisant'],
    'dans': ['Au sein de', 'À travers', 'Parmi']
  };

  const processedSentences = sentences.map(sentence => {
    const firstWord = sentence.trim().split(/\s+/)[0]?.toLowerCase();
    
    if (firstWord && startCounts[firstWord] > 2 && alternatives[firstWord] && Math.random() < 0.4) {
      const replacement = alternatives[firstWord][Math.floor(Math.random() * alternatives[firstWord].length)];
      const newSentence = sentence.replace(/^\w+/, replacement);
      modifications++;
      logSh(`     🔄 Début varié: "${firstWord}" → "${replacement}"`, 'DEBUG');
      return newSentence;
    }
    
    return sentence;
  });

  return {
    content: processedSentences.join('. '),
    modifications
  };
}

/**
 * DÉTECTION UNIFORMITÉ LONGUEURS (Pattern LLM)
 */
function detectUniformLengths(text) {
  const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
  
  if (sentences.length < 3) return { uniform: false, variance: 0 };
  
  const lengths = sentences.map(s => s.trim().length);
  const avgLength = lengths.reduce((sum, len) => sum + len, 0) / lengths.length;
  
  // Calculer variance
  const variance = lengths.reduce((sum, len) => sum + Math.pow(len - avgLength, 2), 0) / lengths.length;
  const standardDev = Math.sqrt(variance);
  
  // Uniformité si écart-type faible par rapport à moyenne
  const coefficientVariation = standardDev / avgLength;
  const uniform = coefficientVariation < 0.3; // Seuil arbitraire
  
  return {
    uniform,
    variance: coefficientVariation,
    avgLength,
    standardDev,
    sentenceCount: sentences.length
  };
}

/**
 * AJOUT VARIATIONS MICRO-SYNTAXIQUES
 */
function addMicroVariations(text, intensity) {
  let modified = text;
  let modifications = 0;

  // Micro-variations subtiles
  const microPatterns = [
    { from: /\btrès (.+?)\b/g, to: 'particulièrement $1', probability: 0.3 },
    { from: /\bassez (.+?)\b/g, to: 'plutôt $1', probability: 0.4 },
    { from: /\bbeaucoup de/g, to: 'de nombreux', probability: 0.3 },
    { from: /\bpermets de/g, to: 'permet de', probability: 0.8 }, // Correction fréquente
    { from: /\bien effet\b/g, to: 'effectivement', probability: 0.2 }
  ];

  microPatterns.forEach(pattern => {
    if (Math.random() < (intensity * pattern.probability)) {
      const before = modified;
      modified = modified.replace(pattern.from, pattern.to);
      if (modified !== before) {
        modifications++;
        logSh(`     🔧 Micro-variation: ${pattern.from} → ${pattern.to}`, 'DEBUG');
      }
    }
  });

  return {
    content: modified,
    modifications
  };
}

// ============= EXPORTS =============
module.exports = {
  varyStructures,
  splitLongSentences,
  mergeShorter,
  reorganizeStructures,
  fixRepetitiveStarts,
  analyzeSentenceStructure,
  detectUniformLengths,
  addMicroVariations,
  LLM_SYNTAX_PATTERNS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pattern-breaking/LLMFingerprints.js                     │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: LLMFingerprints.js
// RESPONSABILITÉ: Remplacement mots et expressions typiques LLM
// Identification et remplacement des "fingerprints" IA
// ========================================

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

/**
 * MOTS ET EXPRESSIONS TYPIQUES LLM À REMPLACER
 * Classés par niveau de suspicion et fréquence d'usage LLM
 */
const LLM_FINGERPRINTS = {
  
  // ========================================
  // NIVEAU CRITIQUE - Très suspects
  // ========================================
  critical: {
    adjectives: [
      { word: 'comprehensive', alternatives: ['complet', 'détaillé', 'approfondi', 'exhaustif'], suspicion: 0.95 },
      { word: 'robust', alternatives: ['solide', 'fiable', 'résistant', 'durable'], suspicion: 0.92 },
      { word: 'seamless', alternatives: ['fluide', 'harmonieux', 'sans accroc', 'naturel'], suspicion: 0.90 },
      { word: 'optimal', alternatives: ['idéal', 'parfait', 'excellent', 'adapté'], suspicion: 0.88 },
      { word: 'cutting-edge', alternatives: ['innovant', 'moderne', 'récent', 'avancé'], suspicion: 0.87 },
      { word: 'state-of-the-art', alternatives: ['dernier cri', 'moderne', 'récent'], suspicion: 0.95 }
    ],
    
    expressions: [
      { phrase: 'il est important de noter que', alternatives: ['remarquons que', 'signalons que', 'précisons que'], suspicion: 0.85 },
      { phrase: 'dans le paysage actuel', alternatives: ['actuellement', 'de nos jours', 'aujourd\'hui'], suspicion: 0.82 },
      { phrase: 'il convient de souligner', alternatives: ['il faut noter', 'soulignons', 'remarquons'], suspicion: 0.80 },
      { phrase: 'en fin de compte', alternatives: ['finalement', 'au final', 'pour conclure'], suspicion: 0.75 }
    ]
  },

  // ========================================
  // NIVEAU ÉLEVÉ - Souvent suspects  
  // ========================================
  high: {
    adjectives: [
      { word: 'innovative', alternatives: ['novateur', 'créatif', 'original', 'moderne'], suspicion: 0.75 },
      { word: 'efficient', alternatives: ['efficace', 'performant', 'rapide', 'pratique'], suspicion: 0.70 },
      { word: 'versatile', alternatives: ['polyvalent', 'adaptable', 'flexible', 'modulable'], suspicion: 0.68 },
      { word: 'sophisticated', alternatives: ['raffiné', 'élaboré', 'avancé', 'complexe'], suspicion: 0.65 },
      { word: 'compelling', alternatives: ['convaincant', 'captivant', 'intéressant'], suspicion: 0.72 }
    ],
    
    verbs: [
      { word: 'leverage', alternatives: ['utiliser', 'exploiter', 'tirer parti de', 'employer'], suspicion: 0.80 },
      { word: 'optimize', alternatives: ['améliorer', 'perfectionner', 'ajuster'], suspicion: 0.65 },
      { word: 'streamline', alternatives: ['simplifier', 'rationaliser', 'organiser'], suspicion: 0.75 },
      { word: 'enhance', alternatives: ['améliorer', 'enrichir', 'renforcer'], suspicion: 0.60 }
    ],
    
    expressions: [
      { phrase: 'par ailleurs', alternatives: ['de plus', 'également', 'aussi', 'en outre'], suspicion: 0.65 },
      { phrase: 'en outre', alternatives: ['de plus', 'également', 'aussi'], suspicion: 0.70 },
      { phrase: 'cela dit', alternatives: ['néanmoins', 'toutefois', 'cependant'], suspicion: 0.60 }
    ]
  },

  // ========================================
  // NIVEAU MODÉRÉ - Parfois suspects
  // ========================================
  moderate: {
    adjectives: [
      { word: 'significant', alternatives: ['important', 'notable', 'considérable', 'marquant'], suspicion: 0.55 },
      { word: 'essential', alternatives: ['indispensable', 'crucial', 'vital', 'nécessaire'], suspicion: 0.50 },
      { word: 'comprehensive', alternatives: ['complet', 'global', 'détaillé'], suspicion: 0.58 },
      { word: 'effective', alternatives: ['efficace', 'performant', 'réussi'], suspicion: 0.45 }
    ],
    
    expressions: [
      { phrase: 'il est essentiel de', alternatives: ['il faut', 'il importe de', 'il est crucial de'], suspicion: 0.55 },
      { phrase: 'dans cette optique', alternatives: ['dans cette perspective', 'ainsi', 'de ce fait'], suspicion: 0.52 },
      { phrase: 'à cet égard', alternatives: ['sur ce point', 'concernant cela', 'à ce propos'], suspicion: 0.48 }
    ]
  }
};

/**
 * PATTERNS STRUCTURELS LLM
 */
const STRUCTURAL_PATTERNS = {
  // Débuts de phrases trop formels
  formalStarts: [
    /^Il est important de souligner que/gi,
    /^Il convient de noter que/gi,
    /^Il est essentiel de comprendre que/gi,
    /^Dans ce contexte, il est crucial de/gi,
    /^Il est primordial de/gi
  ],
  
  // Transitions trop parfaites
  perfectTransitions: [
    /\. Par ailleurs, (.+?)\. En outre, (.+?)\. De plus,/gi,
    /\. Premièrement, (.+?)\. Deuxièmement, (.+?)\. Troisièmement,/gi
  ],
  
  // Conclusions trop formelles
  formalConclusions: [
    /En conclusion, il apparaît clairement que/gi,
    /Pour conclure, il est évident que/gi,
    /En définitive, nous pouvons affirmer que/gi
  ]
};

/**
 * DÉTECTION PATTERNS LLM DANS LE TEXTE
 * @param {string} text - Texte à analyser
 * @returns {object} - { count, patterns, suspicionScore }
 */
function detectLLMPatterns(text) {
  if (!text || text.trim().length === 0) {
    return { count: 0, patterns: [], suspicionScore: 0 };
  }

  const detectedPatterns = [];
  let totalSuspicion = 0;
  let wordCount = text.split(/\s+/).length;

  // Analyser tous les niveaux de fingerprints
  Object.entries(LLM_FINGERPRINTS).forEach(([level, categories]) => {
    Object.entries(categories).forEach(([category, items]) => {
      items.forEach(item => {
        const regex = new RegExp(`\\b${item.word || item.phrase}\\b`, 'gi');
        const matches = text.match(regex);
        
        if (matches) {
          detectedPatterns.push({
            pattern: item.word || item.phrase,
            type: category,
            level: level,
            count: matches.length,
            suspicion: item.suspicion,
            alternatives: item.alternatives
          });
          
          totalSuspicion += item.suspicion * matches.length;
        }
      });
    });
  });

  // Analyser patterns structurels
  Object.entries(STRUCTURAL_PATTERNS).forEach(([patternType, patterns]) => {
    patterns.forEach(pattern => {
      const matches = text.match(pattern);
      if (matches) {
        detectedPatterns.push({
          pattern: pattern.source,
          type: 'structural',
          level: 'high',
          count: matches.length,
          suspicion: 0.80
        });
        
        totalSuspicion += 0.80 * matches.length;
      }
    });
  });

  const suspicionScore = wordCount > 0 ? totalSuspicion / wordCount : 0;

  logSh(`🔍 Patterns LLM détectés: ${detectedPatterns.length} (score suspicion: ${suspicionScore.toFixed(3)})`, 'DEBUG');

  return {
    count: detectedPatterns.length,
    patterns: detectedPatterns.map(p => p.pattern),
    detailedPatterns: detectedPatterns,
    suspicionScore,
    recommendation: suspicionScore > 0.05 ? 'replacement' : 'minor_cleanup'
  };
}

/**
 * REMPLACEMENT FINGERPRINTS LLM
 * @param {string} text - Texte à traiter
 * @param {object} options - Options { intensity, preserveContext, maxReplacements }
 * @returns {object} - { content, replacements, details }
 */
function replaceLLMFingerprints(text, options = {}) {
  if (!text || text.trim().length === 0) {
    return { content: text, replacements: 0 };
  }

  const config = {
    intensity: 0.5,
    preserveContext: true,
    maxReplacements: 5,
    ...options
  };

  logSh(`🤖 Remplacement fingerprints LLM: intensité ${config.intensity}`, 'DEBUG');

  let modifiedText = text;
  let totalReplacements = 0;
  const replacementDetails = [];

  try {
    // Détecter d'abord les patterns
    const detection = detectLLMPatterns(modifiedText);
    
    if (detection.count === 0) {
      logSh(`   ✅ Aucun fingerprint LLM détecté`, 'DEBUG');
      return { content: text, replacements: 0, details: [] };
    }

    // Traiter par niveau de priorité
    const priorities = ['critical', 'high', 'moderate'];
    
    for (const priority of priorities) {
      if (totalReplacements >= config.maxReplacements) break;
      
      const categoryData = LLM_FINGERPRINTS[priority];
      if (!categoryData) continue;

      // Traiter chaque catégorie
      Object.entries(categoryData).forEach(([category, items]) => {
        items.forEach(item => {
          if (totalReplacements >= config.maxReplacements) return;
          
          const searchTerm = item.word || item.phrase;
          const regex = new RegExp(`\\b${searchTerm}\\b`, 'gi');
          
          // Probabilité de remplacement basée sur suspicion et intensité
          const replacementProbability = item.suspicion * config.intensity;
          
          if (modifiedText.match(regex) && Math.random() < replacementProbability) {
            // Choisir alternative aléatoire
            const alternative = item.alternatives[Math.floor(Math.random() * item.alternatives.length)];
            
            const beforeText = modifiedText;
            modifiedText = modifiedText.replace(regex, alternative);
            
            if (modifiedText !== beforeText) {
              totalReplacements++;
              replacementDetails.push({
                original: searchTerm,
                replacement: alternative,
                category,
                level: priority,
                suspicion: item.suspicion
              });
              
              logSh(`     🔄 Remplacé "${searchTerm}" → "${alternative}" (suspicion: ${item.suspicion})`, 'DEBUG');
            }
          }
        });
      });
    }

    // Traitement patterns structurels
    if (totalReplacements < config.maxReplacements) {
      const structuralResult = replaceStructuralPatterns(modifiedText, config.intensity);
      modifiedText = structuralResult.content;
      totalReplacements += structuralResult.replacements;
      replacementDetails.push(...structuralResult.details);
    }

    logSh(`🤖 Fingerprints remplacés: ${totalReplacements} modifications`, 'DEBUG');

  } catch (error) {
    logSh(`❌ Erreur remplacement fingerprints: ${error.message}`, 'WARNING');
    return { content: text, replacements: 0, details: [] };
  }

  return {
    content: modifiedText,
    replacements: totalReplacements,
    details: replacementDetails
  };
}

/**
 * REMPLACEMENT PATTERNS STRUCTURELS
 */
function replaceStructuralPatterns(text, intensity) {
  let modified = text;
  let replacements = 0;
  const details = [];

  // Débuts formels → versions plus naturelles
  const formalStartReplacements = [
    {
      from: /^Il est important de souligner que (.+)/gim,
      to: 'Notons que $1',
      name: 'début formel'
    },
    {
      from: /^Il convient de noter que (.+)/gim,
      to: 'Précisons que $1',
      name: 'formulation convient'
    },
    {
      from: /^Dans ce contexte, il est crucial de (.+)/gim,
      to: 'Il faut $1',
      name: 'contexte crucial'
    }
  ];

  formalStartReplacements.forEach(replacement => {
    if (Math.random() < intensity * 0.7) {
      const before = modified;
      modified = modified.replace(replacement.from, replacement.to);
      
      if (modified !== before) {
        replacements++;
        details.push({
          original: replacement.name,
          replacement: 'version naturelle',
          category: 'structural',
          level: 'high',
          suspicion: 0.80
        });
        
        logSh(`     🏗️ Pattern structurel remplacé: ${replacement.name}`, 'DEBUG');
      }
    }
  });

  return {
    content: modified,
    replacements,
    details
  };
}

/**
 * ANALYSE DENSITÉ FINGERPRINTS
 */
function analyzeFingerprintDensity(text) {
  const detection = detectLLMPatterns(text);
  const wordCount = text.split(/\s+/).length;
  
  const density = detection.count / wordCount;
  const riskLevel = density > 0.08 ? 'high' : density > 0.04 ? 'medium' : 'low';
  
  return {
    fingerprintCount: detection.count,
    wordCount,
    density,
    riskLevel,
    suspicionScore: detection.suspicionScore,
    recommendation: riskLevel === 'high' ? 'immediate_replacement' : 
                    riskLevel === 'medium' ? 'selective_replacement' : 'minimal_cleanup'
  };
}

/**
 * SUGGESTIONS CONTEXTUELLES
 */
function generateContextualAlternatives(word, context, personality) {
  // Adapter selon personnalité si fournie
  if (personality) {
    const personalityAdaptations = {
      'marc': { 'optimal': 'efficace', 'robust': 'solide', 'comprehensive': 'complet' },
      'sophie': { 'optimal': 'parfait', 'robust': 'résistant', 'comprehensive': 'détaillé' },
      'kevin': { 'optimal': 'nickel', 'robust': 'costaud', 'comprehensive': 'complet' }
    };
    
    const adaptations = personalityAdaptations[personality.toLowerCase()];
    if (adaptations && adaptations[word]) {
      return [adaptations[word]];
    }
  }

  // Suggestions contextuelles basiques
  const contextualMappings = {
    'optimal': context.includes('solution') ? ['idéale', 'parfaite'] : ['excellent', 'adapté'],
    'robust': context.includes('système') ? ['fiable', 'stable'] : ['solide', 'résistant'],
    'comprehensive': context.includes('analyse') ? ['approfondie', 'détaillée'] : ['complète', 'globale']
  };

  return contextualMappings[word] || ['standard'];
}

// ============= EXPORTS =============
module.exports = {
  detectLLMPatterns,
  replaceLLMFingerprints,
  replaceStructuralPatterns,
  analyzeFingerprintDensity,
  generateContextualAlternatives,
  LLM_FINGERPRINTS,
  STRUCTURAL_PATTERNS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pattern-breaking/NaturalConnectors.js                   │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: NaturalConnectors.js
// RESPONSABILITÉ: Humanisation des connecteurs et transitions
// Remplacement connecteurs formels par versions naturelles
// ========================================

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

/**
 * CONNECTEURS FORMELS LLM À HUMANISER
 */
const FORMAL_CONNECTORS = {
  // Connecteurs trop formels/académiques
  formal: [
    { connector: 'par ailleurs', alternatives: ['aussi', 'également', 'de plus', 'en plus'], suspicion: 0.75 },
    { connector: 'en outre', alternatives: ['de plus', 'également', 'aussi', 'en plus'], suspicion: 0.80 },
    { connector: 'de surcroît', alternatives: ['de plus', 'aussi', 'en plus'], suspicion: 0.85 },
    { connector: 'qui plus est', alternatives: ['en plus', 'et puis', 'aussi'], suspicion: 0.80 },
    { connector: 'par conséquent', alternatives: ['donc', 'alors', 'du coup', 'résultat'], suspicion: 0.70 },
    { connector: 'en conséquence', alternatives: ['donc', 'alors', 'du coup'], suspicion: 0.75 },
    { connector: 'néanmoins', alternatives: ['mais', 'pourtant', 'cependant', 'malgré ça'], suspicion: 0.65 },
    { connector: 'toutefois', alternatives: ['mais', 'pourtant', 'cependant'], suspicion: 0.70 }
  ],

  // Débuts de phrases formels
  formalStarts: [
    { phrase: 'il convient de noter que', alternatives: ['notons que', 'remarquons que', 'précisons que'], suspicion: 0.90 },
    { phrase: 'il est important de souligner que', alternatives: ['soulignons que', 'notons que', 'précisons que'], suspicion: 0.85 },
    { phrase: 'il est à noter que', alternatives: ['notons que', 'signalons que', 'précisons que'], suspicion: 0.80 },
    { phrase: 'il convient de préciser que', alternatives: ['précisons que', 'ajoutons que', 'notons que'], suspicion: 0.75 },
    { phrase: 'dans ce contexte', alternatives: ['ici', 'dans ce cas', 'alors'], suspicion: 0.70 }
  ],

  // Transitions artificielles
  artificialTransitions: [
    { phrase: 'abordons maintenant', alternatives: ['passons à', 'voyons', 'parlons de'], suspicion: 0.75 },
    { phrase: 'examinons à présent', alternatives: ['voyons', 'regardons', 'passons à'], suspicion: 0.80 },
    { phrase: 'intéressons-nous désormais à', alternatives: ['voyons', 'parlons de', 'passons à'], suspicion: 0.85 },
    { phrase: 'penchons-nous sur', alternatives: ['voyons', 'regardons', 'parlons de'], suspicion: 0.70 }
  ]
};

/**
 * CONNECTEURS NATURELS PAR CONTEXTE
 */
const NATURAL_CONNECTORS_BY_CONTEXT = {
  // Selon le ton/registre souhaité
  casual: ['du coup', 'alors', 'et puis', 'aussi', 'en fait'],
  conversational: ['bon', 'eh bien', 'donc', 'alors', 'et puis'],
  technical: ['donc', 'ainsi', 'alors', 'par là', 'de cette façon'],
  commercial: ['donc', 'alors', 'ainsi', 'de plus', 'aussi']
};

/**
 * HUMANISATION CONNECTEURS ET TRANSITIONS - FONCTION PRINCIPALE
 * @param {string} text - Texte à humaniser
 * @param {object} options - Options { intensity, preserveMeaning, maxReplacements }
 * @returns {object} - { content, replacements, details }
 */
function humanizeTransitions(text, options = {}) {
  if (!text || text.trim().length === 0) {
    return { content: text, replacements: 0 };
  }

  const config = {
    intensity: 0.6,
    preserveMeaning: true,
    maxReplacements: 4,
    tone: 'casual', // casual, conversational, technical, commercial
    ...options
  };

  logSh(`🔗 Humanisation connecteurs: intensité ${config.intensity}, ton ${config.tone}`, 'DEBUG');

  let modifiedText = text;
  let totalReplacements = 0;
  const replacementDetails = [];

  try {
    // 1. Remplacer connecteurs formels
    const connectorsResult = replaceFormalConnectors(modifiedText, config);
    modifiedText = connectorsResult.content;
    totalReplacements += connectorsResult.replacements;
    replacementDetails.push(...connectorsResult.details);

    // 2. Humaniser débuts de phrases
    if (totalReplacements < config.maxReplacements) {
      const startsResult = humanizeFormalStarts(modifiedText, config);
      modifiedText = startsResult.content;
      totalReplacements += startsResult.replacements;
      replacementDetails.push(...startsResult.details);
    }

    // 3. Remplacer transitions artificielles
    if (totalReplacements < config.maxReplacements) {
      const transitionsResult = replaceArtificialTransitions(modifiedText, config);
      modifiedText = transitionsResult.content;
      totalReplacements += transitionsResult.replacements;
      replacementDetails.push(...transitionsResult.details);
    }

    // 4. Ajouter variabilité contextuelle
    if (totalReplacements < config.maxReplacements) {
      const contextResult = addContextualVariability(modifiedText, config);
      modifiedText = contextResult.content;
      totalReplacements += contextResult.replacements;
      replacementDetails.push(...contextResult.details);
    }

    logSh(`🔗 Connecteurs humanisés: ${totalReplacements} remplacements effectués`, 'DEBUG');

  } catch (error) {
    logSh(`❌ Erreur humanisation connecteurs: ${error.message}`, 'WARNING');
    return { content: text, replacements: 0, details: [] };
  }

  return {
    content: modifiedText,
    replacements: totalReplacements,
    details: replacementDetails
  };
}

/**
 * REMPLACEMENT CONNECTEURS FORMELS
 */
function replaceFormalConnectors(text, config) {
  let modified = text;
  let replacements = 0;
  const details = [];

  FORMAL_CONNECTORS.formal.forEach(connector => {
    if (replacements >= Math.floor(config.maxReplacements / 2)) return;

    const regex = new RegExp(`\\b${connector.connector}\\b`, 'gi');
    const matches = modified.match(regex);
    
    if (matches && Math.random() < (config.intensity * connector.suspicion)) {
      // Choisir alternative selon contexte/ton
      const availableAlts = connector.alternatives;
      const contextualAlts = NATURAL_CONNECTORS_BY_CONTEXT[config.tone] || [];
      
      // Préférer alternatives contextuelles si disponibles
      const preferredAlts = availableAlts.filter(alt => contextualAlts.includes(alt));
      const finalAlts = preferredAlts.length > 0 ? preferredAlts : availableAlts;
      
      const chosen = finalAlts[Math.floor(Math.random() * finalAlts.length)];
      
      const beforeText = modified;
      modified = modified.replace(regex, chosen);
      
      if (modified !== beforeText) {
        replacements++;
        details.push({
          original: connector.connector,
          replacement: chosen,
          type: 'formal_connector',
          suspicion: connector.suspicion
        });
        
        logSh(`     🔄 Connecteur formalisé: "${connector.connector}" → "${chosen}"`, 'DEBUG');
      }
    }
  });

  return { content: modified, replacements, details };
}

/**
 * HUMANISATION DÉBUTS DE PHRASES FORMELS
 */
function humanizeFormalStarts(text, config) {
  let modified = text;
  let replacements = 0;
  const details = [];

  FORMAL_CONNECTORS.formalStarts.forEach(start => {
    if (replacements >= Math.floor(config.maxReplacements / 3)) return;

    const regex = new RegExp(start.phrase, 'gi');
    
    if (modified.match(regex) && Math.random() < (config.intensity * start.suspicion)) {
      const alternative = start.alternatives[Math.floor(Math.random() * start.alternatives.length)];
      
      const beforeText = modified;
      modified = modified.replace(regex, alternative);
      
      if (modified !== beforeText) {
        replacements++;
        details.push({
          original: start.phrase,
          replacement: alternative,
          type: 'formal_start',
          suspicion: start.suspicion
        });
        
        logSh(`     🚀 Début formalisé: "${start.phrase}" → "${alternative}"`, 'DEBUG');
      }
    }
  });

  return { content: modified, replacements, details };
}

/**
 * REMPLACEMENT TRANSITIONS ARTIFICIELLES
 */
function replaceArtificialTransitions(text, config) {
  let modified = text;
  let replacements = 0;
  const details = [];

  FORMAL_CONNECTORS.artificialTransitions.forEach(transition => {
    if (replacements >= Math.floor(config.maxReplacements / 4)) return;

    const regex = new RegExp(transition.phrase, 'gi');
    
    if (modified.match(regex) && Math.random() < (config.intensity * transition.suspicion * 0.8)) {
      const alternative = transition.alternatives[Math.floor(Math.random() * transition.alternatives.length)];
      
      const beforeText = modified;
      modified = modified.replace(regex, alternative);
      
      if (modified !== beforeText) {
        replacements++;
        details.push({
          original: transition.phrase,
          replacement: alternative,
          type: 'artificial_transition',
          suspicion: transition.suspicion
        });
        
        logSh(`     🌉 Transition artificialisée: "${transition.phrase}" → "${alternative}"`, 'DEBUG');
      }
    }
  });

  return { content: modified, replacements, details };
}

/**
 * AJOUT VARIABILITÉ CONTEXTUELLE
 */
function addContextualVariability(text, config) {
  let modified = text;
  let replacements = 0;
  const details = [];

  // Connecteurs génériques à contextualiser selon le ton
  const genericPatterns = [
    { from: /\bet puis\b/g, contextual: true },
    { from: /\bdone\b/g, contextual: true },
    { from: /\bainsi\b/g, contextual: true }
  ];

  const contextualReplacements = NATURAL_CONNECTORS_BY_CONTEXT[config.tone] || NATURAL_CONNECTORS_BY_CONTEXT.casual;

  genericPatterns.forEach(pattern => {
    if (replacements >= 2) return;

    if (pattern.contextual && Math.random() < (config.intensity * 0.4)) {
      const matches = modified.match(pattern.from);
      
      if (matches && contextualReplacements.length > 0) {
        const replacement = contextualReplacements[Math.floor(Math.random() * contextualReplacements.length)];
        
        // Éviter remplacements identiques
        if (replacement !== matches[0]) {
          const beforeText = modified;
          modified = modified.replace(pattern.from, replacement);
          
          if (modified !== beforeText) {
            replacements++;
            details.push({
              original: matches[0],
              replacement,
              type: 'contextual_variation',
              suspicion: 0.4
            });
            
            logSh(`     🎯 Variation contextuelle: "${matches[0]}" → "${replacement}"`, 'DEBUG');
          }
        }
      }
    }
  });

  return { content: modified, replacements, details };
}

/**
 * DÉTECTION CONNECTEURS FORMELS DANS TEXTE
 */
function detectFormalConnectors(text) {
  if (!text || text.trim().length === 0) {
    return { count: 0, connectors: [], suspicionScore: 0 };
  }

  const detectedConnectors = [];
  let totalSuspicion = 0;

  // Vérifier tous les types de connecteurs formels
  Object.values(FORMAL_CONNECTORS).flat().forEach(item => {
    const searchTerm = item.connector || item.phrase;
    const regex = new RegExp(`\\b${searchTerm}\\b`, 'gi');
    const matches = text.match(regex);
    
    if (matches) {
      detectedConnectors.push({
        connector: searchTerm,
        count: matches.length,
        suspicion: item.suspicion,
        alternatives: item.alternatives
      });
      
      totalSuspicion += item.suspicion * matches.length;
    }
  });

  const wordCount = text.split(/\s+/).length;
  const suspicionScore = wordCount > 0 ? totalSuspicion / wordCount : 0;

  logSh(`🔍 Connecteurs formels détectés: ${detectedConnectors.length} (score: ${suspicionScore.toFixed(3)})`, 'DEBUG');

  return {
    count: detectedConnectors.length,
    connectors: detectedConnectors.map(c => c.connector),
    detailedConnectors: detectedConnectors,
    suspicionScore,
    recommendation: suspicionScore > 0.03 ? 'humanize' : 'minimal_changes'
  };
}

/**
 * ANALYSE DENSITÉ CONNECTEURS FORMELS
 */
function analyzeConnectorFormality(text) {
  const detection = detectFormalConnectors(text);
  const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
  
  const density = detection.count / sentences.length;
  const formalityLevel = density > 0.4 ? 'high' : density > 0.2 ? 'medium' : 'low';
  
  return {
    connectorsCount: detection.count,
    sentenceCount: sentences.length,
    density,
    formalityLevel,
    suspicionScore: detection.suspicionScore,
    recommendation: formalityLevel === 'high' ? 'extensive_humanization' : 
                    formalityLevel === 'medium' ? 'selective_humanization' : 'minimal_humanization'
  };
}

// ============= EXPORTS =============
module.exports = {
  humanizeTransitions,
  replaceFormalConnectors,
  humanizeFormalStarts,
  replaceArtificialTransitions,
  addContextualVariability,
  detectFormalConnectors,
  analyzeConnectorFormality,
  FORMAL_CONNECTORS,
  NATURAL_CONNECTORS_BY_CONTEXT
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pattern-breaking/PatternBreakingCore.js                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: PatternBreakingCore.js
// RESPONSABILITÉ: Orchestrateur principal Pattern Breaking
// Niveau 2: Casser les patterns syntaxiques typiques des LLMs
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { varyStructures, splitLongSentences, mergeShorter } = require('./SyntaxVariations');
const { replaceLLMFingerprints, detectLLMPatterns } = require('./LLMFingerprints');
const { humanizeTransitions, replaceConnectors } = require('./NaturalConnectors');

/**
 * CONFIGURATION MODULAIRE AGRESSIVE PATTERN BREAKING
 * Chaque feature peut être activée/désactivée individuellement
 */
const DEFAULT_CONFIG = {
  // ========================================
  // CONTRÔLES GLOBAUX
  // ========================================
  intensityLevel: 0.8,              // Intensité globale (0-1) - PLUS AGRESSIVE
  preserveReadability: true,        // Maintenir lisibilité
  maxModificationsPerElement: 8,    // Limite modifications par élément - DOUBLÉE
  qualityThreshold: 0.5,            // Seuil qualité minimum - ABAISSÉ
  
  // ========================================
  // FEATURES SYNTAXE & STRUCTURE
  // ========================================
  syntaxVariationEnabled: true,     // Variations syntaxiques de base
  aggressiveSentenceSplitting: true, // Découpage phrases plus agressif (<80 chars)
  aggressiveSentenceMerging: true,   // Fusion phrases courtes (<60 chars)
  microSyntaxVariations: true,      // Micro-variations subtiles
  questionInjection: true,          // Injection questions rhétoriques
  
  // ========================================
  // FEATURES LLM FINGERPRINTS
  // ========================================
  llmFingerprintReplacement: true,  // Remplacement fingerprints de base
  frenchLLMPatterns: true,          // Patterns spécifiques français
  overlyFormalVocabulary: true,     // Vocabulaire trop formel → casual
  repetitiveStarters: true,         // Débuts de phrases répétitifs
  perfectTransitions: true,         // Transitions trop parfaites
  
  // ========================================
  // FEATURES CONNECTEURS & TRANSITIONS
  // ========================================
  naturalConnectorsEnabled: true,   // Connecteurs naturels de base
  casualConnectors: true,           // Connecteurs très casual (genre, enfin, bref)
  hesitationMarkers: true,          // Marqueurs d'hésitation (..., euh)
  colloquialTransitions: true,      // Transitions colloquiales
  
  // ========================================
  // FEATURES IMPERFECTIONS HUMAINES
  // ========================================
  humanImperfections: true,         // Système d'imperfections humaines
  vocabularyRepetitions: true,      // Répétitions vocabulaire naturelles
  casualizationIntensive: true,     // Casualisation intensive
  naturalHesitations: true,         // Hésitations naturelles en fin de phrase
  informalExpressions: true,        // Expressions informelles ("pas mal", "sympa")
  
  // ========================================
  // FEATURES RESTRUCTURATION
  // ========================================
  intelligentRestructuring: true,   // Restructuration intelligente
  paragraphBreaking: true,          // Cassage paragraphes longs
  listToTextConversion: true,       // Listes → texte naturel
  redundancyInjection: true,        // Injection redondances naturelles
  
  // ========================================
  // FEATURES SPÉCIALISÉES  
  // ========================================
  personalityAdaptation: true,      // Adaptation selon personnalité
  temporalConsistency: true,        // Cohérence temporelle (maintenant/aujourd'hui)
  contextualVocabulary: true,       // Vocabulaire contextuel
  registerVariation: true           // Variation registre langue
};

/**
 * ORCHESTRATEUR PRINCIPAL - Pattern Breaking Layer
 * @param {object} content - Contenu généré à traiter
 * @param {object} options - Options de pattern breaking
 * @returns {object} - { content, stats, fallback }
 */
async function applyPatternBreakingLayer(content, options = {}) {
  return await tracer.run('PatternBreakingCore.applyPatternBreakingLayer()', async () => {
    const startTime = Date.now();
    
    await tracer.annotate({
      contentKeys: Object.keys(content).length,
      intensityLevel: options.intensityLevel,
      personality: options.csvData?.personality?.nom
    });

    logSh(`🔧 PATTERN BREAKING - Début traitement`, 'INFO');
    logSh(`   📊 ${Object.keys(content).length} éléments | Intensité: ${options.intensityLevel || DEFAULT_CONFIG.intensityLevel}`, 'DEBUG');

    try {
      // Configuration fusionnée
      const config = { ...DEFAULT_CONFIG, ...options };
      
      // Stats de pattern breaking
      const patternStats = {
        elementsProcessed: 0,
        syntaxModifications: 0,
        llmFingerprintReplacements: 0,
        connectorReplacements: 0,
        totalModifications: 0,
        fallbackUsed: false,
        patternsDetected: 0
      };

      // Contenu traité
      let processedContent = { ...content };

      // ========================================
      // TRAITEMENT PAR ÉLÉMENT
      // ========================================
      for (const [elementKey, elementContent] of Object.entries(content)) {
        await tracer.run(`PatternBreaking.processElement(${elementKey})`, async () => {
          
          logSh(`   🎯 Traitement élément: ${elementKey}`, 'DEBUG');
          
          let currentContent = elementContent;
          let elementModifications = 0;

          try {
            // 1. Détection patterns LLM
            const detectedPatterns = detectLLMPatterns(currentContent);
            patternStats.patternsDetected += detectedPatterns.count;
            
            if (detectedPatterns.count > 0) {
              logSh(`     🔍 ${detectedPatterns.count} patterns LLM détectés: ${detectedPatterns.patterns.slice(0, 3).join(', ')}`, 'DEBUG');
            }

            // 2. SYNTAXE & STRUCTURE - Couche de base
            if (config.syntaxVariationEnabled) {
              const syntaxResult = await applySyntaxVariation(currentContent, config);
              currentContent = syntaxResult.content;
              elementModifications += syntaxResult.modifications;
              patternStats.syntaxModifications += syntaxResult.modifications;
              logSh(`     📝 Syntaxe: ${syntaxResult.modifications} variations appliquées`, 'DEBUG');
            }

            // 3. SYNTAXE AGRESSIVE - Couche intensive
            if (config.aggressiveSentenceSplitting || config.aggressiveSentenceMerging) {
              const aggressiveResult = await applyAggressiveSyntax(currentContent, config);
              currentContent = aggressiveResult.content;
              elementModifications += aggressiveResult.modifications;
              patternStats.syntaxModifications += aggressiveResult.modifications;
              logSh(`     ✂️ Syntaxe agressive: ${aggressiveResult.modifications} modifications`, 'DEBUG');
            }

            // 4. MICRO-VARIATIONS - Subtiles mais importantes
            if (config.microSyntaxVariations) {
              const microResult = await applyMicroVariations(currentContent, config);
              currentContent = microResult.content;
              elementModifications += microResult.modifications;
              patternStats.syntaxModifications += microResult.modifications;
              logSh(`     🔧 Micro-variations: ${microResult.modifications} ajustements`, 'DEBUG');
            }

            // 5. LLM FINGERPRINTS - Détection de base
            if (config.llmFingerprintReplacement && detectedPatterns.count > 0) {
              const fingerprintResult = await applyLLMFingerprints(currentContent, config);
              currentContent = fingerprintResult.content;
              elementModifications += fingerprintResult.modifications;
              patternStats.llmFingerprintReplacements += fingerprintResult.modifications;
              logSh(`     🤖 LLM Fingerprints: ${fingerprintResult.modifications} remplacements`, 'DEBUG');
            }

            // 6. PATTERNS FRANÇAIS - Spécifique langue française
            if (config.frenchLLMPatterns) {
              const frenchResult = await applyFrenchPatterns(currentContent, config);
              currentContent = frenchResult.content;
              elementModifications += frenchResult.modifications;
              patternStats.llmFingerprintReplacements += frenchResult.modifications;
              logSh(`     🇫🇷 Patterns français: ${frenchResult.modifications} corrections`, 'DEBUG');
            }

            // 7. VOCABULAIRE FORMEL - Casualisation
            if (config.overlyFormalVocabulary) {
              const casualResult = await applyCasualization(currentContent, config);
              currentContent = casualResult.content;
              elementModifications += casualResult.modifications;
              patternStats.llmFingerprintReplacements += casualResult.modifications;
              logSh(`     😎 Casualisation: ${casualResult.modifications} simplifications`, 'DEBUG');
            }

            // 8. CONNECTEURS NATURELS - Base
            if (config.naturalConnectorsEnabled) {
              const connectorResult = await applyNaturalConnectors(currentContent, config);
              currentContent = connectorResult.content;
              elementModifications += connectorResult.modifications;
              patternStats.connectorReplacements += connectorResult.modifications;
              logSh(`     🔗 Connecteurs naturels: ${connectorResult.modifications} humanisés`, 'DEBUG');
            }

            // 9. CONNECTEURS CASUAL - Très familier
            if (config.casualConnectors) {
              const casualConnResult = await applyCasualConnectors(currentContent, config);
              currentContent = casualConnResult.content;
              elementModifications += casualConnResult.modifications;
              patternStats.connectorReplacements += casualConnResult.modifications;
              logSh(`     🗣️ Connecteurs casual: ${casualConnResult.modifications} familiarisés`, 'DEBUG');
            }

            // 10. IMPERFECTIONS HUMAINES - Système principal
            if (config.humanImperfections) {
              const imperfResult = await applyHumanImperfections(currentContent, config);
              currentContent = imperfResult.content;
              elementModifications += imperfResult.modifications;
              patternStats.totalModifications += imperfResult.modifications;
              logSh(`     👤 Imperfections: ${imperfResult.modifications} humanisations`, 'DEBUG');
            }

            // 11. QUESTIONS RHÉTORIQUES - Engagement
            if (config.questionInjection) {
              const questionResult = await applyQuestionInjection(currentContent, config);
              currentContent = questionResult.content;
              elementModifications += questionResult.modifications;
              patternStats.totalModifications += questionResult.modifications;
              logSh(`     ❓ Questions: ${questionResult.modifications} injections`, 'DEBUG');
            }

            // 12. RESTRUCTURATION INTELLIGENTE - Dernière couche
            if (config.intelligentRestructuring) {
              const restructResult = await applyIntelligentRestructuring(currentContent, config);
              currentContent = restructResult.content;
              elementModifications += restructResult.modifications;
              patternStats.totalModifications += restructResult.modifications;
              logSh(`     🧠 Restructuration: ${restructResult.modifications} réorganisations`, 'DEBUG');
            }

            // 5. Validation qualité
            const qualityCheck = validatePatternBreakingQuality(elementContent, currentContent, config.qualityThreshold);
            
            if (qualityCheck.acceptable) {
              processedContent[elementKey] = currentContent;
              patternStats.elementsProcessed++;
              patternStats.totalModifications += elementModifications;
              
              logSh(`     ✅ Élément traité: ${elementModifications} modifications totales`, 'DEBUG');
            } else {
              // Fallback: garder contenu original
              processedContent[elementKey] = elementContent;
              patternStats.fallbackUsed = true;
              
              logSh(`     ⚠️ Qualité insuffisante, fallback vers contenu original`, 'WARNING');
            }

          } catch (elementError) {
            logSh(`     ❌ Erreur pattern breaking élément ${elementKey}: ${elementError.message}`, 'WARNING');
            processedContent[elementKey] = elementContent; // Fallback
            patternStats.fallbackUsed = true;
          }

        }, { elementKey, originalLength: elementContent?.length });
      }

      // ========================================
      // RÉSULTATS FINAUX
      // ========================================
      const duration = Date.now() - startTime;
      const success = patternStats.elementsProcessed > 0 && !patternStats.fallbackUsed;

      logSh(`🔧 PATTERN BREAKING - Terminé (${duration}ms)`, 'INFO');
      logSh(`   ✅ ${patternStats.elementsProcessed}/${Object.keys(content).length} éléments traités`, 'INFO');
      logSh(`   📊 ${patternStats.syntaxModifications} syntaxe | ${patternStats.llmFingerprintReplacements} fingerprints | ${patternStats.connectorReplacements} connecteurs`, 'INFO');
      logSh(`   🎯 Patterns détectés: ${patternStats.patternsDetected} | Fallback: ${patternStats.fallbackUsed ? 'OUI' : 'NON'}`, 'INFO');

      await tracer.event('Pattern Breaking terminé', {
        success,
        duration,
        stats: patternStats
      });

      return {
        content: processedContent,
        stats: patternStats,
        fallback: patternStats.fallbackUsed,
        duration
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ PATTERN BREAKING ÉCHOUÉ (${duration}ms): ${error.message}`, 'ERROR');
      
      await tracer.event('Pattern Breaking échoué', {
        error: error.message,
        duration,
        contentKeys: Object.keys(content).length
      });

      // Fallback complet
      return {
        content,
        stats: { fallbackUsed: true, error: error.message },
        fallback: true,
        duration
      };
    }

  }, { 
    contentElements: Object.keys(content).length,
    intensityLevel: options.intensityLevel 
  });
}

/**
 * APPLICATION VARIATION SYNTAXIQUE
 */
async function applySyntaxVariation(content, config) {
  const syntaxResult = varyStructures(content, config.intensityLevel, {
    preserveReadability: config.preserveReadability,
    maxModifications: Math.floor(config.maxModificationsPerElement / 2)
  });

  return {
    content: syntaxResult.content,
    modifications: syntaxResult.modifications || 0
  };
}

/**
 * APPLICATION REMPLACEMENT LLM FINGERPRINTS
 */
async function applyLLMFingerprints(content, config) {
  const fingerprintResult = replaceLLMFingerprints(content, {
    intensity: config.intensityLevel,
    preserveContext: true,
    maxReplacements: Math.floor(config.maxModificationsPerElement / 2)
  });

  return {
    content: fingerprintResult.content,
    modifications: fingerprintResult.replacements || 0
  };
}

/**
 * APPLICATION CONNECTEURS NATURELS
 */
async function applyNaturalConnectors(content, config) {
  const connectorResult = humanizeTransitions(content, {
    intensity: config.intensityLevel,
    preserveMeaning: true,
    maxReplacements: Math.floor(config.maxModificationsPerElement / 2)
  });

  return {
    content: connectorResult.content,
    modifications: connectorResult.replacements || 0
  };
}

/**
 * VALIDATION QUALITÉ PATTERN BREAKING
 */
function validatePatternBreakingQuality(originalContent, processedContent, qualityThreshold) {
  if (!originalContent || !processedContent) {
    return { acceptable: false, reason: 'Contenu manquant' };
  }

  // Métriques de base
  const lengthDiff = Math.abs(processedContent.length - originalContent.length) / originalContent.length;
  const wordCountOriginal = originalContent.split(/\s+/).length;
  const wordCountProcessed = processedContent.split(/\s+/).length;
  const wordCountDiff = Math.abs(wordCountProcessed - wordCountOriginal) / wordCountOriginal;

  // Vérifications qualité
  const checks = {
    lengthPreserved: lengthDiff < 0.3,          // Pas plus de 30% de différence
    wordCountPreserved: wordCountDiff < 0.2,    // Pas plus de 20% de différence
    noEmpty: processedContent.trim().length > 0, // Pas de contenu vide
    readableStructure: processedContent.includes('.') // Structure lisible
  };

  const passedChecks = Object.values(checks).filter(Boolean).length;
  const score = passedChecks / Object.keys(checks).length;
  
  const acceptable = score >= qualityThreshold;

  logSh(`   🎯 Validation Pattern Breaking: ${acceptable ? 'ACCEPTÉ' : 'REJETÉ'} (score: ${score.toFixed(2)})`, acceptable ? 'DEBUG' : 'WARNING');

  return {
    acceptable,
    score,
    checks,
    reason: acceptable ? 'Qualité acceptable' : 'Score qualité insuffisant'
  };
}

/**
 * APPLICATION SYNTAXE AGRESSIVE
 * Seuils plus bas pour plus de transformations
 */
async function applyAggressiveSyntax(content, config) {
  let modified = content;
  let modifications = 0;

  // Découpage agressif phrases longues (>80 chars au lieu de >120)
  if (config.aggressiveSentenceSplitting) {
    const sentences = modified.split('. ');
    const processedSentences = sentences.map(sentence => {
      if (sentence.length > 80 && Math.random() < (config.intensityLevel * 0.7)) {
        const cutPoints = [
          { pattern: /, qui (.+)/, replacement: '. Celui-ci $1' },
          { pattern: /, que (.+)/, replacement: '. Cette solution $1' },
          { pattern: /, car (.+)/, replacement: '. En fait, $1' },
          { pattern: /, donc (.+)/, replacement: '. Du coup, $1' },
          { pattern: / et (.{20,})/, replacement: '. Aussi, $1' },
          { pattern: /, mais (.+)/, replacement: '. Par contre, $1' }
        ];

        for (const cutPoint of cutPoints) {
          if (sentence.match(cutPoint.pattern)) {
            modifications++;
            return sentence.replace(cutPoint.pattern, cutPoint.replacement);
          }
        }
      }
      return sentence;
    });
    modified = processedSentences.join('. ');
  }

  // Fusion agressive phrases courtes (<60 chars au lieu de <40)
  if (config.aggressiveSentenceMerging) {
    const sentences = modified.split('. ');
    const processedSentences = [];
    
    for (let i = 0; i < sentences.length; i++) {
      const current = sentences[i];
      const next = sentences[i + 1];
      
      if (current && current.length < 60 && next && next.length < 80 && Math.random() < (config.intensityLevel * 0.5)) {
        const connectors = [', du coup,', ', genre,', ', enfin,', ' et puis'];
        const connector = connectors[Math.floor(Math.random() * connectors.length)];
        processedSentences.push(current + connector + ' ' + next.toLowerCase());
        modifications++;
        i++; // Skip next sentence
      } else {
        processedSentences.push(current);
      }
    }
    modified = processedSentences.join('. ');
  }

  return { content: modified, modifications };
}

/**
 * APPLICATION MICRO-VARIATIONS
 * Changements subtiles mais nombreux
 */
async function applyMicroVariations(content, config) {
  let modified = content;
  let modifications = 0;

  const microPatterns = [
    // Intensificateurs
    { from: /\btrès (.+?)\b/g, to: 'super $1', probability: 0.4 },
    { from: /\bassez (.+?)\b/g, to: 'plutôt $1', probability: 0.5 },
    { from: /\bextrêmement\b/g, to: 'vraiment', probability: 0.6 },
    
    // Connecteurs basiques
    { from: /\bainsi\b/g, to: 'du coup', probability: 0.4 },
    { from: /\bpar conséquent\b/g, to: 'donc', probability: 0.7 },
    { from: /\bcependant\b/g, to: 'mais', probability: 0.3 },
    
    // Formulations casual
    { from: /\bde cette manière\b/g, to: 'comme ça', probability: 0.5 },
    { from: /\bafin de\b/g, to: 'pour', probability: 0.4 },
    { from: /\ben vue de\b/g, to: 'pour', probability: 0.6 }
  ];

  microPatterns.forEach(pattern => {
    if (Math.random() < (config.intensityLevel * pattern.probability)) {
      const before = modified;
      modified = modified.replace(pattern.from, pattern.to);
      if (modified !== before) modifications++;
    }
  });

  return { content: modified, modifications };
}

/**
 * APPLICATION PATTERNS FRANÇAIS SPÉCIFIQUES
 * Détection patterns français typiques LLM
 */
async function applyFrenchPatterns(content, config) {
  let modified = content;
  let modifications = 0;

  // Patterns français typiques LLM
  const frenchPatterns = [
    // Expressions trop soutenues
    { from: /\bil convient de noter que\b/gi, to: 'on peut dire que', probability: 0.8 },
    { from: /\bil est important de souligner que\b/gi, to: 'c\'est important de voir que', probability: 0.8 },
    { from: /\bdans ce contexte\b/gi, to: 'là-dessus', probability: 0.6 },
    { from: /\bpar ailleurs\b/gi, to: 'sinon', probability: 0.5 },
    { from: /\ben outre\b/gi, to: 'aussi', probability: 0.7 },
    
    // Formulations administratives
    { from: /\bil s'avère que\b/gi, to: 'en fait', probability: 0.6 },
    { from: /\btoutefois\b/gi, to: 'par contre', probability: 0.5 },
    { from: /\bnéanmoins\b/gi, to: 'quand même', probability: 0.7 }
  ];

  frenchPatterns.forEach(pattern => {
    if (Math.random() < (config.intensityLevel * pattern.probability)) {
      const before = modified;
      modified = modified.replace(pattern.from, pattern.to);
      if (modified !== before) modifications++;
    }
  });

  return { content: modified, modifications };
}

/**
 * APPLICATION CASUALISATION INTENSIVE
 * Rendre le vocabulaire plus décontracté
 */
async function applyCasualization(content, config) {
  let modified = content;
  let modifications = 0;

  const casualizations = [
    // Verbes formels → casual
    { from: /\boptimiser\b/gi, to: 'améliorer', probability: 0.7 },
    { from: /\beffectuer\b/gi, to: 'faire', probability: 0.8 },
    { from: /\bréaliser\b/gi, to: 'faire', probability: 0.6 },
    { from: /\bmettre en œuvre\b/gi, to: 'faire', probability: 0.7 },
    
    // Adjectifs formels → casual
    { from: /\bexceptionnel\b/gi, to: 'super', probability: 0.4 },
    { from: /\bremarquable\b/gi, to: 'pas mal', probability: 0.5 },
    { from: /\bconsidérable\b/gi, to: 'important', probability: 0.6 },
    { from: /\bsubstantiel\b/gi, to: 'important', probability: 0.8 },
    
    // Expressions formelles → casual
    { from: /\bde manière significative\b/gi, to: 'pas mal', probability: 0.6 },
    { from: /\ben définitive\b/gi, to: 'au final', probability: 0.7 },
    { from: /\bdans l'ensemble\b/gi, to: 'globalement', probability: 0.5 }
  ];

  casualizations.forEach(casual => {
    if (Math.random() < (config.intensityLevel * casual.probability)) {
      const before = modified;
      modified = modified.replace(casual.from, casual.to);
      if (modified !== before) modifications++;
    }
  });

  return { content: modified, modifications };
}

/**
 * APPLICATION CONNECTEURS CASUAL
 * Connecteurs très familiers
 */
async function applyCasualConnectors(content, config) {
  let modified = content;
  let modifications = 0;

  const casualConnectors = [
    { from: /\. De plus,/g, to: '. Genre,', probability: 0.3 },
    { from: /\. En outre,/g, to: '. Puis,', probability: 0.4 },
    { from: /\. Par ailleurs,/g, to: '. Sinon,', probability: 0.3 },
    { from: /\. Cependant,/g, to: '. Mais bon,', probability: 0.4 },
    { from: /\. Néanmoins,/g, to: '. Ceci dit,', probability: 0.5 },
    { from: /\. Ainsi,/g, to: '. Du coup,', probability: 0.6 }
  ];

  casualConnectors.forEach(connector => {
    if (Math.random() < (config.intensityLevel * connector.probability)) {
      const before = modified;
      modified = modified.replace(connector.from, connector.to);
      if (modified !== before) modifications++;
    }
  });

  return { content: modified, modifications };
}

/**
 * APPLICATION IMPERFECTIONS HUMAINES
 * Injection d'imperfections réalistes
 */
async function applyHumanImperfections(content, config) {
  let modified = content;
  let modifications = 0;

  // Répétitions vocabulaire
  if (config.vocabularyRepetitions && Math.random() < (config.intensityLevel * 0.4)) {
    const repetitionWords = ['vraiment', 'bien', 'assez', 'plutôt', 'super'];
    const word = repetitionWords[Math.floor(Math.random() * repetitionWords.length)];
    const sentences = modified.split('. ');
    if (sentences.length > 2) {
      sentences[1] = word + ' ' + sentences[1];
      modified = sentences.join('. ');
      modifications++;
    }
  }

  // Hésitations naturelles
  if (config.naturalHesitations && Math.random() < (config.intensityLevel * 0.2)) {
    const hesitations = ['... enfin', '... disons', '... bon'];
    const hesitation = hesitations[Math.floor(Math.random() * hesitations.length)];
    const words = modified.split(' ');
    const insertPos = Math.floor(words.length * 0.6);
    words.splice(insertPos, 0, hesitation);
    modified = words.join(' ');
    modifications++;
  }

  // Expressions informelles
  if (config.informalExpressions && Math.random() < (config.intensityLevel * 0.3)) {
    const informalReplacements = [
      { from: /\bc'est bien\b/gi, to: 'c\'est sympa', probability: 0.4 },
      { from: /\bc'est intéressant\b/gi, to: 'c\'est pas mal', probability: 0.5 },
      { from: /\bc'est efficace\b/gi, to: 'ça marche bien', probability: 0.4 }
    ];

    informalReplacements.forEach(replacement => {
      if (Math.random() < replacement.probability) {
        const before = modified;
        modified = modified.replace(replacement.from, replacement.to);
        if (modified !== before) modifications++;
      }
    });
  }

  return { content: modified, modifications };
}

/**
 * APPLICATION QUESTIONS RHÉTORIQUES
 * Injection questions pour engagement
 */
async function applyQuestionInjection(content, config) {
  let modified = content;
  let modifications = 0;

  if (Math.random() < (config.intensityLevel * 0.3)) {
    const sentences = modified.split('. ');
    if (sentences.length > 3) {
      const questionTemplates = [
        'Mais pourquoi est-ce important ?',
        'Comment faire alors ?',
        'Que faut-il retenir ?',
        'Est-ce vraiment efficace ?'
      ];
      
      const question = questionTemplates[Math.floor(Math.random() * questionTemplates.length)];
      const insertPos = Math.floor(sentences.length / 2);
      sentences.splice(insertPos, 0, question);
      modified = sentences.join('. ');
      modifications++;
    }
  }

  return { content: modified, modifications };
}

/**
 * APPLICATION RESTRUCTURATION INTELLIGENTE
 * Réorganisation structure générale
 */
async function applyIntelligentRestructuring(content, config) {
  let modified = content;
  let modifications = 0;

  // Cassage paragraphes longs
  if (config.paragraphBreaking && modified.length > 400) {
    const sentences = modified.split('. ');
    if (sentences.length > 6) {
      const breakPoint = Math.floor(sentences.length / 2);
      sentences[breakPoint] = sentences[breakPoint] + '\n\n';
      modified = sentences.join('. ');
      modifications++;
    }
  }

  // Injection redondances naturelles
  if (config.redundancyInjection && Math.random() < (config.intensityLevel * 0.2)) {
    const redundancies = ['comme je le disais', 'encore une fois', 'je le répète'];
    const redundancy = redundancies[Math.floor(Math.random() * redundancies.length)];
    const sentences = modified.split('. ');
    if (sentences.length > 2) {
      sentences[sentences.length - 2] = redundancy + ', ' + sentences[sentences.length - 2];
      modified = sentences.join('. ');
      modifications++;
    }
  }

  return { content: modified, modifications };
}

// ============= EXPORTS =============
module.exports = {
  applyPatternBreakingLayer,
  applySyntaxVariation,
  applyLLMFingerprints,
  applyNaturalConnectors,
  validatePatternBreakingQuality,
  applyAggressiveSyntax,
  applyMicroVariations,
  applyFrenchPatterns,
  applyCasualization,
  applyCasualConnectors,
  applyHumanImperfections,
  applyQuestionInjection,
  applyIntelligentRestructuring,
  DEFAULT_CONFIG
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pipeline/PipelineExecutor.js                            │
└────────────────────────────────────────────────────────────────────┘
*/

/**
 * PipelineExecutor.js
 *
 * Moteur d'exécution des pipelines modulaires flexibles.
 * Orchestre l'exécution séquentielle des modules avec gestion d'état.
 */

const { logSh, tracer } = require('../ErrorReporting');
const { PipelineDefinition } = require('./PipelineDefinition');
const { getPersonalities, readInstructionsData, selectPersonalityWithAI } = require('../BrainConfig');

// Modules d'exécution
const { generateSimpleContent } = require('../selective-enhancement/SelectiveUtils');
const { SelectiveCore } = require('../selective-enhancement/SelectiveCore');
const { AdversarialCore } = require('../adversarial-generation/AdversarialCore');
const { HumanSimulationCore } = require('../human-simulation/HumanSimulationCore');
const { PatternBreakingCore } = require('../pattern-breaking/PatternBreakingCore');

/**
 * Classe PipelineExecutor
 */
class PipelineExecutor {
  constructor() {
    this.currentContent = null;
    this.executionLog = [];
    this.checkpoints = [];
    this.metadata = {
      startTime: null,
      endTime: null,
      totalDuration: 0,
      personality: null
    };
  }

  /**
   * Exécute un pipeline complet
   */
  async execute(pipelineConfig, rowNumber, options = {}) {
    return tracer.run('PipelineExecutor.execute', async () => {
      logSh(`🚀 Démarrage pipeline "${pipelineConfig.name}" (${pipelineConfig.pipeline.length} étapes)`, 'INFO');

      // Validation
      const validation = PipelineDefinition.validate(pipelineConfig);
      if (!validation.valid) {
        throw new Error(`Pipeline invalide: ${validation.errors.join(', ')}`);
      }

      this.metadata.startTime = Date.now();
      this.executionLog = [];
      this.checkpoints = [];

      // Charger les données
      const csvData = await this.loadData(rowNumber);

      // Exécuter les étapes
      const enabledSteps = pipelineConfig.pipeline.filter(s => s.enabled !== false);

      for (let i = 0; i < enabledSteps.length; i++) {
        const step = enabledSteps[i];

        try {
          logSh(`▶ Étape ${step.step}/${pipelineConfig.pipeline.length}: ${step.module} (${step.mode})`, 'INFO');

          const stepStartTime = Date.now();
          const result = await this.executeStep(step, csvData, options);
          const stepDuration = Date.now() - stepStartTime;

          // Log l'étape
          this.executionLog.push({
            step: step.step,
            module: step.module,
            mode: step.mode,
            intensity: step.intensity,
            duration: stepDuration,
            modifications: result.modifications || 0,
            success: true,
            timestamp: new Date().toISOString()
          });

          // Mise à jour du contenu
          if (result.content) {
            this.currentContent = result.content;
          }

          // Checkpoint si demandé
          if (step.saveCheckpoint) {
            this.checkpoints.push({
              step: step.step,
              content: this.currentContent,
              timestamp: new Date().toISOString()
            });
            logSh(`💾 Checkpoint sauvegardé (étape ${step.step})`, 'DEBUG');
          }

          logSh(`✔ Étape ${step.step} terminée (${stepDuration}ms, ${result.modifications || 0} modifs)`, 'INFO');

        } catch (error) {
          logSh(`✖ Erreur étape ${step.step}: ${error.message}`, 'ERROR');

          this.executionLog.push({
            step: step.step,
            module: step.module,
            mode: step.mode,
            success: false,
            error: error.message,
            timestamp: new Date().toISOString()
          });

          // Propager l'erreur ou continuer selon options
          if (options.stopOnError !== false) {
            throw error;
          }
        }
      }

      this.metadata.endTime = Date.now();
      this.metadata.totalDuration = this.metadata.endTime - this.metadata.startTime;

      logSh(`✅ Pipeline terminé: ${this.metadata.totalDuration}ms`, 'INFO');

      return {
        success: true,
        finalContent: this.currentContent,
        executionLog: this.executionLog,
        checkpoints: this.checkpoints,
        metadata: {
          ...this.metadata,
          pipelineName: pipelineConfig.name,
          totalSteps: enabledSteps.length,
          successfulSteps: this.executionLog.filter(l => l.success).length
        }
      };
    }, { pipelineName: pipelineConfig.name, rowNumber });
  }

  /**
   * Charge les données depuis Google Sheets
   */
  async loadData(rowNumber) {
    return tracer.run('PipelineExecutor.loadData', async () => {
      const csvData = await readInstructionsData(rowNumber);

      // Charger personnalité si besoin
      const personalities = await getPersonalities();
      const personality = await selectPersonalityWithAI(
        csvData.mc0,
        csvData.t0,
        personalities
      );

      csvData.personality = personality;
      this.metadata.personality = personality.nom;

      logSh(`📊 Données chargées: ${csvData.mc0}, personnalité: ${personality.nom}`, 'DEBUG');

      return csvData;
    }, { rowNumber });
  }

  /**
   * Exécute une étape individuelle
   */
  async executeStep(step, csvData, options) {
    return tracer.run(`PipelineExecutor.executeStep.${step.module}`, async () => {

      switch (step.module) {
        case 'generation':
          return await this.runGeneration(step, csvData);

        case 'selective':
          return await this.runSelective(step, csvData);

        case 'adversarial':
          return await this.runAdversarial(step, csvData);

        case 'human':
          return await this.runHumanSimulation(step, csvData);

        case 'pattern':
          return await this.runPatternBreaking(step, csvData);

        default:
          throw new Error(`Module inconnu: ${step.module}`);
      }

    }, { step: step.step, module: step.module, mode: step.mode });
  }

  /**
   * Exécute la génération initiale
   */
  async runGeneration(step, csvData) {
    return tracer.run('PipelineExecutor.runGeneration', async () => {

      if (this.currentContent) {
        logSh('⚠️ Contenu déjà généré, génération ignorée', 'WARN');
        return { content: this.currentContent, modifications: 0 };
      }

      // Génération simple avec SelectiveUtils
      const result = await generateSimpleContent(
        csvData,
        csvData.personality,
        { source: 'pipeline_executor' }
      );

      logSh(`✓ Génération: ${Object.keys(result).length} éléments créés`, 'DEBUG');

      return {
        content: result,
        modifications: Object.keys(result).length
      };

    }, { mode: step.mode });
  }

  /**
   * Exécute l'enhancement sélectif
   */
  async runSelective(step, csvData) {
    return tracer.run('PipelineExecutor.runSelective', async () => {

      if (!this.currentContent) {
        throw new Error('Aucun contenu à améliorer. Génération requise avant selective enhancement');
      }

      const selectiveCore = new SelectiveCore();

      // Configuration de la couche
      const config = {
        stack: step.mode,
        intensity: step.intensity || 1.0,
        ...step.parameters
      };

      const result = await selectiveCore.applyStack(
        this.currentContent,
        csvData,
        csvData.personality,
        config
      );

      logSh(`✓ Selective: ${result.modificationsCount} modifications`, 'DEBUG');

      return {
        content: result.content,
        modifications: result.modificationsCount
      };

    }, { mode: step.mode, intensity: step.intensity });
  }

  /**
   * Exécute l'adversarial generation
   */
  async runAdversarial(step, csvData) {
    return tracer.run('PipelineExecutor.runAdversarial', async () => {

      if (!this.currentContent) {
        throw new Error('Aucun contenu à traiter. Génération requise avant adversarial');
      }

      if (step.mode === 'none') {
        logSh('Adversarial mode = none, ignoré', 'DEBUG');
        return { content: this.currentContent, modifications: 0 };
      }

      const adversarialCore = new AdversarialCore();

      const config = {
        mode: step.mode,
        detector: step.parameters?.detector || 'general',
        method: step.parameters?.method || 'regeneration',
        intensity: step.intensity || 1.0
      };

      const result = await adversarialCore.applyMode(
        this.currentContent,
        csvData,
        csvData.personality,
        config
      );

      logSh(`✓ Adversarial: ${result.modificationsCount} modifications`, 'DEBUG');

      return {
        content: result.content,
        modifications: result.modificationsCount
      };

    }, { mode: step.mode, detector: step.parameters?.detector });
  }

  /**
   * Exécute la simulation humaine
   */
  async runHumanSimulation(step, csvData) {
    return tracer.run('PipelineExecutor.runHumanSimulation', async () => {

      if (!this.currentContent) {
        throw new Error('Aucun contenu à traiter. Génération requise avant human simulation');
      }

      if (step.mode === 'none') {
        logSh('Human simulation mode = none, ignoré', 'DEBUG');
        return { content: this.currentContent, modifications: 0 };
      }

      const humanCore = new HumanSimulationCore();

      const config = {
        mode: step.mode,
        intensity: step.intensity || 1.0,
        fatigueLevel: step.parameters?.fatigueLevel || 0.5,
        errorRate: step.parameters?.errorRate || 0.3
      };

      const result = await humanCore.applyMode(
        this.currentContent,
        csvData,
        csvData.personality,
        config
      );

      logSh(`✓ Human Simulation: ${result.modificationsCount} modifications`, 'DEBUG');

      return {
        content: result.content,
        modifications: result.modificationsCount
      };

    }, { mode: step.mode, intensity: step.intensity });
  }

  /**
   * Exécute le pattern breaking
   */
  async runPatternBreaking(step, csvData) {
    return tracer.run('PipelineExecutor.runPatternBreaking', async () => {

      if (!this.currentContent) {
        throw new Error('Aucun contenu à traiter. Génération requise avant pattern breaking');
      }

      if (step.mode === 'none') {
        logSh('Pattern breaking mode = none, ignoré', 'DEBUG');
        return { content: this.currentContent, modifications: 0 };
      }

      const patternCore = new PatternBreakingCore();

      const config = {
        mode: step.mode,
        intensity: step.intensity || 1.0,
        focus: step.parameters?.focus || 'both'
      };

      const result = await patternCore.applyMode(
        this.currentContent,
        csvData,
        csvData.personality,
        config
      );

      logSh(`✓ Pattern Breaking: ${result.modificationsCount} modifications`, 'DEBUG');

      return {
        content: result.content,
        modifications: result.modificationsCount
      };

    }, { mode: step.mode, intensity: step.intensity });
  }

  /**
   * Obtient le contenu actuel
   */
  getCurrentContent() {
    return this.currentContent;
  }

  /**
   * Obtient le log d'exécution
   */
  getExecutionLog() {
    return this.executionLog;
  }

  /**
   * Obtient les checkpoints sauvegardés
   */
  getCheckpoints() {
    return this.checkpoints;
  }

  /**
   * Obtient les métadonnées d'exécution
   */
  getMetadata() {
    return this.metadata;
  }

  /**
   * Reset l'état de l'executor
   */
  reset() {
    this.currentContent = null;
    this.executionLog = [];
    this.checkpoints = [];
    this.metadata = {
      startTime: null,
      endTime: null,
      totalDuration: 0,
      personality: null
    };
  }
}

module.exports = { PipelineExecutor };


/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/ElementExtraction.js                                    │
└────────────────────────────────────────────────────────────────────┘
*/

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

// 🔄 NODE.JS IMPORTS
const { logSh } = require('./ErrorReporting');

// ============= 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 fullMatch = match[1]; // Ex: "Titre_H1_1{{T0}}" ou "Titre_H3_3{{MC+1_3}}"
      
      // Séparer nom du tag et variables
      const nameMatch = fullMatch.match(/^([^{]+)/);
      const variablesMatch = fullMatch.match(/\{\{([^}]+)\}\}/g);
      
      // FIX REGEX INSTRUCTIONS - Enlever d'abord les {{variables}} puis chercher {instructions}
      const withoutVariables = fullMatch.replace(/\{\{[^}]+\}\}/g, '');
      const instructionsMatch = withoutVariables.match(/\{([^}]+)\}/);

      let tagName = nameMatch ? nameMatch[1].trim() : fullMatch.split('{')[0];

      // NETTOYAGE: Enlever <strong>, </strong> du nom du tag
      tagName = tagName.replace(/<\/?strong>/g, '');

      // TAG PUR (sans variables)
      const pureTag = `|${tagName}|`;
      
      // RÉSOUDRE le contenu des variables
      const resolvedContent = resolveVariablesContent(variablesMatch, csvData);
      
      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: instructionsMatch ? instructionsMatch[1] : null,
        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');
    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);
      await logSh(`Prompt créé: ${prompt}`, 'DEBUG');
      
      // 🔄 NODE.JS : Import callOpenAI depuis LLM manager
      const { callLLM } = require('./LLMManager');
      const content = await callLLM('openai', prompt, {}, csvData.personality);
      
      await logSh(`Contenu reçu: ${content}`, 'DEBUG');
      
      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) {
  const hierarchy = {};
  
  elements.forEach(element => {
    const structure = parseElementStructure(element);
    const path = structure.hierarchyPath;
    
    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
    } else if (structure.type === 'Txt') {
      hierarchy[path].text = structure;
    } else if (structure.type === 'Intro') {
      hierarchy[path].text = structure;  
    } else if (structure.type === 'Faq') {
      hierarchy[path].questions.push(structure);
    }
  });
  
  // ← LIGNE COMPILÉE
  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('Correspondances: ' + mappingSummary, '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
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/MissingKeywords.js                                      │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: MissingKeywords.js - Version Node.js
// Description: Génération automatique des mots-clés manquants
// ========================================

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

/**
 * Génère automatiquement les mots-clés manquants pour les éléments non définis
 * @param {Array} elements - Liste des éléments extraits
 * @param {Object} csvData - Données CSV avec personnalité
 * @returns {Object} Éléments mis à jour avec nouveaux mots-clés
 */
async function generateMissingKeywords(elements, csvData) {
  logSh('>>> GÉNÉRATION MOTS-CLÉS MANQUANTS <<<', 'INFO');
  
  // 1. IDENTIFIER tous les éléments manquants
  const missingElements = [];
  elements.forEach(element => {
    if (element.resolvedContent.includes('non défini') || 
        element.resolvedContent.includes('non résolu') || 
        element.resolvedContent.trim() === '') {
      
      missingElements.push({
        tag: element.originalTag,
        name: element.name,
        type: element.type,
        currentContent: element.resolvedContent,
        context: getElementContext(element, elements, csvData)
      });
    }
  });
  
  if (missingElements.length === 0) {
    logSh('Aucun mot-clé manquant détecté', 'INFO');
    return {};
  }
  
  logSh(`${missingElements.length} mots-clés manquants détectés`, 'INFO');
  
  // 2. ANALYSER le contexte global disponible
  const contextAnalysis = analyzeAvailableContext(elements, csvData);
  
  // 3. GÉNÉRER tous les manquants en UN SEUL appel IA
  const generatedKeywords = await callOpenAIForMissingKeywords(missingElements, contextAnalysis, csvData);
  
  // 4. METTRE À JOUR les éléments avec les nouveaux mots-clés
  const updatedElements = updateElementsWithKeywords(elements, generatedKeywords);
  
  logSh(`Mots-clés manquants générés: ${Object.keys(generatedKeywords).length}`, 'INFO');
  return updatedElements;
}

/**
 * Analyser le contexte disponible pour guider la génération
 * @param {Array} elements - Tous les éléments
 * @param {Object} csvData - Données CSV
 * @returns {Object} Analyse contextuelle
 */
function analyzeAvailableContext(elements, csvData) {
  const availableKeywords = [];
  const availableContent = [];
  
  // Récupérer tous les mots-clés/contenu déjà disponibles
  elements.forEach(element => {
    if (element.resolvedContent && 
        !element.resolvedContent.includes('non défini') && 
        !element.resolvedContent.includes('non résolu') &&
        element.resolvedContent.trim() !== '') {
      
      if (element.type.includes('titre')) {
        availableKeywords.push(element.resolvedContent);
      } else {
        availableContent.push(element.resolvedContent.substring(0, 100));
      }
    }
  });
  
  return {
    mainKeyword: csvData.mc0,
    mainTitle: csvData.t0,
    availableKeywords: availableKeywords,
    availableContent: availableContent,
    theme: csvData.mc0, // Thème principal
    businessContext: "Autocollant.fr - signalétique personnalisée, plaques"
  };
}

/**
 * Obtenir le contexte spécifique d'un élément
 * @param {Object} element - Élément à analyser
 * @param {Array} allElements - Tous les éléments
 * @param {Object} csvData - Données CSV
 * @returns {Object} Contexte de l'élément
 */
function getElementContext(element, allElements, csvData) {
  const context = {
    elementType: element.type,
    hierarchyLevel: element.name,
    nearbyElements: []
  };
  
  // Trouver les éléments proches dans la hiérarchie
  const elementParts = element.name.split('_');
  if (elementParts.length >= 2) {
    const baseLevel = elementParts.slice(0, 2).join('_'); // Ex: "Titre_H3"
    
    allElements.forEach(otherElement => {
      if (otherElement.name.startsWith(baseLevel) && 
          otherElement.resolvedContent && 
          !otherElement.resolvedContent.includes('non défini')) {
        
        context.nearbyElements.push(otherElement.resolvedContent);
      }
    });
  }
  
  return context;
}

/**
 * Appel IA pour générer tous les mots-clés manquants en un seul batch
 * @param {Array} missingElements - Éléments manquants
 * @param {Object} contextAnalysis - Analyse contextuelle
 * @param {Object} csvData - Données CSV avec personnalité
 * @returns {Object} Mots-clés générés
 */
async function callOpenAIForMissingKeywords(missingElements, contextAnalysis, csvData) {
  const personality = csvData.personality;
  
  let prompt = `Tu es ${personality.nom} (${personality.description}). Style: ${personality.style}

MISSION: GÉNÈRE ${missingElements.length} MOTS-CLÉS/EXPRESSIONS MANQUANTS pour ${contextAnalysis.mainKeyword}

CONTEXTE:
- Sujet: ${contextAnalysis.mainKeyword}
- Entreprise: Autocollant.fr (signalétique)
- Mots-clés existants: ${contextAnalysis.availableKeywords.slice(0, 3).join(', ')}

ÉLÉMENTS MANQUANTS:
`;

  missingElements.forEach((missing, index) => {
    prompt += `${index + 1}. [${missing.name}] → Mot-clé SEO\n`;
  });
  
  prompt += `\nCONSIGNES:
- Thème: ${contextAnalysis.mainKeyword}
- Mots-clés SEO naturels
- Varie les termes
- Évite répétitions

FORMAT:
[${missingElements[0].name}]
mot-clé

[${missingElements[1] ? missingElements[1].name : 'exemple'}]
mot-clé

etc...`;

  try {
    logSh('Génération mots-clés manquants...', 'DEBUG');
    
    // Utilisation du LLM Manager avec fallback
    const response = await callLLM('openai', prompt, {
      temperature: 0.7,
      maxTokens: 2000
    }, personality);
    
    // Parser la réponse
    const generatedKeywords = parseMissingKeywordsResponse(response, missingElements);
    
    return generatedKeywords;
    
  } catch (error) {
    logSh(`❌ FATAL: Génération mots-clés manquants échouée: ${error}`, 'ERROR');
    throw new Error(`FATAL: Génération mots-clés LLM impossible - arrêt du workflow: ${error}`);
  }
}

/**
 * Parser la réponse IA pour extraire les mots-clés générés
 * @param {string} response - Réponse de l'IA
 * @param {Array} missingElements - Éléments manquants
 * @returns {Object} Mots-clés parsés
 */
function parseMissingKeywordsResponse(response, missingElements) {
  const results = {};
  
  const regex = /\[([^\]]+)\]\s*\n([^[]*?)(?=\n\[|$)/gs;
  let match;
  
  while ((match = regex.exec(response)) !== null) {
    const elementName = match[1].trim();
    const generatedKeyword = match[2].trim();
    
    results[elementName] = generatedKeyword;
    
    logSh(`✓ Mot-clé généré [${elementName}]: "${generatedKeyword}"`, 'DEBUG');
  }
  
  // VALIDATION: Vérifier qu'on a au moins récupéré des résultats (tolérer doublons)
  const uniqueNames = [...new Set(missingElements.map(e => e.name))];
  const parsedCount = Object.keys(results).length;

  if (parsedCount === 0) {
    logSh(`❌ FATAL: Aucun mot-clé parsé`, 'ERROR');
    throw new Error(`FATAL: Parsing mots-clés échoué complètement - arrêt du workflow`);
  }

  // Warning si doublons détectés (mais on continue)
  if (missingElements.length > uniqueNames.length) {
    const doublonsCount = missingElements.length - uniqueNames.length;
    logSh(`⚠️ ${doublonsCount} doublons détectés dans les tags XML (${uniqueNames.length} tags uniques)`, 'WARNING');
  }

  // Vérifier qu'on a au moins autant de résultats que de tags uniques
  if (parsedCount < uniqueNames.length) {
    const manquants = uniqueNames.length - parsedCount;
    logSh(`❌ FATAL: Parsing incomplet - ${manquants}/${uniqueNames.length} tags uniques non parsés`, 'ERROR');
    throw new Error(`FATAL: Parsing mots-clés incomplet (${manquants}/${uniqueNames.length} manquants) - arrêt du workflow`);
  }

  logSh(`✅ ${parsedCount} mots-clés parsés pour ${uniqueNames.length} tags uniques (${missingElements.length} éléments total)`, 'INFO');
  return results;
}

/**
 * Mettre à jour les éléments avec les nouveaux mots-clés générés
 * @param {Array} elements - Éléments originaux
 * @param {Object} generatedKeywords - Nouveaux mots-clés
 * @returns {Array} Éléments mis à jour
 */
function updateElementsWithKeywords(elements, generatedKeywords) {
  const updatedElements = elements.map(element => {
    const newKeyword = generatedKeywords[element.name];
    
    if (newKeyword) {
      return {
        ...element,
        resolvedContent: newKeyword
      };
    }
    
    return element;
  });
  
  logSh('Éléments mis à jour avec nouveaux mots-clés', 'INFO');
  return updatedElements;
}

// Exports CommonJS
module.exports = {
  generateMissingKeywords
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/generation/InitialGeneration.js                         │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// INITIAL GENERATION LAYER - GÉNÉRATION INITIALE MODULAIRE
// Responsabilité: Génération de contenu initial réutilisable
// LLM: Claude Sonnet-4 (précision et créativité équilibrée)
// ========================================

const { callLLM } = require('../LLMManager');
const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { chunkArray, sleep } = require('../selective-enhancement/SelectiveUtils');

/**
 * COUCHE GÉNÉRATION INITIALE MODULAIRE
 */
class InitialGenerationLayer {
  constructor() {
    this.name = 'InitialGeneration';
    this.defaultLLM = 'claude';
    this.priority = 0; // Priorité maximale - appliqué en premier
  }

  /**
   * MAIN METHOD - Générer contenu initial
   */
  async apply(contentStructure, config = {}) {
    return await tracer.run('InitialGenerationLayer.apply()', async () => {
      const {
        llmProvider = this.defaultLLM,
        temperature = 0.7,
        csvData = null,
        context = {}
      } = config;

      await tracer.annotate({
        initialGeneration: true,
        llmProvider,
        temperature,
        elementsCount: Object.keys(contentStructure).length,
        mc0: csvData?.mc0
      });

      const startTime = Date.now();
      logSh(`🎯 INITIAL GENERATION: Génération contenu initial (${llmProvider})`, 'INFO');
      logSh(`   📊 ${Object.keys(contentStructure).length} éléments à générer`, 'INFO');

      try {
        // Créer les éléments à générer à partir de la structure
        const elementsToGenerate = this.prepareElementsForGeneration(contentStructure, csvData);
        
        // Générer en chunks pour gérer les gros contenus
        const results = {};
        const chunks = chunkArray(Object.entries(elementsToGenerate), 4); // Chunks de 4 pour Claude
        
        for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
          const chunk = chunks[chunkIndex];
          
          try {
            logSh(`   📦 Chunk génération ${chunkIndex + 1}/${chunks.length}: ${chunk.length} éléments`, 'DEBUG');
            
            const generationPrompt = this.createInitialGenerationPrompt(chunk, csvData, config);
            
            const response = await callLLM(llmProvider, generationPrompt, {
              temperature,
              maxTokens: 4000
            }, csvData?.personality);
            
            const chunkResults = this.parseInitialGenerationResponse(response, chunk);
            Object.assign(results, chunkResults);
            
            logSh(`   ✅ Chunk génération ${chunkIndex + 1}: ${Object.keys(chunkResults).length} générés`, 'DEBUG');
            
            // Délai entre chunks
            if (chunkIndex < chunks.length - 1) {
              await sleep(2000);
            }
            
          } catch (error) {
            logSh(`   ❌ Chunk génération ${chunkIndex + 1} échoué: ${error.message}`, 'ERROR');
            
            // Fallback: contenu basique
            chunk.forEach(([tag, instruction]) => {
              results[tag] = this.createFallbackContent(tag, csvData);
            });
          }
        }

        const duration = Date.now() - startTime;
        const stats = {
          generated: Object.keys(results).length,
          total: Object.keys(contentStructure).length,
          generationRate: (Object.keys(results).length / Math.max(Object.keys(contentStructure).length, 1)) * 100,
          duration,
          llmProvider,
          temperature
        };

        logSh(`✅ INITIAL GENERATION TERMINÉE: ${stats.generated}/${stats.total} générés (${duration}ms)`, 'INFO');

        await tracer.event('Initial generation appliquée', stats);

        return { content: results, stats };

      } catch (error) {
        const duration = Date.now() - startTime;
        logSh(`❌ INITIAL GENERATION ÉCHOUÉE après ${duration}ms: ${error.message}`, 'ERROR');
        throw error;
      }
    }, { contentStructure: Object.keys(contentStructure), config });
  }

  /**
   * PRÉPARER ÉLÉMENTS POUR GÉNÉRATION
   */
  prepareElementsForGeneration(contentStructure, csvData) {
    const elements = {};
    
    // Convertir la structure en instructions de génération
    Object.entries(contentStructure).forEach(([tag, placeholder]) => {
      elements[tag] = {
        type: this.detectElementType(tag),
        instruction: this.createInstructionFromPlaceholder(placeholder, csvData),
        context: csvData?.mc0 || 'contenu personnalisé'
      };
    });
    
    return elements;
  }

  /**
   * DÉTECTER TYPE D'ÉLÉMENT
   */
  detectElementType(tag) {
    const tagLower = tag.toLowerCase();
    
    if (tagLower.includes('titre') || tagLower.includes('h1') || tagLower.includes('h2')) {
      return 'titre';
    } else if (tagLower.includes('intro') || tagLower.includes('introduction')) {
      return 'introduction';
    } else if (tagLower.includes('conclusion')) {
      return 'conclusion';
    } else if (tagLower.includes('faq') || tagLower.includes('question')) {
      return 'faq';
    } else {
      return 'contenu';
    }
  }

  /**
   * CRÉER INSTRUCTION À PARTIR DU PLACEHOLDER
   */
  createInstructionFromPlaceholder(placeholder, csvData) {
    // Si c'est déjà une vraie instruction, la garder
    if (typeof placeholder === 'string' && placeholder.length > 30) {
      return placeholder;
    }
    
    // Sinon, créer une instruction basique
    const mc0 = csvData?.mc0 || 'produit';
    return `Rédige un contenu professionnel et engageant sur ${mc0}`;
  }

  /**
   * CRÉER PROMPT GÉNÉRATION INITIALE
   */
  createInitialGenerationPrompt(chunk, csvData, config) {
    const personality = csvData?.personality;
    const mc0 = csvData?.mc0 || 'contenu personnalisé';
    
    let prompt = `MISSION: Génère du contenu SEO initial de haute qualité.

CONTEXTE: ${mc0} - Article optimisé SEO
${personality ? `PERSONNALITÉ: ${personality.nom} (${personality.style})` : ''}
TEMPÉRATURE: ${config.temperature || 0.7} (créativité équilibrée)

ÉLÉMENTS À GÉNÉRER:

${chunk.map(([tag, data], i) => `[${i + 1}] TAG: ${tag}
TYPE: ${data.type}
INSTRUCTION: ${data.instruction}
CONTEXTE: ${data.context}`).join('\n\n')}

CONSIGNES GÉNÉRATION:
- CRÉE du contenu original et engageant${personality ? ` avec le style ${personality.style}` : ''}
- INTÈGRE naturellement le mot-clé "${mc0}" 
- RESPECTE les bonnes pratiques SEO (mots-clés, structure)
- ADAPTE longueur selon type d'élément:
  * Titres: 8-15 mots
  * Introduction: 2-3 phrases (40-80 mots)
  * Contenu: 3-6 phrases (80-200 mots)  
  * Conclusion: 2-3 phrases (40-80 mots)
- ÉVITE contenu générique, sois spécifique et informatif
- UTILISE un ton professionnel mais accessible

VOCABULAIRE RECOMMANDÉ SELON CONTEXTE:
- Si signalétique: matériaux (dibond, aluminium), procédés (gravure, impression)
- Adapte selon le domaine du mot-clé principal

FORMAT RÉPONSE:
[1] Contenu généré pour premier élément
[2] Contenu généré pour deuxième élément
etc...

IMPORTANT: Réponse DIRECTE par les contenus générés, pas d'explication.`;

    return prompt;
  }

  /**
   * PARSER RÉPONSE GÉNÉRATION INITIALE
   */
  parseInitialGenerationResponse(response, chunk) {
    const results = {};
    const regex = /\[(\d+)\]\s*([^[]*?)(?=\n\[\d+\]|$)/gs;
    let match;
    let index = 0;
    
    while ((match = regex.exec(response)) && index < chunk.length) {
      let generatedContent = match[2].trim();
      const [tag] = chunk[index];
      
      // Nettoyer contenu généré
      generatedContent = this.cleanGeneratedContent(generatedContent);
      
      if (generatedContent && generatedContent.length > 10) {
        results[tag] = generatedContent;
        logSh(`✅ Généré [${tag}]: "${generatedContent.substring(0, 60)}..."`, 'DEBUG');
      } else {
        results[tag] = this.createFallbackContent(tag, chunk[index][1]);
        logSh(`⚠️ Fallback génération [${tag}]: contenu invalide`, 'WARNING');
      }
      
      index++;
    }
    
    // Compléter les manquants
    while (index < chunk.length) {
      const [tag, data] = chunk[index];
      results[tag] = this.createFallbackContent(tag, data);
      index++;
    }
    
    return results;
  }

  /**
   * NETTOYER CONTENU GÉNÉRÉ
   */
  cleanGeneratedContent(content) {
    if (!content) return content;
    
    // Supprimer préfixes indésirables
    content = content.replace(/^(voici\s+)?le\s+contenu\s+(généré|pour)\s*[:.]?\s*/gi, '');
    content = content.replace(/^(contenu|élément)\s+(généré|pour)\s*[:.]?\s*/gi, '');
    content = content.replace(/^(bon,?\s*)?(alors,?\s*)?/gi, '');
    
    // Nettoyer formatage
    content = content.replace(/\*\*[^*]+\*\*/g, ''); // Gras markdown
    content = content.replace(/\s{2,}/g, ' '); // Espaces multiples
    content = content.trim();
    
    return content;
  }

  /**
   * CRÉER CONTENU FALLBACK
   */
  createFallbackContent(tag, data) {
    const mc0 = data?.context || 'produit';
    const type = data?.type || 'contenu';
    
    switch (type) {
      case 'titre':
        return `${mc0.charAt(0).toUpperCase()}${mc0.slice(1)} de qualité professionnelle`;
      case 'introduction':
        return `Découvrez notre gamme complète de ${mc0}. Qualité premium et service personnalisé.`;
      case 'conclusion':
        return `Faites confiance à notre expertise pour votre ${mc0}. Contactez-nous pour plus d'informations.`;
      default:
        return `Notre ${mc0} répond à vos besoins avec des solutions adaptées et un service de qualité.`;
    }
  }
}

module.exports = { InitialGenerationLayer };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/selective-enhancement/SelectiveLayers.js                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// 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: 'openai', intensity: 0.7 }
    ],
    layersCount: 1
  },
  
  // Stack standard - Technique + Transitions
  standardEnhancement: {
    name: 'standardEnhancement',
    description: 'Amélioration technique et style (OpenAI + Mistral)',
    layers: [
      { type: 'technical', llm: 'openai', intensity: 0.9 },
      { type: 'style', llm: 'mistral', intensity: 0.8 }
    ],
    layersCount: 2
  },
  
  // Stack complet - Toutes couches séquentielles
  fullEnhancement: {
    name: 'fullEnhancement',
    description: 'Enhancement complet multi-LLM (OpenAI + Mistral)',
    layers: [
      { type: 'technical', llm: 'openai', intensity: 1.0 },
      { type: 'style', llm: 'mistral', intensity: 0.8 }
    ],
    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', intensity: 1.2 },
      { type: 'technical', llm: 'openai', 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', intensity: 1.1 },
      { type: 'technical', llm: 'openai', 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');

    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(`   🔧 Couche ${i + 1}/${stack.layersCount}: ${layer.type} (${layer.llm})`, '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;
          }

          const layerResult = await applySelectiveLayer(currentContent, layerConfig);
          
          currentContent = layerResult.content;
          
          stackStats.layers.push({
            order: i + 1,
            type: layer.type,
            llm: layer.llm,
            intensity: layer.intensity,
            elementsEnhanced: layerResult.stats.elementsEnhanced,
            duration: layerResult.stats.duration,
            success: !layerResult.stats.fallback
          });
          
          stackStats.totalModifications += layerResult.stats.elementsEnhanced;
          stackStats.totalDuration += layerResult.stats.duration;
          
          logSh(`   ✅ Couche ${layer.type}: ${layerResult.stats.elementsEnhanced} améliorations`, '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(`✅ STACK SELECTIVE ${stackName}: ${successfulLayers}/${stack.layersCount} couches | ${stackStats.totalModifications} modifications (${duration}ms)`, 'INFO');
      
      await tracer.event('Stack selective appliqué', { ...stackStats, totalDuration: duration });
      
      return {
        content: currentContent,
        stats: { ...stackStats, totalDuration: duration },
        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: 'openai',
          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', 
          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 
          }
        };
      }
      
      // 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 },
        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 },
        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
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/adversarial-generation/AdversarialLayers.js             │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// ADVERSARIAL LAYERS - COUCHES MODULAIRES
// Responsabilité: Couches adversariales composables et réutilisables
// Architecture: Fonction pipeline |> layer1 |> layer2 |> layer3
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { applyAdversarialLayer } = require('./AdversarialCore');

/**
 * COUCHE ANTI-GPTZEERO - Spécialisée contre GPTZero
 */
async function applyAntiGPTZeroLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: 'gptZero',
    intensity: options.intensity || 1.0,
    method: options.method || 'regeneration',
    ...options
  });
}

/**
 * COUCHE ANTI-ORIGINALITY - Spécialisée contre Originality.ai
 */
async function applyAntiOriginalityLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: 'originality',
    intensity: options.intensity || 1.1,
    method: options.method || 'hybrid',
    ...options
  });
}

/**
 * COUCHE ANTI-WINSTON - Spécialisée contre Winston AI
 */
async function applyAntiWinstonLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: 'winston',
    intensity: options.intensity || 0.9,
    method: options.method || 'enhancement',
    ...options
  });
}

/**
 * COUCHE GÉNÉRALE - Protection généraliste multi-détecteurs
 */
async function applyGeneralAdversarialLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: 'general',
    intensity: options.intensity || 0.8,
    method: options.method || 'hybrid',
    ...options
  });
}

/**
 * COUCHE LÉGÈRE - Modifications subtiles pour préserver qualité
 */
async function applyLightAdversarialLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: options.detectorTarget || 'general',
    intensity: 0.5,
    method: 'enhancement',
    preserveStructure: true,
    ...options
  });
}

/**
 * COUCHE INTENSIVE - Maximum anti-détection
 */
async function applyIntensiveAdversarialLayer(content, options = {}) {
  return await applyAdversarialLayer(content, {
    detectorTarget: options.detectorTarget || 'gptZero',
    intensity: 1.5,
    method: 'regeneration',
    preserveStructure: false,
    ...options
  });
}

/**
 * PIPELINE COMPOSABLE - Application séquentielle de couches
 */
async function applyLayerPipeline(content, layers = [], globalOptions = {}) {
  return await tracer.run('AdversarialLayers.applyLayerPipeline()', async () => {
    await tracer.annotate({
      layersPipeline: true,
      layersCount: layers.length,
      elementsCount: Object.keys(content).length
    });

    const startTime = Date.now();
    logSh(`🔄 PIPELINE COUCHES ADVERSARIALES: ${layers.length} couches`, 'INFO');

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

    try {
      for (let i = 0; i < layers.length; i++) {
        const layer = layers[i];
        const layerStartTime = Date.now();
        
        logSh(`   🎯 Couche ${i + 1}/${layers.length}: ${layer.name || layer.type || 'anonyme'}`, 'DEBUG');
        
        try {
          const layerResult = await applyLayerByConfig(currentContent, layer, globalOptions);
          
          currentContent = layerResult.content;
          
          const layerStats = {
            name: layer.name || `layer_${i + 1}`,
            type: layer.type,
            duration: Date.now() - layerStartTime,
            modificationsCount: layerResult.stats?.elementsModified || 0,
            success: true
          };
          
          pipelineStats.layers.push(layerStats);
          pipelineStats.totalModifications += layerStats.modificationsCount;
          
          logSh(`   ✅ ${layerStats.name}: ${layerStats.modificationsCount} modifs (${layerStats.duration}ms)`, 'DEBUG');
          
        } catch (error) {
          logSh(`   ❌ Couche ${i + 1} échouée: ${error.message}`, 'ERROR');
          
          pipelineStats.layers.push({
            name: layer.name || `layer_${i + 1}`,
            type: layer.type,
            duration: Date.now() - layerStartTime,
            success: false,
            error: error.message
          });
          
          // Continuer avec le contenu précédent si une couche échoue
          if (!globalOptions.stopOnError) {
            continue;
          } else {
            throw error;
          }
        }
      }

      pipelineStats.totalDuration = Date.now() - startTime;
      pipelineStats.success = pipelineStats.layers.every(layer => layer.success);

      logSh(`🔄 PIPELINE TERMINÉ: ${pipelineStats.totalModifications} modifs totales (${pipelineStats.totalDuration}ms)`, 'INFO');

      await tracer.event('Pipeline couches terminé', pipelineStats);

      return {
        content: currentContent,
        stats: pipelineStats,
        original: content
      };

    } catch (error) {
      pipelineStats.totalDuration = Date.now() - startTime;
      pipelineStats.success = false;
      
      logSh(`❌ PIPELINE COUCHES ÉCHOUÉ après ${pipelineStats.totalDuration}ms: ${error.message}`, 'ERROR');
      throw error;
    }
  }, { layers: layers.map(l => l.name || l.type), content: Object.keys(content) });
}

/**
 * COUCHES PRÉDÉFINIES - Configurations courantes
 */
const PREDEFINED_LAYERS = {
  // Stack défensif léger
  lightDefense: [
    { type: 'general', name: 'General Light', intensity: 0.6, method: 'enhancement' },
    { type: 'anti-gptZero', name: 'GPTZero Light', intensity: 0.5, method: 'enhancement' }
  ],
  
  // Stack défensif standard
  standardDefense: [
    { type: 'general', name: 'General Standard', intensity: 0.8, method: 'hybrid' },
    { type: 'anti-gptZero', name: 'GPTZero Standard', intensity: 0.9, method: 'enhancement' },
    { type: 'anti-originality', name: 'Originality Standard', intensity: 0.8, method: 'enhancement' }
  ],
  
  // Stack défensif intensif
  heavyDefense: [
    { type: 'general', name: 'General Heavy', intensity: 1.0, method: 'regeneration' },
    { type: 'anti-gptZero', name: 'GPTZero Heavy', intensity: 1.2, method: 'regeneration' },
    { type: 'anti-originality', name: 'Originality Heavy', intensity: 1.1, method: 'hybrid' },
    { type: 'anti-winston', name: 'Winston Heavy', intensity: 1.0, method: 'enhancement' }
  ],
  
  // Stack ciblé GPTZero
  gptZeroFocused: [
    { type: 'anti-gptZero', name: 'GPTZero Primary', intensity: 1.3, method: 'regeneration' },
    { type: 'general', name: 'General Support', intensity: 0.7, method: 'enhancement' }
  ],
  
  // Stack ciblé Originality
  originalityFocused: [
    { type: 'anti-originality', name: 'Originality Primary', intensity: 1.4, method: 'hybrid' },
    { type: 'general', name: 'General Support', intensity: 0.8, method: 'enhancement' }
  ]
};

/**
 * APPLIQUER STACK PRÉDÉFINI
 */
async function applyPredefinedStack(content, stackName, options = {}) {
  const stack = PREDEFINED_LAYERS[stackName];
  
  if (!stack) {
    throw new Error(`Stack prédéfini inconnu: ${stackName}. Disponibles: ${Object.keys(PREDEFINED_LAYERS).join(', ')}`);
  }
  
  logSh(`📦 APPLICATION STACK PRÉDÉFINI: ${stackName}`, 'INFO');
  
  return await applyLayerPipeline(content, stack, options);
}

/**
 * COUCHES ADAPTATIVES - S'adaptent selon le contenu
 */
async function applyAdaptiveLayers(content, options = {}) {
  const { 
    targetDetectors = ['gptZero', 'originality'],
    maxIntensity = 1.0,
    analysisMode = true 
  } = options;

  logSh(`🧠 COUCHES ADAPTATIVES: Analyse + adaptation auto`, 'INFO');

  // 1. Analyser le contenu pour détecter les risques
  const contentAnalysis = analyzeContentRisks(content);
  
  // 2. Construire pipeline adaptatif selon l'analyse
  const adaptiveLayers = [];
  
  // Niveau de base selon risque global
  const baseIntensity = Math.min(maxIntensity, contentAnalysis.globalRisk * 1.2);
  
  if (baseIntensity > 0.3) {
    adaptiveLayers.push({
      type: 'general',
      name: 'Adaptive Base',
      intensity: baseIntensity,
      method: baseIntensity > 0.7 ? 'hybrid' : 'enhancement'
    });
  }
  
  // Couches spécifiques selon détecteurs ciblés
  targetDetectors.forEach(detector => {
    const detectorRisk = contentAnalysis.detectorRisks[detector] || 0;
    
    if (detectorRisk > 0.4) {
      const intensity = Math.min(maxIntensity * 1.1, detectorRisk * 1.5);
      adaptiveLayers.push({
        type: `anti-${detector}`,
        name: `Adaptive ${detector}`,
        intensity,
        method: intensity > 0.8 ? 'regeneration' : 'enhancement'
      });
    }
  });
  
  logSh(`   🎯 ${adaptiveLayers.length} couches adaptatives générées`, 'DEBUG');
  
  if (adaptiveLayers.length === 0) {
    logSh(`   ✅ Contenu déjà optimal, aucune couche nécessaire`, 'INFO');
    return { content, stats: { adaptive: true, layersApplied: 0 }, original: content };
  }
  
  return await applyLayerPipeline(content, adaptiveLayers, options);
}

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

/**
 * Appliquer couche selon configuration
 */
async function applyLayerByConfig(content, layerConfig, globalOptions = {}) {
  const { type, intensity, method, ...layerOptions } = layerConfig;
  const options = { ...globalOptions, ...layerOptions, intensity, method };
  
  switch (type) {
    case 'general':
      return await applyGeneralAdversarialLayer(content, options);
    case 'anti-gptZero':
      return await applyAntiGPTZeroLayer(content, options);
    case 'anti-originality':
      return await applyAntiOriginalityLayer(content, options);
    case 'anti-winston':
      return await applyAntiWinstonLayer(content, options);
    case 'light':
      return await applyLightAdversarialLayer(content, options);
    case 'intensive':
      return await applyIntensiveAdversarialLayer(content, options);
    default:
      throw new Error(`Type de couche inconnu: ${type}`);
  }
}

/**
 * Analyser risques du contenu pour adaptation
 */
function analyzeContentRisks(content) {
  const analysis = {
    globalRisk: 0,
    detectorRisks: {},
    riskFactors: []
  };
  
  const allContent = Object.values(content).join(' ');
  
  // Risques génériques
  let riskScore = 0;
  
  // 1. Mots typiques IA
  const aiWords = ['optimal', 'comprehensive', 'seamless', 'robust', 'leverage', 'cutting-edge', 'furthermore', 'moreover'];
  const aiWordCount = aiWords.filter(word => allContent.toLowerCase().includes(word)).length;
  
  if (aiWordCount > 2) {
    riskScore += 0.3;
    analysis.riskFactors.push(`mots_ia: ${aiWordCount}`);
  }
  
  // 2. Structure uniforme
  const contentLengths = Object.values(content).map(c => c.length);
  const avgLength = contentLengths.reduce((a, b) => a + b, 0) / contentLengths.length;
  const variance = contentLengths.reduce((sum, len) => sum + Math.pow(len - avgLength, 2), 0) / contentLengths.length;
  const uniformity = 1 - (Math.sqrt(variance) / Math.max(avgLength, 1));
  
  if (uniformity > 0.8) {
    riskScore += 0.2;
    analysis.riskFactors.push(`uniformité: ${uniformity.toFixed(2)}`);
  }
  
  // 3. Connecteurs répétitifs
  const repetitiveConnectors = ['par ailleurs', 'en effet', 'de plus', 'cependant'];
  const connectorCount = repetitiveConnectors.filter(conn => 
    (allContent.match(new RegExp(conn, 'gi')) || []).length > 1
  ).length;
  
  if (connectorCount > 2) {
    riskScore += 0.2;
    analysis.riskFactors.push(`connecteurs_répétitifs: ${connectorCount}`);
  }
  
  analysis.globalRisk = Math.min(1, riskScore);
  
  // Risques spécifiques par détecteur
  analysis.detectorRisks = {
    gptZero: analysis.globalRisk + (uniformity > 0.7 ? 0.3 : 0),
    originality: analysis.globalRisk + (aiWordCount > 3 ? 0.4 : 0),
    winston: analysis.globalRisk + (connectorCount > 2 ? 0.2 : 0)
  };
  
  return analysis;
}

/**
 * Obtenir informations sur les stacks disponibles
 */
function getAvailableStacks() {
  return Object.keys(PREDEFINED_LAYERS).map(stackName => ({
    name: stackName,
    layersCount: PREDEFINED_LAYERS[stackName].length,
    description: getStackDescription(stackName),
    layers: PREDEFINED_LAYERS[stackName]
  }));
}

/**
 * Description des stacks prédéfinis
 */
function getStackDescription(stackName) {
  const descriptions = {
    lightDefense: 'Protection légère préservant la qualité',
    standardDefense: 'Protection équilibrée multi-détecteurs',
    heavyDefense: 'Protection maximale tous détecteurs',
    gptZeroFocused: 'Optimisation spécifique anti-GPTZero',
    originalityFocused: 'Optimisation spécifique anti-Originality.ai'
  };
  
  return descriptions[stackName] || 'Stack personnalisé';
}

module.exports = {
  // Couches individuelles
  applyAntiGPTZeroLayer,
  applyAntiOriginalityLayer,
  applyAntiWinstonLayer,
  applyGeneralAdversarialLayer,
  applyLightAdversarialLayer,
  applyIntensiveAdversarialLayer,
  
  // Pipeline et stacks
  applyLayerPipeline,              // ← MAIN ENTRY POINT PIPELINE
  applyPredefinedStack,            // ← MAIN ENTRY POINT STACKS
  applyAdaptiveLayers,             // ← MAIN ENTRY POINT ADAPTATIF
  
  // Utilitaires
  getAvailableStacks,
  analyzeContentRisks,
  PREDEFINED_LAYERS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/human-simulation/HumanSimulationLayers.js               │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: HumanSimulationLayers.js
// RESPONSABILITÉ: Stacks prédéfinis Human Simulation
// Compatible avec architecture modulaire existante
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { applyHumanSimulationLayer } = require('./HumanSimulationCore');

/**
 * STACKS PRÉDÉFINIS HUMAN SIMULATION
 * Configuration par niveau d'intensité
 */
const HUMAN_SIMULATION_STACKS = {
  
  // ========================================
  // SIMULATION LÉGÈRE - Pour tests et développement
  // ========================================
  lightSimulation: {
    name: 'lightSimulation',
    description: 'Simulation humaine légère - développement et tests',
    layersCount: 3,
    config: {
      fatigueEnabled: true,
      personalityErrorsEnabled: true, 
      temporalStyleEnabled: false,      // Désactivé en mode light
      imperfectionIntensity: 0.3,       // Faible intensité
      naturalRepetitions: true,
      qualityThreshold: 0.8,           // Seuil élevé
      maxModificationsPerElement: 2     // Limité à 2 modifs par élément
    },
    expectedImpact: {
      modificationsPerElement: '1-2',
      qualityPreservation: '95%',
      detectionReduction: '10-15%',
      executionTime: '+20%'
    }
  },

  // ========================================
  // SIMULATION STANDARD - Usage production normal
  // ========================================
  standardSimulation: {
    name: 'standardSimulation', 
    description: 'Simulation humaine standard - équilibre performance/qualité',
    layersCount: 3,
    config: {
      fatigueEnabled: true,
      personalityErrorsEnabled: true,
      temporalStyleEnabled: true,        // Activé
      imperfectionIntensity: 0.6,        // Intensité moyenne
      naturalRepetitions: true,
      qualityThreshold: 0.7,            // Seuil normal
      maxModificationsPerElement: 3      // 3 modifs max
    },
    expectedImpact: {
      modificationsPerElement: '2-3',
      qualityPreservation: '85%',
      detectionReduction: '25-35%',
      executionTime: '+40%'
    }
  },

  // ========================================
  // SIMULATION INTENSIVE - Maximum anti-détection
  // ========================================
  heavySimulation: {
    name: 'heavySimulation',
    description: 'Simulation humaine intensive - anti-détection maximale',
    layersCount: 3,
    config: {
      fatigueEnabled: true,
      personalityErrorsEnabled: true,
      temporalStyleEnabled: true,
      imperfectionIntensity: 0.9,        // Intensité élevée
      naturalRepetitions: true,
      qualityThreshold: 0.6,            // Seuil plus permissif
      maxModificationsPerElement: 5      // Jusqu'à 5 modifs
    },
    expectedImpact: {
      modificationsPerElement: '3-5',
      qualityPreservation: '75%',
      detectionReduction: '40-50%',
      executionTime: '+60%'
    }
  },

  // ========================================
  // SIMULATION ADAPTIVE - Intelligence contextuelle
  // ========================================
  adaptiveSimulation: {
    name: 'adaptiveSimulation',
    description: 'Simulation humaine adaptive - ajustement intelligent selon contexte',
    layersCount: 3,
    config: {
      fatigueEnabled: true,
      personalityErrorsEnabled: true,
      temporalStyleEnabled: true,
      imperfectionIntensity: 'adaptive',  // Calculé dynamiquement
      naturalRepetitions: true,
      qualityThreshold: 'adaptive',       // Ajusté selon complexité
      maxModificationsPerElement: 'adaptive', // Variable
      adaptiveLogic: true                 // Flag pour logique adaptive
    },
    expectedImpact: {
      modificationsPerElement: '1-4',
      qualityPreservation: '80-90%',
      detectionReduction: '30-45%',
      executionTime: '+45%'
    }
  },

  // ========================================
  // SIMULATION PERSONNALISÉE - Focus personnalité
  // ========================================
  personalityFocus: {
    name: 'personalityFocus',
    description: 'Focus erreurs personnalité - cohérence maximale',
    layersCount: 2,
    config: {
      fatigueEnabled: false,            // Désactivé
      personalityErrorsEnabled: true,
      temporalStyleEnabled: false,      // Désactivé
      imperfectionIntensity: 1.0,       // Focus sur personnalité
      naturalRepetitions: true,
      qualityThreshold: 0.75,
      maxModificationsPerElement: 3
    },
    expectedImpact: {
      modificationsPerElement: '2-3',
      qualityPreservation: '85%',
      detectionReduction: '20-30%',
      executionTime: '+25%'
    }
  },

  // ========================================
  // SIMULATION TEMPORELLE - Focus variations horaires
  // ========================================
  temporalFocus: {
    name: 'temporalFocus',
    description: 'Focus style temporel - variations selon heure',
    layersCount: 2,
    config: {
      fatigueEnabled: false,
      personalityErrorsEnabled: false,
      temporalStyleEnabled: true,        // Focus principal
      imperfectionIntensity: 0.8,
      naturalRepetitions: true,
      qualityThreshold: 0.75,
      maxModificationsPerElement: 3
    },
    expectedImpact: {
      modificationsPerElement: '1-3',
      qualityPreservation: '85%',
      detectionReduction: '15-25%',
      executionTime: '+20%'
    }
  }
};

/**
 * APPLICATION STACK PRÉDÉFINI
 * @param {object} content - Contenu à simuler
 * @param {string} stackName - Nom du stack
 * @param {object} options - Options additionnelles
 * @returns {object} - Résultat simulation
 */
async function applyPredefinedSimulation(content, stackName, options = {}) {
  return await tracer.run(`HumanSimulationLayers.applyPredefinedSimulation(${stackName})`, async () => {
    
    const stack = HUMAN_SIMULATION_STACKS[stackName];
    if (!stack) {
      throw new Error(`Stack Human Simulation non trouvé: ${stackName}`);
    }

    await tracer.annotate({
      stackName,
      stackDescription: stack.description,
      layersCount: stack.layersCount,
      contentElements: Object.keys(content).length
    });

    logSh(`🧠 APPLICATION STACK: ${stack.name}`, 'INFO');
    logSh(`   📝 ${stack.description}`, 'DEBUG');
    logSh(`   ⚙️ ${stack.layersCount} couches actives`, 'DEBUG');

    try {
      // Configuration fusionnée
      let finalConfig = { ...stack.config, ...options };

      // ========================================
      // LOGIQUE ADAPTIVE (si applicable)
      // ========================================
      if (stack.config.adaptiveLogic) {
        finalConfig = await applyAdaptiveLogic(content, finalConfig, options);
        logSh(`   🧠 Logique adaptive appliquée`, 'DEBUG');
      }

      // ========================================
      // APPLICATION SIMULATION PRINCIPALE
      // ========================================
      const simulationOptions = {
        ...finalConfig,
        elementIndex: options.elementIndex || 0,
        totalElements: options.totalElements || Object.keys(content).length,
        currentHour: options.currentHour || new Date().getHours(),
        csvData: options.csvData,
        stackName: stack.name
      };

      const result = await applyHumanSimulationLayer(content, simulationOptions);

      // ========================================
      // ENRICHISSEMENT RÉSULTAT
      // ========================================
      const enrichedResult = {
        ...result,
        stackInfo: {
          name: stack.name,
          description: stack.description,
          layersCount: stack.layersCount,
          expectedImpact: stack.expectedImpact,
          configUsed: finalConfig
        }
      };

      logSh(`✅ STACK ${stack.name} terminé: ${result.stats.totalModifications} modifications`, 'INFO');
      
      await tracer.event('Stack Human Simulation terminé', {
        stackName,
        success: !result.fallback,
        modifications: result.stats.totalModifications,
        qualityScore: result.qualityScore
      });

      return enrichedResult;

    } catch (error) {
      logSh(`❌ ERREUR STACK ${stack.name}: ${error.message}`, 'ERROR');
      
      await tracer.event('Stack Human Simulation échoué', {
        stackName,
        error: error.message
      });

      // Fallback gracieux
      return {
        content,
        stats: { fallbackUsed: true, error: error.message },
        fallback: true,
        stackInfo: { name: stack.name, error: error.message }
      };
    }

  }, { stackName, contentElements: Object.keys(content).length });
}

/**
 * LOGIQUE ADAPTIVE INTELLIGENTE
 * Ajuste la configuration selon le contexte
 */
async function applyAdaptiveLogic(content, config, options) {
  logSh('🧠 Application logique adaptive', 'DEBUG');

  const adaptedConfig = { ...config };

  // ========================================
  // 1. ANALYSE COMPLEXITÉ CONTENU
  // ========================================
  const totalText = Object.values(content).join(' ');
  const wordCount = totalText.split(/\s+/).length;
  const avgElementLength = wordCount / Object.keys(content).length;

  // ========================================
  // 2. AJUSTEMENT INTENSITÉ SELON COMPLEXITÉ
  // ========================================
  if (avgElementLength > 200) {
    // Contenu long = intensité réduite pour préserver qualité
    adaptedConfig.imperfectionIntensity = 0.5;
    adaptedConfig.qualityThreshold = 0.8;
    logSh('   📏 Contenu long détecté: intensité réduite', 'DEBUG');
  } else if (avgElementLength < 50) {
    // Contenu court = intensité augmentée
    adaptedConfig.imperfectionIntensity = 1.0;
    adaptedConfig.qualityThreshold = 0.6;
    logSh('   📏 Contenu court détecté: intensité augmentée', 'DEBUG');
  } else {
    // Contenu moyen = intensité équilibrée
    adaptedConfig.imperfectionIntensity = 0.7;
    adaptedConfig.qualityThreshold = 0.7;
  }

  // ========================================
  // 3. AJUSTEMENT SELON PERSONNALITÉ
  // ========================================
  const personality = options.csvData?.personality;
  if (personality) {
    const personalityName = personality.nom.toLowerCase();
    
    // Personnalités techniques = moins d'erreurs de personnalité
    if (['marc', 'amara', 'fabrice'].includes(personalityName)) {
      adaptedConfig.imperfectionIntensity *= 0.8;
      logSh('   🎭 Personnalité technique: intensité erreurs réduite', 'DEBUG');
    }
    
    // Personnalités créatives = plus d'erreurs stylistiques  
    if (['sophie', 'émilie', 'chloé'].includes(personalityName)) {
      adaptedConfig.imperfectionIntensity *= 1.2;
      logSh('   🎭 Personnalité créative: intensité erreurs augmentée', 'DEBUG');
    }
  }

  // ========================================
  // 4. AJUSTEMENT SELON HEURE
  // ========================================
  const currentHour = options.currentHour || new Date().getHours();
  
  if (currentHour >= 22 || currentHour <= 6) {
    // Nuit = plus de fatigue, moins de complexité
    adaptedConfig.fatigueEnabled = true;
    adaptedConfig.temporalStyleEnabled = true;
    adaptedConfig.imperfectionIntensity *= 1.3;
    logSh('   🌙 Période nocturne: simulation fatigue renforcée', 'DEBUG');
  } else if (currentHour >= 6 && currentHour <= 10) {
    // Matin = énergie, moins d'erreurs
    adaptedConfig.imperfectionIntensity *= 0.7;
    logSh('   🌅 Période matinale: intensité réduite', 'DEBUG');
  }

  // ========================================
  // 5. LIMITATION SÉCURITÉ
  // ========================================
  adaptedConfig.imperfectionIntensity = Math.max(0.2, Math.min(1.5, adaptedConfig.imperfectionIntensity));
  adaptedConfig.qualityThreshold = Math.max(0.5, Math.min(0.9, adaptedConfig.qualityThreshold));
  
  // Modifs max adaptées à la taille du contenu
  adaptedConfig.maxModificationsPerElement = Math.min(6, Math.max(1, Math.ceil(avgElementLength / 50)));

  logSh(`   🎯 Config adaptée: intensité=${adaptedConfig.imperfectionIntensity.toFixed(2)}, seuil=${adaptedConfig.qualityThreshold.toFixed(2)}`, 'DEBUG');

  return adaptedConfig;
}

/**
 * OBTENIR STACKS DISPONIBLES
 * @returns {array} - Liste des stacks avec métadonnées
 */
function getAvailableSimulationStacks() {
  return Object.values(HUMAN_SIMULATION_STACKS).map(stack => ({
    name: stack.name,
    description: stack.description,
    layersCount: stack.layersCount,
    expectedImpact: stack.expectedImpact,
    configPreview: {
      fatigueEnabled: stack.config.fatigueEnabled,
      personalityErrorsEnabled: stack.config.personalityErrorsEnabled,
      temporalStyleEnabled: stack.config.temporalStyleEnabled,
      intensity: stack.config.imperfectionIntensity
    }
  }));
}

/**
 * VALIDATION STACK
 * @param {string} stackName - Nom du stack à valider
 * @returns {object} - Résultat validation
 */
function validateSimulationStack(stackName) {
  const stack = HUMAN_SIMULATION_STACKS[stackName];
  
  if (!stack) {
    return {
      valid: false,
      error: `Stack '${stackName}' non trouvé`,
      availableStacks: Object.keys(HUMAN_SIMULATION_STACKS)
    };
  }

  // Validation configuration
  const configIssues = [];
  
  if (typeof stack.config.imperfectionIntensity === 'number' && 
      (stack.config.imperfectionIntensity < 0 || stack.config.imperfectionIntensity > 2)) {
    configIssues.push('intensité hors limites (0-2)');
  }
  
  if (typeof stack.config.qualityThreshold === 'number' && 
      (stack.config.qualityThreshold < 0.3 || stack.config.qualityThreshold > 1)) {
    configIssues.push('seuil qualité hors limites (0.3-1)');
  }

  return {
    valid: configIssues.length === 0,
    stack,
    issues: configIssues,
    recommendation: configIssues.length > 0 ? 
      'Corriger la configuration avant utilisation' : 
      'Stack prêt à utiliser'
  };
}

/**
 * RECOMMANDATION STACK AUTOMATIQUE
 * @param {object} context - Contexte { contentLength, personality, hour, goal }
 * @returns {string} - Nom du stack recommandé
 */
function recommendSimulationStack(context = {}) {
  const { contentLength, personality, hour, goal } = context;

  logSh('🤖 Recommandation stack automatique', 'DEBUG');

  // Priorité 1: Objectif spécifique
  if (goal === 'development') return 'lightSimulation';
  if (goal === 'maximum_stealth') return 'heavySimulation';
  if (goal === 'personality_focus') return 'personalityFocus';
  if (goal === 'temporal_focus') return 'temporalFocus';

  // Priorité 2: Complexité contenu
  if (contentLength > 2000) return 'lightSimulation'; // Contenu long = prudent
  if (contentLength < 300) return 'heavySimulation';  // Contenu court = intensif

  // Priorité 3: Personnalité
  if (personality) {
    const personalityName = personality.toLowerCase();
    if (['marc', 'amara', 'fabrice'].includes(personalityName)) {
      return 'standardSimulation'; // Techniques = équilibré
    }
    if (['sophie', 'chloé', 'émilie'].includes(personalityName)) {
      return 'personalityFocus'; // Créatives = focus personnalité
    }
  }

  // Priorité 4: Heure
  if (hour >= 22 || hour <= 6) return 'temporalFocus'; // Nuit = focus temporel
  if (hour >= 6 && hour <= 10) return 'lightSimulation'; // Matin = léger

  // Par défaut: adaptive pour intelligence contextuelle
  logSh('   🎯 Recommandation: adaptiveSimulation (par défaut)', 'DEBUG');
  return 'adaptiveSimulation';
}

// ============= EXPORTS =============
module.exports = {
  applyPredefinedSimulation,
  getAvailableSimulationStacks,
  validateSimulationStack,
  recommendSimulationStack,
  applyAdaptiveLogic,
  HUMAN_SIMULATION_STACKS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pattern-breaking/PatternBreakingLayers.js               │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: PatternBreakingLayers.js
// RESPONSABILITÉ: Stacks prédéfinis pour Pattern Breaking
// Configurations optimisées par cas d'usage
// ========================================

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

/**
 * CONFIGURATIONS PRÉDÉFINIES PATTERN BREAKING
 * Optimisées pour différents niveaux et cas d'usage
 */
const PATTERN_BREAKING_STACKS = {

  // ========================================
  // STACK LÉGER - Usage quotidien
  // ========================================
  lightPatternBreaking: {
    name: 'Light Pattern Breaking',
    description: 'Anti-détection subtile pour usage quotidien',
    intensity: 0.3,
    config: {
      syntaxVariationEnabled: true,
      llmFingerprintReplacement: false,  // Pas de remplacement mots
      naturalConnectorsEnabled: true,
      preserveReadability: true,
      maxModificationsPerElement: 2,
      qualityThreshold: 0.7
    },
    expectedReduction: '10-15%',
    useCase: 'Articles standard, faible risque détection'
  },

  // ========================================
  // STACK STANDARD - Équilibre optimal
  // ========================================
  standardPatternBreaking: {
    name: 'Standard Pattern Breaking',
    description: 'Équilibre optimal efficacité/naturalité',
    intensity: 0.5,
    config: {
      syntaxVariationEnabled: true,
      llmFingerprintReplacement: true,
      naturalConnectorsEnabled: true,
      preserveReadability: true,
      maxModificationsPerElement: 4,
      qualityThreshold: 0.6
    },
    expectedReduction: '20-25%',
    useCase: 'Usage général recommandé'
  },

  // ========================================
  // STACK INTENSIF - Anti-détection poussée
  // ========================================
  heavyPatternBreaking: {
    name: 'Heavy Pattern Breaking',
    description: 'Anti-détection intensive pour cas critiques',
    intensity: 0.8,
    config: {
      syntaxVariationEnabled: true,
      llmFingerprintReplacement: true,
      naturalConnectorsEnabled: true,
      preserveReadability: true,
      maxModificationsPerElement: 6,
      qualityThreshold: 0.5
    },
    expectedReduction: '30-35%',
    useCase: 'Détection élevée, contenu critique'
  },

  // ========================================
  // STACK ADAPTATIF - Selon contenu
  // ========================================
  adaptivePatternBreaking: {
    name: 'Adaptive Pattern Breaking',
    description: 'Adaptation intelligente selon détection patterns',
    intensity: 0.6,
    config: {
      syntaxVariationEnabled: true,
      llmFingerprintReplacement: true,
      naturalConnectorsEnabled: true,
      preserveReadability: true,
      maxModificationsPerElement: 5,
      qualityThreshold: 0.6,
      adaptiveMode: true  // Ajuste selon détection patterns
    },
    expectedReduction: '25-30%',
    useCase: 'Adaptation automatique par contenu'
  },

  // ========================================
  // STACK SYNTAXE FOCUS - Syntaxe uniquement
  // ========================================
  syntaxFocus: {
    name: 'Syntax Focus',
    description: 'Focus sur variations syntaxiques uniquement',
    intensity: 0.7,
    config: {
      syntaxVariationEnabled: true,
      llmFingerprintReplacement: false,
      naturalConnectorsEnabled: false,
      preserveReadability: true,
      maxModificationsPerElement: 6,
      qualityThreshold: 0.7
    },
    expectedReduction: '15-20%',
    useCase: 'Préservation vocabulaire, syntaxe variable'
  },

  // ========================================
  // STACK CONNECTEURS FOCUS - Connecteurs uniquement
  // ========================================
  connectorsFocus: {
    name: 'Connectors Focus', 
    description: 'Humanisation connecteurs et transitions',
    intensity: 0.8,
    config: {
      syntaxVariationEnabled: false,
      llmFingerprintReplacement: false,
      naturalConnectorsEnabled: true,
      preserveReadability: true,
      maxModificationsPerElement: 4,
      qualityThreshold: 0.8,
      connectorTone: 'casual'  // casual, conversational, technical, commercial
    },
    expectedReduction: '12-18%',
    useCase: 'Textes formels à humaniser'
  }
};

/**
 * APPLICATION STACK PATTERN BREAKING
 * @param {string} stackName - Nom du stack à appliquer
 * @param {object} content - Contenu à traiter
 * @param {object} overrides - Options pour surcharger le stack
 * @returns {object} - { content, stats, stackUsed }
 */
async function applyPatternBreakingStack(stackName, content, overrides = {}) {
  const { applyPatternBreakingLayer } = require('./PatternBreakingCore');

  logSh(`📦 Application Stack Pattern Breaking: ${stackName}`, 'INFO');

  const stack = PATTERN_BREAKING_STACKS[stackName];
  if (!stack) {
    logSh(`❌ Stack Pattern Breaking inconnu: ${stackName}`, 'WARNING');
    throw new Error(`Stack Pattern Breaking inconnu: ${stackName}`);
  }

  try {
    // Configuration fusionnée (stack + overrides)
    const finalConfig = {
      ...stack.config,
      intensityLevel: stack.intensity,
      ...overrides
    };

    logSh(`   🎯 Configuration: ${stack.description}`, 'DEBUG');
    logSh(`   ⚡ Intensité: ${finalConfig.intensityLevel} | Réduction attendue: ${stack.expectedReduction}`, 'DEBUG');

    // Mode adaptatif si activé
    if (finalConfig.adaptiveMode) {
      const adaptedConfig = await adaptConfigurationToContent(content, finalConfig);
      Object.assign(finalConfig, adaptedConfig);
      logSh(`   🧠 Mode adaptatif appliqué`, 'DEBUG');
    }

    // Application Pattern Breaking
    const result = await applyPatternBreakingLayer(content, finalConfig);

    logSh(`📦 Stack Pattern Breaking terminé: ${result.stats?.totalModifications || 0} modifications`, 'INFO');

    return {
      content: result.content,
      stats: {
        ...result.stats,
        stackUsed: stackName,
        stackDescription: stack.description,
        expectedReduction: stack.expectedReduction
      },
      fallback: result.fallback,
      stackUsed: stackName
    };

  } catch (error) {
    logSh(`❌ Erreur application Stack Pattern Breaking ${stackName}: ${error.message}`, 'ERROR');
    throw error;
  }
}

/**
 * ADAPTATION CONFIGURATION SELON CONTENU
 */
async function adaptConfigurationToContent(content, baseConfig) {
  const { detectLLMPatterns } = require('./LLMFingerprints');
  const { detectFormalConnectors } = require('./NaturalConnectors');

  logSh(`🧠 Adaptation configuration selon contenu...`, 'DEBUG');

  const adaptations = { ...baseConfig };

  try {
    // Analyser patterns LLM
    const llmDetection = detectLLMPatterns(content);
    const formalDetection = detectFormalConnectors(content);

    logSh(`   📊 Patterns LLM: ${llmDetection.count} (score: ${llmDetection.suspicionScore.toFixed(3)})`, 'DEBUG');
    logSh(`   📊 Connecteurs formels: ${formalDetection.count} (score: ${formalDetection.suspicionScore.toFixed(3)})`, 'DEBUG');

    // Adapter selon détection patterns LLM
    if (llmDetection.suspicionScore > 0.06) {
      adaptations.llmFingerprintReplacement = true;
      adaptations.intensityLevel = Math.min(1.0, baseConfig.intensityLevel + 0.2);
      logSh(`   🔧 Intensité augmentée pour patterns LLM élevés: ${adaptations.intensityLevel}`, 'DEBUG');
    } else if (llmDetection.suspicionScore < 0.02) {
      adaptations.llmFingerprintReplacement = false;
      logSh(`   🔧 Remplacement LLM désactivé (faible détection)`, 'DEBUG');
    }

    // Adapter selon connecteurs formels
    if (formalDetection.suspicionScore > 0.04) {
      adaptations.naturalConnectorsEnabled = true;
      adaptations.maxModificationsPerElement = Math.min(8, baseConfig.maxModificationsPerElement + 2);
      logSh(`   🔧 Focus connecteurs activé: max ${adaptations.maxModificationsPerElement} modifications`, 'DEBUG');
    }

    // Adapter selon longueur texte
    const wordCount = content.split(/\s+/).length;
    if (wordCount > 500) {
      adaptations.maxModificationsPerElement = Math.min(10, baseConfig.maxModificationsPerElement + 3);
      logSh(`   🔧 Texte long détecté: max ${adaptations.maxModificationsPerElement} modifications`, 'DEBUG');
    }

  } catch (error) {
    logSh(`⚠️ Erreur adaptation configuration: ${error.message}`, 'WARNING');
  }

  return adaptations;
}

/**
 * RECOMMANDATION STACK AUTOMATIQUE
 */
function recommendPatternBreakingStack(content, context = {}) {
  const { detectLLMPatterns } = require('./LLMFingerprints');
  const { detectFormalConnectors } = require('./NaturalConnectors');

  try {
    const llmDetection = detectLLMPatterns(content);
    const formalDetection = detectFormalConnectors(content);
    const wordCount = content.split(/\s+/).length;

    logSh(`🤖 Recommandation Stack Pattern Breaking...`, 'DEBUG');

    // Critères de recommandation
    const criteria = {
      llmPatternsHigh: llmDetection.suspicionScore > 0.05,
      formalConnectorsHigh: formalDetection.suspicionScore > 0.03,
      longContent: wordCount > 300,
      criticalContext: context.critical === true,
      preserveQuality: context.preserveQuality === true
    };

    // Logique de recommandation
    let recommendedStack = 'standardPatternBreaking';
    let reason = 'Configuration équilibrée par défaut';

    if (criteria.criticalContext) {
      recommendedStack = 'heavyPatternBreaking';
      reason = 'Contexte critique détecté';
    } else if (criteria.llmPatternsHigh && criteria.formalConnectorsHigh) {
      recommendedStack = 'heavyPatternBreaking';
      reason = 'Patterns LLM et connecteurs formels élevés';
    } else if (criteria.llmPatternsHigh) {
      recommendedStack = 'adaptivePatternBreaking';
      reason = 'Patterns LLM élevés détectés';
    } else if (criteria.formalConnectorsHigh) {
      recommendedStack = 'connectorsFocus';
      reason = 'Connecteurs formels prédominants';
    } else if (criteria.preserveQuality) {
      recommendedStack = 'lightPatternBreaking';
      reason = 'Préservation qualité prioritaire';
    } else if (!criteria.llmPatternsHigh && !criteria.formalConnectorsHigh) {
      recommendedStack = 'syntaxFocus';
      reason = 'Faible détection patterns, focus syntaxe';
    }

    logSh(`🎯 Stack recommandé: ${recommendedStack} (${reason})`, 'DEBUG');

    return {
      recommendedStack,
      reason,
      criteria,
      confidence: calculateRecommendationConfidence(criteria)
    };

  } catch (error) {
    logSh(`⚠️ Erreur recommandation Stack: ${error.message}`, 'WARNING');
    return {
      recommendedStack: 'standardPatternBreaking',
      reason: 'Fallback suite erreur analyse',
      criteria: {},
      confidence: 0.5
    };
  }
}

/**
 * CALCUL CONFIANCE RECOMMANDATION
 */
function calculateRecommendationConfidence(criteria) {
  let confidence = 0.5; // Base

  // Augmenter confiance selon critères détectés
  if (criteria.llmPatternsHigh) confidence += 0.2;
  if (criteria.formalConnectorsHigh) confidence += 0.2;
  if (criteria.criticalContext) confidence += 0.3;
  if (criteria.longContent) confidence += 0.1;

  return Math.min(1.0, confidence);
}

/**
 * LISTE STACKS DISPONIBLES
 */
function listAvailableStacks() {
  return Object.entries(PATTERN_BREAKING_STACKS).map(([key, stack]) => ({
    name: key,
    displayName: stack.name,
    description: stack.description,
    intensity: stack.intensity,
    expectedReduction: stack.expectedReduction,
    useCase: stack.useCase
  }));
}

/**
 * VALIDATION STACK
 */
function validateStack(stackName) {
  const stack = PATTERN_BREAKING_STACKS[stackName];
  if (!stack) {
    return { valid: false, error: `Stack inconnu: ${stackName}` };
  }

  // Vérifications configuration
  const config = stack.config;
  const checks = {
    hasIntensity: typeof stack.intensity === 'number',
    hasConfig: typeof config === 'object',
    hasValidThreshold: config.qualityThreshold >= 0 && config.qualityThreshold <= 1,
    hasValidMaxMods: config.maxModificationsPerElement > 0
  };

  const valid = Object.values(checks).every(Boolean);

  return {
    valid,
    checks,
    error: valid ? null : 'Configuration stack invalide'
  };
}

// ============= EXPORTS =============
module.exports = {
  applyPatternBreakingStack,
  recommendPatternBreakingStack,
  adaptConfigurationToContent,
  listAvailableStacks,
  validateStack,
  PATTERN_BREAKING_STACKS
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/StepExecutor.js                                         │
└────────────────────────────────────────────────────────────────────┘
*/

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

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

/**
 * 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) {
    const contentStructure = {};

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

      Object.entries(hierarchy).forEach(([path, section]) => {
        // Générer pour le titre si présent
        if (section.title && section.title.originalElement) {
          const tag = section.title.originalElement.name;
          const instruction = section.title.instructions || section.title.originalElement.instructions || `Rédige un titre pour ${inputData.mc0}`;
          contentStructure[tag] = instruction;
        }

        // Générer pour le texte si présent
        if (section.text && section.text.originalElement) {
          const tag = section.text.originalElement.name;
          const instruction = section.text.instructions || section.text.originalElement.instructions || `Rédige du contenu sur ${inputData.mc0}`;
          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) {
              const tag = q.originalElement.name;
              const instruction = q.instructions || q.originalElement.instructions || `Rédige une question/réponse FAQ sur ${inputData.mc0}`;
              contentStructure[tag] = instruction;
            }
          });
        }
      });

      logSh(`🏗️ Structure depuis hiérarchie: ${Object.keys(contentStructure).length} éléments`, 'DEBUG');
    } 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
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/ContentAssembly.js                                      │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: ContentAssembly.js
// Description: Assemblage et nettoyage du contenu XML
// ========================================

const { logSh } = require('./ErrorReporting'); // Using unified logSh from ErrorReporting

/**
 * Nettoie les balises <strong> du template XML
 * @param {string} xmlString - Le contenu XML à nettoyer
 * @returns {string} - XML nettoyé
 */
function cleanStrongTags(xmlString) {
  logSh('Nettoyage balises <strong> du template...', 'DEBUG');
  
  // Enlever toutes les balises <strong> et </strong>
  let cleaned = xmlString.replace(/<\/?strong>/g, '');
  
  // Log du nettoyage
  const strongCount = (xmlString.match(/<\/?strong>/g) || []).length;
  if (strongCount > 0) {
    logSh(`${strongCount} balises <strong> supprimées`, 'INFO');
  }
  
  return cleaned;
}

/**
 * Remplace toutes les variables CSV dans le XML
 * @param {string} xmlString - Le contenu XML
 * @param {object} csvData - Les données CSV
 * @returns {string} - XML avec variables remplacées
 */
function replaceAllCSVVariables(xmlString, csvData) {
  logSh('Remplacement variables CSV...', 'DEBUG');
  
  let result = xmlString;
  
  // Variables simples
  result = result.replace(/\{\{T0\}\}/g, csvData.t0 || '');
  result = result.replace(/\{\{MC0\}\}/g, csvData.mc0 || '');
  result = result.replace(/\{\{T-1\}\}/g, csvData.tMinus1 || '');
  result = result.replace(/\{\{L-1\}\}/g, csvData.lMinus1 || '');
  
  logSh(`Variables simples remplacées: T0="${csvData.t0}", MC0="${csvData.mc0}"`, 'DEBUG');
  
  // Variables multiples
  const mcPlus1 = (csvData.mcPlus1 || '').split(',').map(s => s.trim());
  const tPlus1 = (csvData.tPlus1 || '').split(',').map(s => s.trim());
  const lPlus1 = (csvData.lPlus1 || '').split(',').map(s => s.trim());
  
  logSh(`Variables multiples: MC+1[${mcPlus1.length}], T+1[${tPlus1.length}], L+1[${lPlus1.length}]`, 'DEBUG');
  
  // Remplacer MC+1_1, MC+1_2, etc.
  for (let i = 1; i <= 6; i++) {
    const mcValue = mcPlus1[i-1] || `[MC+1_${i} non défini]`;
    const tValue = tPlus1[i-1] || `[T+1_${i} non défini]`;
    const lValue = lPlus1[i-1] || `[L+1_${i} non défini]`;
    
    result = result.replace(new RegExp(`\\{\\{MC\\+1_${i}\\}\\}`, 'g'), mcValue);
    result = result.replace(new RegExp(`\\{\\{T\\+1_${i}\\}\\}`, 'g'), tValue);
    result = result.replace(new RegExp(`\\{\\{L\\+1_${i}\\}\\}`, 'g'), lValue);
    
    if (mcPlus1[i-1]) {
      logSh(`MC+1_${i} = "${mcValue}"`, 'DEBUG');
    }
  }
  
  // Vérifier qu'il ne reste pas de variables non remplacées
  const remainingVars = (result.match(/\{\{[^}]+\}\}/g) || []);
  if (remainingVars.length > 0) {
    logSh(`ATTENTION: Variables non remplacées: ${remainingVars.join(', ')}`, 'WARNING');
  }
  
  logSh('Toutes les variables CSV remplacées', 'INFO');
  return result;
}

/**
 * Injecte le contenu généré dans le XML final
 * @param {string} cleanXML - XML nettoyé
 * @param {object} generatedContent - Contenu généré par tag
 * @param {array} elements - Éléments extraits
 * @returns {string} - XML final avec contenu injecté
 */
function injectGeneratedContent(cleanXML, generatedContent, elements) {
  logSh('🔍 === DEBUG INJECTION MAPPING ===', 'DEBUG');
  logSh(`XML reçu: ${cleanXML.length} caractères`, 'DEBUG');
  logSh(`Contenu généré: ${Object.keys(generatedContent).length} éléments`, 'DEBUG');
  logSh(`Éléments fournis: ${elements ? elements.length : 'undefined'} éléments`, 'DEBUG');

  // Fix: s'assurer que elements est un array
  if (!Array.isArray(elements)) {
    logSh(`⚠ Elements n'est pas un array, type: ${typeof elements}`, 'WARN');
    elements = [];
  }
  
  // Debug: montrer le XML
  logSh(`🔍 XML début: ${cleanXML}`, 'DEBUG');
  
  // Debug: montrer le contenu généré
  Object.keys(generatedContent).forEach(key => {
    logSh(`🔍 Généré [${key}]: "${generatedContent[key]}"`, 'DEBUG');
  });
  
  // Debug: montrer les éléments
  elements.forEach((element, i) => {
    logSh(`🔍 Element ${i+1}: originalTag="${element.originalTag}", originalFullMatch="${element.originalFullMatch}"`, 'DEBUG');
  });
  
  let finalXML = cleanXML;
  
  // Créer un mapping tag pur → tag original complet
  const tagMapping = {};
  elements.forEach(element => {
    tagMapping[element.originalTag] = element.originalFullMatch || element.originalTag;
  });
  
  logSh(`🔍 TagMapping créé: ${JSON.stringify(tagMapping, null, 2)}`, 'DEBUG');
  
  // Remplacer en utilisant les tags originaux complets
  Object.keys(generatedContent).forEach(pureTag => {
    const content = generatedContent[pureTag];
    
    logSh(`🔍 === TRAITEMENT TAG: ${pureTag} ===`, 'DEBUG');
    logSh(`🔍 Contenu à injecter: "${content}"`, 'DEBUG');
    
    // Trouver le tag original complet dans le XML
    const originalTag = findOriginalTagInXML(finalXML, pureTag);
    
    logSh(`🔍 Tag original trouvé: ${originalTag ? originalTag : 'AUCUN'}`, 'DEBUG');
    
    if (originalTag) {
      const beforeLength = finalXML.length;
      finalXML = finalXML.replace(originalTag, content);
      const afterLength = finalXML.length;
      
      if (beforeLength !== afterLength) {
        logSh(`✅ SUCCÈS: Remplacé ${originalTag} par contenu (${afterLength - beforeLength + originalTag.length} chars)`, 'DEBUG');
      } else {
        logSh(`❌ ÉCHEC: Replace n'a pas fonctionné pour ${originalTag}`, 'DEBUG');
      }
    } else {
      // Fallback : essayer avec le tag pur
      const beforeLength = finalXML.length;
      finalXML = finalXML.replace(pureTag, content);
      const afterLength = finalXML.length;
      
      logSh(`⚠ FALLBACK ${pureTag}: remplacement ${beforeLength !== afterLength ? 'RÉUSSI' : 'ÉCHOUÉ'}`, 'DEBUG');
      logSh(`⚠ Contenu fallback: "${content}"`, 'DEBUG');
    }
  });
  
  // Vérifier les tags restants
  const remainingTags = (finalXML.match(/\|[^|]*\|/g) || []);
  if (remainingTags.length > 0) {
    logSh(`ATTENTION: ${remainingTags.length} tags non remplacés: ${remainingTags.slice(0, 3).join(', ')}...`, 'WARNING');
  }
  
  logSh('Injection terminée', 'INFO');
  return finalXML;
}

/**
 * Helper pour trouver le tag original complet dans le XML
 * @param {string} xmlString - Contenu XML
 * @param {string} pureTag - Tag pur à rechercher
 * @returns {string|null} - Tag original trouvé ou null
 */
function findOriginalTagInXML(xmlString, pureTag) {
  logSh(`🔍 === RECHERCHE TAG DANS XML ===`, 'DEBUG');
  logSh(`🔍 Tag pur recherché: "${pureTag}"`, 'DEBUG');
  
  // Extraire le nom du tag pur : |Titre_H1_1| → Titre_H1_1
  const tagName = pureTag.replace(/\|/g, '');
  logSh(`🔍 Nom tag extrait: "${tagName}"`, 'DEBUG');
  
  // Chercher tous les tags qui commencent par ce nom (avec espaces optionnels)
  const regex = new RegExp(`\\|\\s*${tagName}[^|]*\\|`, 'g');
  logSh(`🔍 Regex utilisée: ${regex}`, 'DEBUG');
  
  // Debug: montrer tous les tags présents dans le XML
  const allTags = xmlString.match(/\|[^|]*\|/g) || [];
  logSh(`🔍 Tags présents dans XML: ${allTags.length}`, 'DEBUG');
  allTags.forEach((tag, i) => {
    logSh(`🔍   ${i+1}. "${tag}"`, 'DEBUG');
  });
  
  const matches = xmlString.match(regex);
  logSh(`🔍 Matches trouvés: ${matches ? matches.length : 0}`, 'DEBUG');
  
  if (matches && matches.length > 0) {
    logSh(`🔍 Premier match: "${matches[0]}"`, 'DEBUG');
    logSh(`✅ Tag original trouvé pour ${pureTag}: ${matches[0]}`, 'DEBUG');
    return matches[0];
  }
  
  logSh(`❌ Aucun tag original trouvé pour ${pureTag}`, 'DEBUG');
  return null;
}

// ============= EXPORTS =============
module.exports = {
  cleanStrongTags,
  replaceAllCSVVariables,
  injectGeneratedContent,
  findOriginalTagInXML
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/ArticleStorage.js                                       │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: ArticleStorage.js
// Description: Système de sauvegarde articles avec texte compilé uniquement
// ========================================

require('dotenv').config();
const { google } = require('googleapis');
const { logSh } = require('./ErrorReporting');

// Configuration Google Sheets
const SHEET_CONFIG = {
  sheetId: '1iA2GvWeUxX-vpnAMfVm3ZMG9LhaC070SdGssEcXAh2c'
};

/**
 * NOUVELLE FONCTION : Compiler le contenu de manière organique
 * Respecte la hiérarchie et les associations naturelles
 */
async function compileGeneratedTextsOrganic(generatedTexts, elements) {
  if (!generatedTexts || Object.keys(generatedTexts).length === 0) {
    return '';
  }
  
  logSh(`🌱 Compilation ORGANIQUE de ${Object.keys(generatedTexts).length} éléments...`, 'DEBUG');
  
  let compiledParts = [];
  
  // 1. DÉTECTER et GROUPER les sections organiques
  const organicSections = buildOrganicSections(generatedTexts, elements);
  
  // 2. COMPILER dans l'ordre naturel
  organicSections.forEach(section => {
    if (section.type === 'header_with_content') {
      // H1, H2, H3 avec leur contenu associé
      if (section.title) {
        compiledParts.push(cleanIndividualContent(section.title));
      }
      if (section.content) {
        compiledParts.push(cleanIndividualContent(section.content));
      }
    } 
    else if (section.type === 'standalone_content') {
      // Contenu sans titre associé
      compiledParts.push(cleanIndividualContent(section.content));
    }
    else if (section.type === 'faq_pair') {
      // Paire question + réponse
      if (section.question && section.answer) {
        compiledParts.push(cleanIndividualContent(section.question));
        compiledParts.push(cleanIndividualContent(section.answer));
      }
    }
  });
  
  // 3. Joindre avec espacement naturel
  const finalText = compiledParts.join('\n\n');
  
  logSh(`✅ Compilation organique terminée: ${finalText.length} caractères`, 'INFO');
  return finalText.trim();
}

/**
 * Construire les sections organiques en analysant les associations
 */
function buildOrganicSections(generatedTexts, elements) {
  const sections = [];
  const usedTags = new Set();
  
  // 🔧 FIX: Gérer le cas où elements est null/undefined
  if (!elements) {
    logSh('⚠️ Elements null, utilisation compilation simple', 'DEBUG');
    // Compilation simple : tout le contenu dans l'ordre des clés
    Object.keys(generatedTexts).forEach(tag => {
      sections.push({
        type: 'standalone_content',
        content: generatedTexts[tag],
        tag: tag
      });
    });
    return sections;
  }
  
  // 1. ANALYSER l'ordre original des éléments
  const originalOrder = elements.map(el => el.originalTag);
  
  logSh(`📋 Analyse de ${originalOrder.length} éléments dans l'ordre original...`, 'DEBUG');
  
  // 2. DÉTECTER les associations naturelles
  for (let i = 0; i < originalOrder.length; i++) {
    const currentTag = originalOrder[i];
    const currentContent = generatedTexts[currentTag];
    
    if (!currentContent || usedTags.has(currentTag)) continue;
    
    const currentType = identifyElementType(currentTag);
    
    if (currentType === 'titre_h1' || currentType === 'titre_h2' || currentType === 'titre_h3') {
      // CHERCHER le contenu associé qui suit
      const associatedContent = findAssociatedContent(originalOrder, i, generatedTexts, usedTags);
      
      sections.push({
        type: 'header_with_content',
        title: currentContent,
        content: associatedContent.content,
        titleTag: currentTag,
        contentTag: associatedContent.tag
      });
      
      usedTags.add(currentTag);
      if (associatedContent.tag) {
        usedTags.add(associatedContent.tag);
      }
      
      logSh(`  ✓ Section: ${currentType} + contenu associé`, 'DEBUG');
    }
    else if (currentType === 'faq_question') {
      // CHERCHER la réponse correspondante
      const matchingAnswer = findMatchingFAQAnswer(currentTag, generatedTexts);
      
      if (matchingAnswer) {
        sections.push({
          type: 'faq_pair',
          question: currentContent,
          answer: matchingAnswer.content,
          questionTag: currentTag,
          answerTag: matchingAnswer.tag
        });
        
        usedTags.add(currentTag);
        usedTags.add(matchingAnswer.tag);
        
        logSh(`  ✓ Paire FAQ: ${currentTag} + ${matchingAnswer.tag}`, 'DEBUG');
      }
    }
    else if (currentType !== 'faq_reponse') {
      // CONTENU STANDALONE (pas une réponse FAQ déjà traitée)
      sections.push({
        type: 'standalone_content',
        content: currentContent,
        contentTag: currentTag
      });
      
      usedTags.add(currentTag);
      logSh(`  ✓ Contenu standalone: ${currentType}`, 'DEBUG');
    }
  }
  
  logSh(`🏗️ ${sections.length} sections organiques construites`, 'INFO');
  return sections;
}

/**
 * Trouver le contenu associé à un titre (paragraphe qui suit)
 */
function findAssociatedContent(originalOrder, titleIndex, generatedTexts, usedTags) {
  // Chercher dans les éléments suivants
  for (let j = titleIndex + 1; j < originalOrder.length; j++) {
    const nextTag = originalOrder[j];
    const nextContent = generatedTexts[nextTag];
    
    if (!nextContent || usedTags.has(nextTag)) continue;
    
    const nextType = identifyElementType(nextTag);
    
    // Si on trouve un autre titre, on s'arrête
    if (nextType === 'titre_h1' || nextType === 'titre_h2' || nextType === 'titre_h3') {
      break;
    }
    
    // Si on trouve du contenu (texte, intro), c'est probablement associé
    if (nextType === 'texte' || nextType === 'intro') {
      return {
        content: nextContent,
        tag: nextTag
      };
    }
  }
  
  return { content: null, tag: null };
}

/**
 * Extraire le numéro d'une FAQ : |Faq_q_1| ou |Faq_a_2| → "1" ou "2"
 */
function extractFAQNumber(tag) {
  const match = tag.match(/(\d+)/);
  return match ? match[1] : null;
}

/**
 * Trouver la réponse FAQ correspondant à une question
 */
function findMatchingFAQAnswer(questionTag, generatedTexts) {
  // Extraire le numéro : |Faq_q_1| → 1
  const questionNumber = extractFAQNumber(questionTag);
  
  if (!questionNumber) return null;
  
  // Chercher la réponse correspondante
  for (const tag in generatedTexts) {
    const tagType = identifyElementType(tag);
    
    if (tagType === 'faq_reponse') {
      const answerNumber = extractFAQNumber(tag);
      
      if (answerNumber === questionNumber) {
        return {
          content: generatedTexts[tag],
          tag: tag
        };
      }
    }
  }
  
  return null;
}

/**
 * Nouvelle fonction de sauvegarde avec compilation organique
 */
async function saveGeneratedArticleOrganic(articleData, csvData, config = {}) {
  try {
    logSh('💾 Sauvegarde article avec compilation organique...', 'INFO');
    
    const sheets = await getSheetsClient();
    
    // 🆕 Choisir la sheet selon le flag useVersionedSheet
    const targetSheetName = config.useVersionedSheet ? 'Generated_Articles_Versioned' : 'Generated_Articles';
    let articlesSheet = await getOrCreateSheet(sheets, targetSheetName);
    
    // ===== COMPILATION ORGANIQUE =====
    const compiledText = await compileGeneratedTextsOrganic(
      articleData.generatedTexts,
      articleData.originalElements // Passer les éléments originaux si disponibles
    );
    
    logSh(`📝 Texte compilé organiquement: ${compiledText.length} caractères`, 'INFO');
    
    // Métadonnées avec format français
    const now = new Date();
    const frenchTimestamp = formatDateToFrench(now);
    
    // UTILISER le slug du CSV (colonne A du Google Sheet source)
    // Le slug doit venir de csvData.slug (récupéré via getBrainConfig)
    const slug = csvData.slug || generateSlugFromContent(csvData.mc0, csvData.t0);
    
    const metadata = {
      timestamp: frenchTimestamp,
      slug: slug,
      mc0: csvData.mc0,
      t0: csvData.t0,
      personality: csvData.personality?.nom || 'Unknown',
      antiDetectionLevel: config.antiDetectionLevel || config.adversarialMode || 'none',
      elementsCount: Object.keys(articleData.generatedTexts || {}).length,
      textLength: compiledText.length,
      wordCount: countWords(compiledText),
      llmUsed: config.llmUsed || 'openai',
      validationStatus: articleData.validationReport?.status || 'unknown',
      // 🆕 Métadonnées de versioning
      version: config.version || '1.0',
      stage: config.stage || 'final_version',
      stageDescription: config.stageDescription || 'Version finale',
      parentArticleId: config.parentArticleId || null,
      versionHistory: config.versionHistory || null
    };
    
    // Préparer la ligne de données selon le format de la sheet
    let row;

    if (config.useVersionedSheet) {
      // Format VERSIONED (21 colonnes) : avec version, stage, stageDescription, parentArticleId
      row = [
        metadata.timestamp,
        metadata.slug,
        metadata.mc0,
        metadata.t0,
        metadata.personality,
        metadata.antiDetectionLevel,
        compiledText,
        metadata.textLength,
        metadata.wordCount,
        metadata.elementsCount,
        metadata.llmUsed,
        metadata.validationStatus,
        metadata.version,           // Colonne M
        metadata.stage,             // Colonne N
        metadata.stageDescription,  // Colonne O
        metadata.parentArticleId || '', // Colonne P
        '', '', '', '',            // Colonnes Q,R,S,T : scores détecteurs (réservées)
        JSON.stringify({           // Colonne U
          csvData: { ...csvData, xmlTemplate: undefined, xmlFileName: csvData.xmlFileName },
          config: config,
          stats: metadata,
          versionHistory: metadata.versionHistory
        })
      ];
    } else {
      // Format LEGACY (17 colonnes) : sans version/stage, scores détecteurs à la place
      row = [
        metadata.timestamp,
        metadata.slug,
        metadata.mc0,
        metadata.t0,
        metadata.personality,
        metadata.antiDetectionLevel,
        compiledText,
        metadata.textLength,
        metadata.wordCount,
        metadata.elementsCount,
        metadata.llmUsed,
        metadata.validationStatus,
        '', '', '', '',            // Colonnes M,N,O,P : scores détecteurs (GPTZero, Originality, CopyLeaks, HumanQuality)
        JSON.stringify({           // Colonne Q
          csvData: { ...csvData, xmlTemplate: undefined, xmlFileName: csvData.xmlFileName },
          config: config,
          stats: metadata
        })
      ];
    }
    
    // DEBUG: Vérifier le slug généré
    logSh(`💾 Sauvegarde avec slug: "${metadata.slug}" (colonne B)`, 'DEBUG');
    
    // Ajouter la ligne aux données dans la bonne sheet
    // Forcer le range à A1 pour éviter le décalage horizontal
    const targetRange = config.useVersionedSheet ? 'Generated_Articles_Versioned!A1' : 'Generated_Articles!A1';

    logSh(`🔍 DEBUG APPEND: sheetId=${SHEET_CONFIG.sheetId}, range=${targetRange}, rowLength=${row.length}`, 'INFO');
    logSh(`🔍 DEBUG ROW PREVIEW: [${row.slice(0, 5).map(c => typeof c === 'string' ? c.substring(0, 50) : c).join(', ')}...]`, 'INFO');

    const appendResult = await sheets.spreadsheets.values.append({
      spreadsheetId: SHEET_CONFIG.sheetId,
      range: targetRange,
      valueInputOption: 'USER_ENTERED',
      insertDataOption: 'INSERT_ROWS',  // Force l'insertion d'une nouvelle ligne
      resource: {
        values: [row]
      }
    });

    logSh(`✅ APPEND SUCCESS: ${appendResult.status} - Updated ${appendResult.data.updates?.updatedCells || 0} cells`, 'INFO');
    
    // Récupérer le numéro de ligne pour l'ID article
    const targetRangeForId = config.useVersionedSheet ? 'Generated_Articles_Versioned!A:A' : 'Generated_Articles!A:A';
    const response = await sheets.spreadsheets.values.get({
      spreadsheetId: SHEET_CONFIG.sheetId,
      range: targetRangeForId
    });
    
    const articleId = response.data.values ? response.data.values.length : 1;
    
    logSh(`✅ Article organique sauvé: ID ${articleId}, ${metadata.wordCount} mots`, 'INFO');
    
    return {
      articleId: articleId,
      textLength: metadata.textLength,
      wordCount: metadata.wordCount,
      sheetRow: response.data.values ? response.data.values.length : 2
    };
    
  } catch (error) {
    logSh(`❌ Erreur sauvegarde organique: ${error.toString()}`, 'ERROR');
    throw error;
  }
}

/**
 * Générer un slug à partir du contenu MC0 et T0
 */
function generateSlugFromContent(mc0, t0) {
  if (!mc0 && !t0) return 'article-generated';
  
  const source = mc0 || t0;
  return source
    .toString()
    .toLowerCase()
    .replace(/[àáâäã]/g, 'a')
    .replace(/[èéêë]/g, 'e')
    .replace(/[ìíîï]/g, 'i')
    .replace(/[òóôöõ]/g, 'o')
    .replace(/[ùúûü]/g, 'u')
    .replace(/[ç]/g, 'c')
    .replace(/[ñ]/g, 'n')
    .replace(/[^a-z0-9\s-]/g, '') // Enlever caractères spéciaux
    .replace(/\s+/g, '-')          // Espaces -> tirets
    .replace(/-+/g, '-')           // Éviter doubles tirets
    .replace(/^-+|-+$/g, '')       // Enlever tirets début/fin
    .substring(0, 50);             // Limiter longueur
}

/**
 * Identifier le type d'élément par son tag
 */
function identifyElementType(tag) {
  const cleanTag = tag.toLowerCase().replace(/[|{}]/g, '');
  
  if (cleanTag.includes('titre_h1') || cleanTag.includes('h1')) return 'titre_h1';
  if (cleanTag.includes('titre_h2') || cleanTag.includes('h2')) return 'titre_h2';
  if (cleanTag.includes('titre_h3') || cleanTag.includes('h3')) return 'titre_h3';
  if (cleanTag.includes('intro')) return 'intro';
  if (cleanTag.includes('faq_q') || cleanTag.includes('faq_question')) return 'faq_question';
  if (cleanTag.includes('faq_a') || cleanTag.includes('faq_reponse')) return 'faq_reponse';
  
  return 'texte'; // Par défaut
}

/**
 * Nettoyer un contenu individuel
 */
function cleanIndividualContent(content) {
  if (!content) return '';
  
  let cleaned = content.toString();
  
  // 1. Supprimer les balises HTML
  cleaned = cleaned.replace(/<[^>]*>/g, '');
  
  // 2. Décoder les entités HTML
  cleaned = cleaned.replace(/&lt;/g, '<');
  cleaned = cleaned.replace(/&gt;/g, '>');
  cleaned = cleaned.replace(/&amp;/g, '&');
  cleaned = cleaned.replace(/&quot;/g, '"');
  cleaned = cleaned.replace(/&#039;/g, "'");
  cleaned = cleaned.replace(/&nbsp;/g, ' ');
  
  // 3. Nettoyer les espaces
  cleaned = cleaned.replace(/\s+/g, ' ');
  cleaned = cleaned.replace(/\n\s+/g, '\n');
  
  // 4. Supprimer les caractères de contrôle étranges
  cleaned = cleaned.replace(/[\x00-\x1F\x7F-\x9F]/g, '');
  
  return cleaned.trim();
}

/**
 * Créer la sheet de stockage avec headers appropriés
 */
async function createArticlesStorageSheet(sheets, sheetName = 'Generated_Articles') {
  logSh(`🗄️ Création sheet ${sheetName}...`, 'INFO');
  
  try {
    // Créer la nouvelle sheet
    await sheets.spreadsheets.batchUpdate({
      spreadsheetId: SHEET_CONFIG.sheetId,
      resource: {
        requests: [{
          addSheet: {
            properties: {
              title: sheetName
            }
          }
        }]
      }
    });
    
    // Headers avec versioning
    const headers = [
      'Timestamp',
      'Slug', 
      'MC0',
      'T0',
      'Personality',
      'AntiDetection_Level',
      'Compiled_Text',           // ← COLONNE PRINCIPALE
      'Text_Length',
      'Word_Count',
      'Elements_Count',
      'LLM_Used',
      'Validation_Status',
      // 🆕 Colonnes de versioning
      'Version',                 // v1.0, v1.1, v1.2, v2.0
      'Stage',                   // initial_generation, selective_enhancement, etc.
      'Stage_Description',       // Description détaillée de l'étape
      'Parent_Article_ID',       // ID de l'article parent (pour linkage)
      'GPTZero_Score',          // Scores détecteurs (à remplir)
      'Originality_Score',
      'CopyLeaks_Score', 
      'Human_Quality_Score',
      'Full_Metadata_JSON'      // Backup complet avec historique
    ];
    
    // Ajouter les headers
    await sheets.spreadsheets.values.update({
      spreadsheetId: SHEET_CONFIG.sheetId,
      range: `${sheetName}!A1:U1`,
      valueInputOption: 'USER_ENTERED',
      resource: {
        values: [headers]
      }
    });
    
    // Formatter les headers
    await sheets.spreadsheets.batchUpdate({
      spreadsheetId: SHEET_CONFIG.sheetId,
      resource: {
        requests: [{
          repeatCell: {
            range: {
              sheetId: await getSheetIdByName(sheets, sheetName),
              startRowIndex: 0,
              endRowIndex: 1,
              startColumnIndex: 0,
              endColumnIndex: headers.length
            },
            cell: {
              userEnteredFormat: {
                textFormat: {
                  bold: true
                },
                backgroundColor: {
                  red: 0.878,
                  green: 0.878,
                  blue: 0.878
                },
                horizontalAlignment: 'CENTER'
              }
            },
            fields: 'userEnteredFormat(textFormat,backgroundColor,horizontalAlignment)'
          }
        }]
      }
    });
    
    logSh(`✅ Sheet ${sheetName} créée avec succès`, 'INFO');
    return true;
    
  } catch (error) {
    logSh(`❌ Erreur création sheet: ${error.toString()}`, 'ERROR');
    throw error;
  }
}

/**
 * Formater date au format français DD/MM/YYYY HH:mm:ss
 */
function formatDateToFrench(date) {
  // Utiliser toLocaleString avec le format français
  return date.toLocaleString('fr-FR', {
    day: '2-digit',
    month: '2-digit', 
    year: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
    timeZone: 'Europe/Paris'
  }).replace(',', '');
}

/**
 * Compter les mots dans un texte
 */
function countWords(text) {
  if (!text || text.trim() === '') return 0;
  return text.trim().split(/\s+/).length;
}

/**
 * Récupérer un article sauvé par ID
 */
async function getStoredArticle(articleId) {
  try {
    const sheets = await getSheetsClient();
    
    const rowNumber = articleId + 2; // +2 car header + 0-indexing
    const response = await sheets.spreadsheets.values.get({
      spreadsheetId: SHEET_CONFIG.sheetId,
      range: `Generated_Articles!A${rowNumber}:Q${rowNumber}`
    });
    
    if (!response.data.values || response.data.values.length === 0) {
      throw new Error(`Article ${articleId} non trouvé`);
    }
    
    const data = response.data.values[0];
    
    return {
      articleId: articleId,
      timestamp: data[0],
      slug: data[1],
      mc0: data[2],
      t0: data[3],
      personality: data[4],
      antiDetectionLevel: data[5],
      compiledText: data[6],      // ← TEXTE PUR
      textLength: data[7],
      wordCount: data[8],
      elementsCount: data[9],
      llmUsed: data[10],
      validationStatus: data[11],
      gptZeroScore: data[12],
      originalityScore: data[13],
      copyLeaksScore: data[14],
      humanScore: data[15],
      fullMetadata: data[16] ? JSON.parse(data[16]) : null
    };
    
  } catch (error) {
    logSh(`❌ Erreur récupération article ${articleId}: ${error.toString()}`, 'ERROR');
    throw error;
  }
}

/**
 * Lister les derniers articles générés
 */
async function getRecentArticles(limit = 10) {
  try {
    const sheets = await getSheetsClient();
    
    const response = await sheets.spreadsheets.values.get({
      spreadsheetId: SHEET_CONFIG.sheetId,
      range: 'Generated_Articles!A:L'
    });
    
    if (!response.data.values || response.data.values.length <= 1) {
      return []; // Pas de données ou seulement headers
    }
    
    const data = response.data.values.slice(1); // Exclure headers
    const startIndex = Math.max(0, data.length - limit);
    const recentData = data.slice(startIndex);
    
    return recentData.map((row, index) => ({
      articleId: startIndex + index,
      timestamp: row[0],
      slug: row[1],
      mc0: row[2],
      personality: row[4],
      antiDetectionLevel: row[5],
      wordCount: row[8],
      validationStatus: row[11]
    })).reverse(); // Plus récents en premier
    
  } catch (error) {
    logSh(`❌ Erreur liste articles récents: ${error.toString()}`, 'ERROR');
    return [];
  }
}

/**
 * Mettre à jour les scores de détection d'un article
 */
async function updateDetectionScores(articleId, scores) {
  try {
    const sheets = await getSheetsClient();
    const rowNumber = articleId + 2;
    
    const updates = [];
    
    // Colonnes des scores : M, N, O (GPTZero, Originality, CopyLeaks)
    if (scores.gptzero !== undefined) {
      updates.push({
        range: `Generated_Articles!M${rowNumber}`,
        values: [[scores.gptzero]]
      });
    }
    if (scores.originality !== undefined) {
      updates.push({
        range: `Generated_Articles!N${rowNumber}`,
        values: [[scores.originality]]
      });
    }
    if (scores.copyleaks !== undefined) {
      updates.push({
        range: `Generated_Articles!O${rowNumber}`,
        values: [[scores.copyleaks]]
      });
    }
    
    if (updates.length > 0) {
      await sheets.spreadsheets.values.batchUpdate({
        spreadsheetId: SHEET_CONFIG.sheetId,
        resource: {
          valueInputOption: 'USER_ENTERED',
          data: updates
        }
      });
    }
    
    logSh(`✅ Scores détection mis à jour pour article ${articleId}`, 'INFO');
    
  } catch (error) {
    logSh(`❌ Erreur maj scores article ${articleId}: ${error.toString()}`, 'ERROR');
    throw error;
  }
}

// ============= HELPERS GOOGLE SHEETS =============

/**
 * Obtenir le client Google Sheets authentifié
 */
async function getSheetsClient() {
  const auth = new google.auth.GoogleAuth({
    credentials: {
      client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
      private_key: process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n')
    },
    scopes: ['https://www.googleapis.com/auth/spreadsheets']
  });
  
  const authClient = await auth.getClient();
  const sheets = google.sheets({ version: 'v4', auth: authClient });
  
  return sheets;
}

/**
 * Obtenir ou créer une sheet
 */
async function getOrCreateSheet(sheets, sheetName) {
  try {
    // Vérifier si la sheet existe
    const response = await sheets.spreadsheets.get({
      spreadsheetId: SHEET_CONFIG.sheetId
    });
    
    const existingSheet = response.data.sheets.find(
      sheet => sheet.properties.title === sheetName
    );
    
    if (existingSheet) {
      return existingSheet;
    } else {
      // Créer la sheet si elle n'existe pas
      if (sheetName === 'Generated_Articles' || sheetName === 'Generated_Articles_Versioned') {
        await createArticlesStorageSheet(sheets, sheetName);
        return await getOrCreateSheet(sheets, sheetName); // Récursif pour récupérer la sheet créée
      }
      throw new Error(`Sheet ${sheetName} non supportée pour création automatique`);
    }
    
  } catch (error) {
    logSh(`❌ Erreur accès/création sheet ${sheetName}: ${error.toString()}`, 'ERROR');
    throw error;
  }
}

/**
 * Obtenir l'ID d'une sheet par son nom
 */
async function getSheetIdByName(sheets, sheetName) {
  const response = await sheets.spreadsheets.get({
    spreadsheetId: SHEET_CONFIG.sheetId
  });
  
  const sheet = response.data.sheets.find(
    s => s.properties.title === sheetName
  );
  
  return sheet ? sheet.properties.sheetId : null;
}

// ============= EXPORTS =============

module.exports = {
  compileGeneratedTextsOrganic,
  buildOrganicSections,
  findAssociatedContent,
  extractFAQNumber,
  findMatchingFAQAnswer,
  saveGeneratedArticleOrganic,
  identifyElementType,
  cleanIndividualContent,
  createArticlesStorageSheet,
  formatDateToFrench,
  countWords,
  getStoredArticle,
  getRecentArticles,
  updateDetectionScores,
  getSheetsClient,
  getOrCreateSheet,
  getSheetIdByName,
  generateSlugFromContent
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/Main.js                                                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// MAIN MODULAIRE - PIPELINE ARCHITECTURALE MODERNE
// Responsabilité: Orchestration workflow avec architecture modulaire complète
// Usage: node main_modulaire.js [rowNumber] [stackType]
// ========================================

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

// Import système de tendances
const { TrendManager } = require('./trend-prompts/TrendManager');

// Import système de pipelines flexibles
const { PipelineExecutor } = require('./pipeline/PipelineExecutor');

// Imports pipeline de base
const { readInstructionsData, selectPersonalityWithAI, getPersonalities } = require('./BrainConfig');
const { extractElements, buildSmartHierarchy } = require('./ElementExtraction');
const { generateMissingKeywords } = require('./MissingKeywords');
// Migration vers StepExecutor pour garantir la cohérence avec step-by-step
const { StepExecutor } = require('./StepExecutor');
const { injectGeneratedContent } = require('./ContentAssembly');
const { saveGeneratedArticleOrganic } = require('./ArticleStorage');

// Imports modules modulaires
const { applySelectiveLayer } = require('./selective-enhancement/SelectiveCore');
const { 
  applyPredefinedStack, 
  applyAdaptiveLayers,
  getAvailableStacks 
} = require('./selective-enhancement/SelectiveLayers');
const { 
  applyAdversarialLayer 
} = require('./adversarial-generation/AdversarialCore');
const { 
  applyPredefinedStack: applyAdversarialStack 
} = require('./adversarial-generation/AdversarialLayers');
const {
  applyHumanSimulationLayer
} = require('./human-simulation/HumanSimulationCore');
const {
  applyPredefinedSimulation,
  getAvailableSimulationStacks,
  recommendSimulationStack
} = require('./human-simulation/HumanSimulationLayers');
const {
  applyPatternBreakingLayer
} = require('./pattern-breaking/PatternBreakingCore');
const {
  applyPatternBreakingStack,
  recommendPatternBreakingStack,
  listAvailableStacks: listPatternBreakingStacks
} = require('./pattern-breaking/PatternBreakingLayers');

/**
 * WORKFLOW MODULAIRE AVEC DONNÉES FOURNIES (COMPATIBILITÉ MAKE.COM/DIGITAL OCEAN)
 */
async function handleModularWorkflowWithData(data, config = {}) {
  return await tracer.run('Main.handleModularWorkflowWithData()', async () => {
    const {
      selectiveStack = 'standardEnhancement',
      adversarialMode = 'light', 
      humanSimulationMode = 'none',
      patternBreakingMode = 'none',
      saveIntermediateSteps = false,
      source = 'compatibility_mode'
    } = config;

    await tracer.annotate({
      modularWorkflow: true,
      compatibilityMode: true,
      selectiveStack,
      adversarialMode,
      humanSimulationMode,
      patternBreakingMode,
      source
    });

    const startTime = Date.now();
    logSh(`🚀 WORKFLOW MODULAIRE COMPATIBILITÉ DÉMARRÉ`, 'INFO');
    logSh(`   📊 Source: ${source} | Selective: ${selectiveStack} | Adversarial: ${adversarialMode}`, 'INFO');

    try {
      // Utiliser les données fournies directement (skippping phases 1-4)
      const csvData = data.csvData;
      const xmlTemplate = data.xmlTemplate;

      // Décoder XML si nécessaire
      let xmlString = xmlTemplate;
      if (xmlTemplate && !xmlTemplate.startsWith('<?xml') && !xmlTemplate.startsWith('<')) {
        xmlString = Buffer.from(xmlTemplate, 'base64').toString('utf8');
      }
      csvData.xmlTemplate = xmlString;

      // ========================================
      // PHASE 2-4: EXTRACTION ÉLÉMENTS (SIMPLIFIÉ)
      // ========================================
      logSh(`📝 PHASE 2-4: Extraction éléments et préparation`, 'INFO');
      
      const elements = await extractElements(xmlString, csvData);
      const finalElements = await generateMissingKeywords(elements, csvData);
      
      // S'assurer que finalElements est un array
      const elementsArray = Array.isArray(finalElements) ? finalElements : 
        (finalElements && typeof finalElements === 'object') ? Object.values(finalElements) : [];
      
      const hierarchy = await buildSmartHierarchy(elementsArray);
      
      logSh(`   ✅ ${Object.keys(hierarchy).length} sections hiérarchisées`, 'DEBUG');

      // ========================================
      // PHASE 5-8B: WORKFLOW MODULAIRE COMPLET
      // ========================================
      
      // Continuer avec le workflow modulaire normal
      const executor = new StepExecutor();
      const generationResult = await executor.executeInitialGeneration(csvData, { hierarchy });
      const generatedContent = generationResult.content || generationResult;
      logSh(`   ✅ ${Object.keys(generatedContent).length} éléments générés`, 'DEBUG');

      // Appliquer toutes les couches modulaires comme dans le workflow normal
      let finalContent = generatedContent;
      let versionHistory = [];
      let parentArticleId = null;

      // SELECTIVE ENHANCEMENT
      logSh(`🔧 PHASE 6: Selective Enhancement Modulaire (${selectiveStack})`, 'INFO');
      
      let selectiveResult;
      if (selectiveStack === 'adaptive') {
        selectiveResult = await applyAdaptiveLayers(finalContent, {
          maxIntensity: 1.1,
          analysisThreshold: 0.3,
          csvData
        });
      } else {
        selectiveResult = await applyPredefinedStack(finalContent, selectiveStack, {
          csvData,
          analysisMode: true
        });
      }
      
      finalContent = selectiveResult.content;
      logSh(`   ✅ Selective: ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} améliorations`, 'INFO');

      // ADVERSARIAL ENHANCEMENT
      if (adversarialMode !== 'none') {
        logSh(`🎯 PHASE 7: Adversarial Enhancement (${adversarialMode})`, 'INFO');
        
        let adversarialResult;
        if (adversarialMode === 'adaptive') {
          adversarialResult = await applyAdversarialLayer(finalContent, {
            detectorTarget: 'general',
            method: 'hybrid',
            intensity: 0.8,
            analysisMode: true
          });
        } else {
          const stackMapping = {
            light: 'lightDefense',
            standard: 'standardDefense', 
            heavy: 'heavyDefense'
          };
          
          adversarialResult = await applyAdversarialStack(finalContent, stackMapping[adversarialMode], {
            csvData
          });
        }
        
        if (adversarialResult && !adversarialResult.fallback) {
          finalContent = adversarialResult.content;
          logSh(`   ✅ Adversarial: ${adversarialResult.stats.elementsModified || 0} modifications`, 'INFO');
        }
      }

      // HUMAN SIMULATION & PATTERN BREAKING (si demandés)
      // ... Implémentations similaires au workflow complet

      // ASSEMBLAGE FINAL
      logSh(`🔗 PHASE 9: Assemblage et stockage final`, 'INFO');
      
      const assembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
      
      const storageResult = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
        version: '1.0',
        stage: 'final_version',
        source,
        adversarialMode,
        stageDescription: `Version finale compatibility mode`,
        useVersionedSheet: false
      });
      
      logSh(`   ✅ Stocké: ${storageResult.textLength} caractères`, 'DEBUG');

      // RÉSUMÉ FINAL
      const totalDuration = Date.now() - startTime;
      const finalStats = {
        source,
        selectiveStack,
        adversarialMode,
        totalDuration,
        elementsGenerated: Object.keys(generatedContent).length,
        finalLength: storageResult.textLength,
        personality: csvData.personality?.nom || 'Unknown'
      };

      logSh(`✅ WORKFLOW MODULAIRE COMPATIBILITÉ TERMINÉ (${totalDuration}ms)`, 'INFO');

      await tracer.event('Workflow modulaire compatibilité terminé', finalStats);

      return {
        success: true,
        stats: finalStats,
        content: finalContent,
        assembledContent,
        storageResult,
        xmlContent: assembledContent,
        generatedTexts: finalContent,
        elementsGenerated: finalElements.length,
        personality: csvData.personality?.nom || 'Unknown',
        csvData,
        timestamp: new Date().toISOString(),
        // Compatibilité avec l'ancien format de réponse
        antiDetectionLevel: 'Selective_Enhancement',
        llmsUsed: ['claude', 'openai', 'gemini', 'mistral'],
        enhancementApplied: true,
        workflowVersion: '2.0-Modular'
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ WORKFLOW MODULAIRE COMPATIBILITÉ ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
      logSh(`Stack trace: ${error.stack}`, 'ERROR');
      
      await tracer.event('Workflow modulaire compatibilité échoué', { 
        error: error.message, 
        duration,
        source
      });
      
      throw error;
    }
  }, { data, config });
}

/**
 * WORKFLOW MODULAIRE PRINCIPAL
 */
async function handleModularWorkflow(config = {}) {
  return await tracer.run('MainModulaire.handleModularWorkflow()', async () => {
    const {
      rowNumber = 2,
      selectiveStack = 'standardEnhancement',  // lightEnhancement, standardEnhancement, fullEnhancement, personalityFocus, fluidityFocus, adaptive
      adversarialMode = 'light',               // none, light, standard, heavy, adaptive
      humanSimulationMode = 'none',            // none, lightSimulation, standardSimulation, heavySimulation, adaptiveSimulation, personalityFocus, temporalFocus
      patternBreakingMode = 'none',            // none, lightPatternBreaking, standardPatternBreaking, heavyPatternBreaking, adaptivePatternBreaking, syntaxFocus, connectorsFocus
      intensity = 1.0,                         // 0.5-1.5 intensité générale
      trendManager = null,                     // Instance TrendManager pour tendances
      saveIntermediateSteps = true,            // 🆕 NOUVELLE OPTION: Sauvegarder chaque étape
      source = 'main_modulaire'
    } = config;

    await tracer.annotate({
      modularWorkflow: true,
      rowNumber,
      selectiveStack,
      adversarialMode,
      humanSimulationMode,
      patternBreakingMode,
      source
    });

    const startTime = Date.now();
    logSh(`🚀 WORKFLOW MODULAIRE DÉMARRÉ`, 'INFO');
    logSh(`   📊 Ligne: ${rowNumber} | Selective: ${selectiveStack} | Adversarial: ${adversarialMode} | Human: ${humanSimulationMode} | Pattern: ${patternBreakingMode}`, 'INFO');

    try {
      // ========================================
      // PHASE 1: PRÉPARATION DONNÉES
      // ========================================
      logSh(`📋 PHASE 1: Préparation données`, 'INFO');
      
      const csvData = await readInstructionsData(rowNumber);
      if (!csvData) {
        throw new Error(`Impossible de lire les données ligne ${rowNumber}`);
      }
      
      const personalities = await getPersonalities();
      const selectedPersonality = await selectPersonalityWithAI(
        csvData.mc0,
        csvData.t0,
        personalities
      );
      
      csvData.personality = selectedPersonality;
      
      logSh(`   ✅ Données: ${csvData.mc0} | Personnalité: ${selectedPersonality.nom}`, 'DEBUG');

      // ========================================
      // PHASE 2: EXTRACTION ÉLÉMENTS
      // ========================================
      logSh(`📝 PHASE 2: Extraction éléments XML`, 'INFO');
      
      const elements = await extractElements(csvData.xmlTemplate, csvData);
      logSh(`   ✅ ${elements.length} éléments extraits`, 'DEBUG');

      // ========================================
      // PHASE 3: GÉNÉRATION MOTS-CLÉS MANQUANTS
      // ========================================
      logSh(`🔍 PHASE 3: Génération mots-clés manquants`, 'INFO');
      
      const finalElements = await generateMissingKeywords(elements, csvData);
      logSh(`   ✅ Mots-clés complétés`, 'DEBUG');

      // ========================================
      // PHASE 4: CONSTRUCTION HIÉRARCHIE
      // ========================================
      logSh(`🏗️ PHASE 4: Construction hiérarchie`, 'INFO');
      
      const hierarchy = await buildSmartHierarchy(finalElements);
      logSh(`   ✅ ${Object.keys(hierarchy).length} sections hiérarchisées`, 'DEBUG');

      // ========================================
      // PHASE 5: GÉNÉRATION CONTENU DE BASE
      // ========================================
      logSh(`💫 PHASE 5: Génération contenu de base`, 'INFO');
      
      const executor = new StepExecutor();
      const generationResult = await executor.executeInitialGeneration(csvData, { hierarchy });
      const generatedContent = generationResult.content;
      
      logSh(`   ✅ ${Object.keys(generatedContent).length} éléments générés`, 'DEBUG');

      // 🆕 SAUVEGARDE ÉTAPE 1: Génération initiale
      let parentArticleId = null;
      let versionHistory = [];

      logSh(`🔍 DEBUG: saveIntermediateSteps = ${saveIntermediateSteps}`, 'INFO');

      if (saveIntermediateSteps) {
        logSh(`💾 SAUVEGARDE v1.0: Génération initiale`, 'INFO');
        
        const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
        const initialAssembledContent = await injectGeneratedContent(xmlString, generatedContent, finalElements);
        
        const initialStorage = await saveGeneratedArticleOrganic({ generatedTexts: generatedContent }, csvData, {
          version: 'v1.0',
          stage: 'initial_generation',
          source: `${source}_initial`,
          adversarialMode: 'none',
          stageDescription: 'Génération de contenu de base sans améliorations',
          useVersionedSheet: true  // 🆕 Utiliser Generated_Articles_Versioned
        });
        
        parentArticleId = initialStorage.articleId;
        versionHistory.push({
          version: 'v1.0',
          stage: 'initial_generation',
          articleId: initialStorage.articleId,
          length: initialStorage.textLength,
          wordCount: initialStorage.wordCount
        });
        
        logSh(`   ✅ Sauvé v1.0 - ID: ${parentArticleId}`, 'DEBUG');
      }

      // ========================================
      // PHASE 6: SELECTIVE ENHANCEMENT MODULAIRE
      // ========================================
      logSh(`🔧 PHASE 6: Selective Enhancement Modulaire (${selectiveStack})`, 'INFO');
      
      let selectiveResult;
      
      switch (selectiveStack) {
        case 'adaptive':
          selectiveResult = await applyAdaptiveLayers(generatedContent, {
            maxIntensity: 1.1,
            analysisThreshold: 0.3,
            csvData
          });
          break;
          
        case 'technical':
        case 'transitions':  
        case 'style':
          selectiveResult = await applySelectiveLayer(generatedContent, {
            layerType: selectiveStack,
            llmProvider: 'auto',
            intensity: 1.0,
            csvData
          });
          break;
          
        default:
          // Stack prédéfini avec support tendances
          selectiveResult = await applyPredefinedStack(generatedContent, selectiveStack, {
            csvData,
            analysisMode: true,
            intensity,
            trendManager
          });
      }
      
      const enhancedContent = selectiveResult.content;
      
      logSh(`   ✅ Selective: ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} améliorations`, 'INFO');

      // 🆕 SAUVEGARDE ÉTAPE 2: Selective Enhancement
      if (saveIntermediateSteps) {
        logSh(`💾 SAUVEGARDE v1.1: Selective Enhancement`, 'INFO');
        
        const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
        const selectiveAssembledContent = await injectGeneratedContent(xmlString, enhancedContent, finalElements);
        
        const selectiveStorage = await saveGeneratedArticleOrganic({ generatedTexts: enhancedContent }, csvData, {
          version: 'v1.1',
          stage: 'selective_enhancement',
          source: `${source}_selective_${selectiveStack}`,
          adversarialMode: 'none',
          stageDescription: `Amélioration selective (${selectiveStack}) - ${selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0} modifications`,
          parentArticleId: parentArticleId,
          useVersionedSheet: true  // 🆕 Utiliser Generated_Articles_Versioned
        });
        
        versionHistory.push({
          version: 'v1.1',
          stage: 'selective_enhancement',
          articleId: selectiveStorage.articleId,
          length: selectiveStorage.textLength,
          wordCount: selectiveStorage.wordCount,
          modifications: selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0
        });
        
        logSh(`   ✅ Sauvé v1.1 - ID: ${selectiveStorage.articleId}`, 'DEBUG');
      }
      
      // ========================================
      // PHASE 7: ADVERSARIAL ENHANCEMENT (OPTIONNEL)
      // ========================================
      let finalContent = enhancedContent;
      let adversarialStats = null;
      
      if (adversarialMode !== 'none') {
        logSh(`🎯 PHASE 7: Adversarial Enhancement (${adversarialMode})`, 'INFO');
        
        let adversarialResult;
        
        switch (adversarialMode) {
          case 'adaptive':
            // Utiliser adversarial adaptatif
            adversarialResult = await applyAdversarialLayer(enhancedContent, {
              detectorTarget: 'general',
              method: 'hybrid',
              intensity: 0.8,
              analysisMode: true
            });
            break;
            
          case 'light':
          case 'standard':
          case 'heavy':
            // Utiliser stack adversarial prédéfini
            const stackMapping = {
              light: 'lightDefense',
              standard: 'standardDefense', 
              heavy: 'heavyDefense'
            };
            
            adversarialResult = await applyAdversarialStack(enhancedContent, stackMapping[adversarialMode], {
              csvData
            });
            break;
        }
        
        if (adversarialResult && !adversarialResult.fallback) {
          finalContent = adversarialResult.content;
          adversarialStats = adversarialResult.stats;
          
          logSh(`   ✅ Adversarial: ${adversarialStats.elementsModified || adversarialStats.totalModifications || 0} modifications`, 'INFO');
          
          // 🆕 SAUVEGARDE ÉTAPE 3: Adversarial Enhancement
          if (saveIntermediateSteps) {
            logSh(`💾 SAUVEGARDE v1.2: Adversarial Enhancement`, 'INFO');
            
            const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
            const adversarialAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
            
            const adversarialStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
              version: 'v1.2',
              stage: 'adversarial_enhancement',
              source: `${source}_adversarial_${adversarialMode}`,
              adversarialMode,
              stageDescription: `Amélioration adversarial (${adversarialMode}) - ${adversarialStats.elementsModified || adversarialStats.totalModifications || 0} modifications`,
              parentArticleId: parentArticleId,
              useVersionedSheet: true  // 🆕 Utiliser Generated_Articles_Versioned
            });
            
            versionHistory.push({
              version: 'v1.2',
              stage: 'adversarial_enhancement',
              articleId: adversarialStorage.articleId,
              length: adversarialStorage.textLength,
              wordCount: adversarialStorage.wordCount,
              modifications: adversarialStats.elementsModified || adversarialStats.totalModifications || 0
            });
            
            logSh(`   ✅ Sauvé v1.2 - ID: ${adversarialStorage.articleId}`, 'DEBUG');
          }
        } else {
          logSh(`   ⚠️ Adversarial fallback: contenu selective préservé`, 'WARNING');
        }
      }

      // ========================================
      // PHASE 8: HUMAN SIMULATION (NIVEAU 5)
      // ========================================
      let humanSimulationStats = null;
      
      if (humanSimulationMode !== 'none') {
        logSh(`🧠 PHASE 8: Human Simulation (${humanSimulationMode})`, 'INFO');
        
        let humanSimulationResult;
        
        try {
          // Calculer éléments pour simulation fatigue
          const totalElements = Object.keys(finalContent).length;
          const elementIndex = Math.floor(totalElements * 0.6); // Position simulée milieu-fin pour fatigue
          
          // Configuration simulation
          const simulationConfig = {
            elementIndex,
            totalElements,
            currentHour: new Date().getHours(),
            csvData,
            source: `human_simulation_${humanSimulationMode}`
          };
          
          // Application selon mode
          switch (humanSimulationMode) {
            case 'adaptiveSimulation':
              // Recommandation automatique si adaptive
              const context = {
                contentLength: Object.values(finalContent).join('').length,
                personality: csvData.personality?.nom,
                hour: new Date().getHours(),
                goal: 'adaptive'
              };
              const recommendedStack = recommendSimulationStack(context);
              logSh(`   🤖 Recommandation adaptive: ${recommendedStack}`, 'DEBUG');
              
              humanSimulationResult = await applyPredefinedSimulation(finalContent, recommendedStack, simulationConfig);
              break;
              
            case 'lightSimulation':
            case 'standardSimulation': 
            case 'heavySimulation':
            case 'personalityFocus':
            case 'temporalFocus':
              // Stack prédéfini
              humanSimulationResult = await applyPredefinedSimulation(finalContent, humanSimulationMode, simulationConfig);
              break;
              
            default:
              // Mode custom ou direct
              humanSimulationResult = await applyHumanSimulationLayer(finalContent, simulationConfig);
          }
          
          // Vérification résultat
          if (humanSimulationResult && !humanSimulationResult.fallback) {
            finalContent = humanSimulationResult.content;
            humanSimulationStats = humanSimulationResult.stats;
            
            logSh(`   ✅ Human Simulation: ${humanSimulationStats.totalModifications || 0} modifications`, 'INFO');
            logSh(`   🎯 Score qualité: ${humanSimulationResult.qualityScore?.toFixed(2) || 'N/A'}`, 'INFO');
            
            // 🆕 SAUVEGARDE ÉTAPE 4: Human Simulation
            if (saveIntermediateSteps) {
              logSh(`💾 SAUVEGARDE v1.3: Human Simulation`, 'INFO');
              
              const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
              const humanAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
              
              const humanStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
                version: 'v1.3',
                stage: 'human_simulation',
                source: `${source}_human_${humanSimulationMode}`,
                adversarialMode,
                stageDescription: `Simulation humaine (${humanSimulationMode}) - ${humanSimulationStats.totalModifications || 0} modifications`,
                parentArticleId: parentArticleId,
                useVersionedSheet: true  // 🆕 Utiliser Generated_Articles_Versioned
              });
              
              versionHistory.push({
                version: 'v1.3',
                stage: 'human_simulation',
                articleId: humanStorage.articleId,
                length: humanStorage.textLength,
                wordCount: humanStorage.wordCount,
                modifications: humanSimulationStats.totalModifications || 0,
                qualityScore: humanSimulationResult.qualityScore
              });
              
              logSh(`   ✅ Sauvé v1.3 - ID: ${humanStorage.articleId}`, 'DEBUG');
            }
          } else {
            logSh(`   ⚠️ Human Simulation fallback: contenu précédent préservé`, 'WARNING');
          }
          
        } catch (humanSimulationError) {
          logSh(`   ❌ Erreur Human Simulation: ${humanSimulationError.message}`, 'ERROR');
          logSh(`   🔄 Fallback: contenu adversarial préservé`, 'INFO');
        }
      }

      // ========================================
      // PHASE 8B: PATTERN BREAKING (NIVEAU 2)
      // ========================================
      let patternBreakingStats = null;
      
      if (patternBreakingMode !== 'none') {
        logSh(`🔧 PHASE 8B: Pattern Breaking (${patternBreakingMode})`, 'INFO');
        
        let patternBreakingResult;
        
        try {
          // Configuration Pattern Breaking
          const patternConfig = {
            csvData,
            source: `pattern_breaking_${patternBreakingMode}`,
            personality: csvData.personality
          };
          
          // Application selon mode
          switch (patternBreakingMode) {
            case 'adaptivePatternBreaking':
              // Recommandation automatique si adaptive
              const patternContext = {
                contentLength: Object.values(finalContent).join('').length,
                critical: false,
                preserveQuality: true
              };
              const recommendedPattern = recommendPatternBreakingStack(Object.values(finalContent).join(' '), patternContext);
              logSh(`   🤖 Recommandation Pattern Breaking: ${recommendedPattern.recommendedStack}`, 'DEBUG');
              
              patternBreakingResult = await applyPatternBreakingStack(recommendedPattern.recommendedStack, finalContent, patternConfig);
              break;
              
            case 'lightPatternBreaking':
            case 'standardPatternBreaking': 
            case 'heavyPatternBreaking':
            case 'syntaxFocus':
            case 'connectorsFocus':
              // Stack prédéfini
              patternBreakingResult = await applyPatternBreakingStack(patternBreakingMode, finalContent, patternConfig);
              break;
              
            default:
              // Mode custom ou direct
              patternBreakingResult = await applyPatternBreakingLayer(finalContent, patternConfig);
          }
          
          // Vérification résultat
          if (patternBreakingResult && !patternBreakingResult.fallback) {
            finalContent = patternBreakingResult.content;
            patternBreakingStats = patternBreakingResult.stats;
            
            logSh(`   ✅ Pattern Breaking: ${patternBreakingStats.totalModifications || 0} modifications`, 'INFO');
            logSh(`   🎯 Patterns détectés: ${patternBreakingStats.patternsDetected || 0}`, 'INFO');
            
            // 🆕 SAUVEGARDE ÉTAPE 5: Pattern Breaking
            if (saveIntermediateSteps) {
              logSh(`💾 SAUVEGARDE v1.4: Pattern Breaking`, 'INFO');
              
              const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
              const patternAssembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
              
              const patternStorage = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
                version: 'v1.4',
                stage: 'pattern_breaking',
                source: `${source}_pattern_${patternBreakingMode}`,
                adversarialMode,
                stageDescription: `Pattern Breaking (${patternBreakingMode}) - ${patternBreakingStats.totalModifications || 0} modifications`,
                parentArticleId: parentArticleId,
                useVersionedSheet: true  // 🆕 Utiliser Generated_Articles_Versioned
              });
              
              versionHistory.push({
                version: 'v1.4',
                stage: 'pattern_breaking',
                articleId: patternStorage.articleId,
                length: patternStorage.textLength,
                wordCount: patternStorage.wordCount,
                modifications: patternBreakingStats.totalModifications || 0,
                patternsDetected: patternBreakingStats.patternsDetected || 0
              });
              
              logSh(`   ✅ Sauvé v1.4 - ID: ${patternStorage.articleId}`, 'DEBUG');
            }
          } else {
            logSh(`   ⚠️ Pattern Breaking fallback: contenu précédent préservé`, 'WARNING');
          }
          
        } catch (patternBreakingError) {
          logSh(`   ❌ Erreur Pattern Breaking: ${patternBreakingError.message}`, 'ERROR');
          logSh(`   🔄 Fallback: contenu précédent préservé`, 'INFO');
        }
      }

      // ========================================
      // PHASE 9: ASSEMBLAGE ET STOCKAGE FINAL
      // ========================================
      logSh(`🔗 PHASE 9: Assemblage et stockage final`, 'INFO');
      
      // D'abord récupérer le XML décodé et les finalElements
      const xmlString = csvData.xmlTemplate.startsWith('<?xml') ? csvData.xmlTemplate : Buffer.from(csvData.xmlTemplate, 'base64').toString('utf8');
      const assembledContent = await injectGeneratedContent(xmlString, finalContent, finalElements);
      
      // 🆕 SAUVEGARDE VERSION FINALE
      const finalSourceTag = `${source}_${selectiveStack}${adversarialMode !== 'none' ? `_${adversarialMode}` : ''}${humanSimulationMode !== 'none' ? `_${humanSimulationMode}` : ''}${patternBreakingMode !== 'none' ? `_${patternBreakingMode}` : ''}`;
      
      const storageResult = await saveGeneratedArticleOrganic({ generatedTexts: finalContent }, csvData, {
        version: saveIntermediateSteps ? 'v2.0' : '1.0',
        stage: 'final_version',
        source: finalSourceTag,
        adversarialMode,
        stageDescription: `Version finale complète avec toutes améliorations`,
        parentArticleId: parentArticleId,
        versionHistory: saveIntermediateSteps ? versionHistory : undefined,
        useVersionedSheet: false  // 🆕 Version finale → Generated_Articles (comme avant)
      });
      
      // Ajouter la version finale à l'historique
      if (saveIntermediateSteps) {
        versionHistory.push({
          version: 'v2.0',
          stage: 'final_version',
          articleId: storageResult.articleId,
          length: storageResult.textLength,
          wordCount: storageResult.wordCount
        });
        
        logSh(`💾 SAUVEGARDE v2.0: Version finale`, 'INFO');
        logSh(`   📋 Historique complet: ${versionHistory.length} versions`, 'INFO');
      }
      
      logSh(`   ✅ Stocké: ${storageResult.textLength} caractères`, 'DEBUG');

      // ========================================
      // RÉSUMÉ FINAL
      // ========================================
      const totalDuration = Date.now() - startTime;
      const finalStats = {
        rowNumber,
        selectiveStack,
        adversarialMode,
        humanSimulationMode,
        patternBreakingMode,
        totalDuration,
        elementsGenerated: Object.keys(generatedContent).length,
        selectiveEnhancements: selectiveResult.stats.elementsEnhanced || selectiveResult.stats.totalModifications || 0,
        adversarialModifications: adversarialStats?.elementsModified || adversarialStats?.totalModifications || 0,
        humanSimulationModifications: humanSimulationStats?.totalModifications || 0,
        patternBreakingModifications: patternBreakingStats?.totalModifications || 0,
        finalLength: storageResult.textLength,
        personality: selectedPersonality.nom,
        source,
        versionHistory: saveIntermediateSteps ? versionHistory : undefined,
        parentArticleId: parentArticleId
      };

      logSh(`✅ WORKFLOW MODULAIRE TERMINÉ (${totalDuration}ms)`, 'INFO');
      logSh(`   📊 ${finalStats.elementsGenerated} générés | ${finalStats.selectiveEnhancements} selective | ${finalStats.adversarialModifications} adversarial | ${finalStats.humanSimulationModifications} humain | ${finalStats.patternBreakingModifications} pattern`, 'INFO');
      logSh(`   🎭 Personnalité: ${finalStats.personality} | Taille finale: ${finalStats.finalLength} chars`, 'INFO');

      await tracer.event('Workflow modulaire terminé', finalStats);

      return {
        success: true,
        stats: finalStats,
        content: finalContent,
        assembledContent,
        storageResult,
        selectiveResult,
        adversarialResult: adversarialStats ? { stats: adversarialStats } : null,
        humanSimulationResult: humanSimulationStats ? { stats: humanSimulationStats } : null,
        patternBreakingResult: patternBreakingStats ? { stats: patternBreakingStats } : null
      };

    } catch (error) {
      const duration = Date.now() - startTime;
      logSh(`❌ WORKFLOW MODULAIRE ÉCHOUÉ après ${duration}ms: ${error.message}`, 'ERROR');
      logSh(`Stack trace: ${error.stack}`, 'ERROR');
      
      await tracer.event('Workflow modulaire échoué', { 
        error: error.message, 
        duration, 
        rowNumber, 
        selectiveStack, 
        adversarialMode,
        humanSimulationMode,
        patternBreakingMode 
      });
      
      throw error;
    }
  }, { config });
}

/**
 * BENCHMARK COMPARATIF STACKS
 */
async function benchmarkStacks(rowNumber = 2) {
  console.log('\n⚡ === BENCHMARK STACKS MODULAIRES ===\n');
  
  const stacks = getAvailableStacks();
  const adversarialModes = ['none', 'light', 'standard'];
  const humanSimulationModes = ['none', 'lightSimulation', 'standardSimulation'];
  const patternBreakingModes = ['none', 'lightPatternBreaking', 'standardPatternBreaking'];
  
  const results = [];
  
  for (const stack of stacks.slice(0, 2)) { // Tester 2 stacks principaux
    for (const advMode of adversarialModes.slice(0, 2)) { // 2 modes adversarial  
      for (const humanMode of humanSimulationModes.slice(0, 2)) { // 2 modes human simulation
      for (const patternMode of patternBreakingModes.slice(0, 2)) { // 2 modes pattern breaking
        
        console.log(`🧪 Test: ${stack.name} + adversarial ${advMode} + human ${humanMode} + pattern ${patternMode}`);
        
        try {
          const startTime = Date.now();
          
          const result = await handleModularWorkflow({
            rowNumber,
            selectiveStack: stack.name,
            adversarialMode: advMode,
            humanSimulationMode: humanMode,
            patternBreakingMode: patternMode,
            source: 'benchmark'
          });
        
        const duration = Date.now() - startTime;
        
          results.push({
            stack: stack.name,
            adversarial: advMode,
            humanSimulation: humanMode,
            patternBreaking: patternMode,
            duration,
            success: true,
            selectiveEnhancements: result.stats.selectiveEnhancements,
            adversarialModifications: result.stats.adversarialModifications,
            humanSimulationModifications: result.stats.humanSimulationModifications,
            patternBreakingModifications: result.stats.patternBreakingModifications,
            finalLength: result.stats.finalLength
          });
          
          console.log(`   ✅ ${duration}ms | ${result.stats.selectiveEnhancements} selective | ${result.stats.adversarialModifications} adversarial | ${result.stats.humanSimulationModifications} humain | ${result.stats.patternBreakingModifications} pattern`);
        
        } catch (error) {
          results.push({
            stack: stack.name,
            adversarial: advMode,
            humanSimulation: humanMode,
            patternBreaking: patternMode,
            success: false,
            error: error.message
          });
          
          console.log(`   ❌ Échoué: ${error.message}`);
        }
      }
      }
    }
  }
  
  // Résumé benchmark
  console.log('\n📊 RÉSUMÉ BENCHMARK:');
  
  const successful = results.filter(r => r.success);
  if (successful.length > 0) {
    const avgDuration = successful.reduce((sum, r) => sum + r.duration, 0) / successful.length;
    const bestPerf = successful.reduce((best, r) => r.duration < best.duration ? r : best);
    const mostEnhancements = successful.reduce((best, r) => {
      const rTotal = r.selectiveEnhancements + r.adversarialModifications + (r.humanSimulationModifications || 0) + (r.patternBreakingModifications || 0);
      const bestTotal = best.selectiveEnhancements + best.adversarialModifications + (best.humanSimulationModifications || 0) + (best.patternBreakingModifications || 0);
      return rTotal > bestTotal ? r : best;
    });
    
    console.log(`   ⚡ Durée moyenne: ${avgDuration.toFixed(0)}ms`);
    console.log(`   🏆 Meilleure perf: ${bestPerf.stack} + ${bestPerf.adversarial} + ${bestPerf.humanSimulation} + ${bestPerf.patternBreaking} (${bestPerf.duration}ms)`);
    console.log(`   🔥 Plus d'améliorations: ${mostEnhancements.stack} + ${mostEnhancements.adversarial} + ${mostEnhancements.humanSimulation} + ${mostEnhancements.patternBreaking} (${mostEnhancements.selectiveEnhancements + mostEnhancements.adversarialModifications + (mostEnhancements.humanSimulationModifications || 0) + (mostEnhancements.patternBreakingModifications || 0)})`);
  }
  
  return results;
}

/**
 * INTERFACE LIGNE DE COMMANDE
 */
async function main() {
  const args = process.argv.slice(2);
  const command = args[0] || 'workflow';
  
  try {
    switch (command) {
      case 'workflow':
        const rowNumber = parseInt(args[1]) || 2;
        const selectiveStack = args[2] || 'standardEnhancement';
        const adversarialMode = args[3] || 'light';
        const humanSimulationMode = args[4] || 'none';
        const patternBreakingMode = args[5] || 'none';
        
        console.log(`\n🚀 Exécution workflow modulaire:`);
        console.log(`   📊 Ligne: ${rowNumber}`);
        console.log(`   🔧 Stack selective: ${selectiveStack}`);
        console.log(`   🎯 Mode adversarial: ${adversarialMode}`);
        console.log(`   🧠 Mode human simulation: ${humanSimulationMode}`);
        console.log(`   🔧 Mode pattern breaking: ${patternBreakingMode}`);
        
        const result = await handleModularWorkflow({
          rowNumber,
          selectiveStack,
          adversarialMode,
          humanSimulationMode,
          patternBreakingMode,
          source: 'cli'
        });
        
        console.log('\n✅ WORKFLOW MODULAIRE RÉUSSI');
        console.log(`📈 Stats: ${JSON.stringify(result.stats, null, 2)}`);
        break;
        
      case 'benchmark':
        const benchRowNumber = parseInt(args[1]) || 2;
        
        console.log(`\n⚡ Benchmark stacks (ligne ${benchRowNumber})`);
        const benchResults = await benchmarkStacks(benchRowNumber);
        
        console.log('\n📊 Résultats complets:');
        console.table(benchResults);
        break;
        
      case 'stacks':
        console.log('\n📦 STACKS SELECTIVE DISPONIBLES:');
        const availableStacks = getAvailableStacks();
        availableStacks.forEach(stack => {
          console.log(`\n   🔧 ${stack.name}:`);
          console.log(`      📝 ${stack.description}`);
          console.log(`      📊 ${stack.layersCount} couches`);
          console.log(`      🎯 Couches: ${stack.layers ? stack.layers.map(l => `${l.type}(${l.llm})`).join(' → ') : 'N/A'}`);
        });
        
        console.log('\n🎯 MODES ADVERSARIAL DISPONIBLES:');
        console.log('   - none: Pas d\'adversarial');
        console.log('   - light: Défense légère');
        console.log('   - standard: Défense standard');
        console.log('   - heavy: Défense intensive');
        console.log('   - adaptive: Adaptatif intelligent');
        
        console.log('\n🧠 MODES HUMAN SIMULATION DISPONIBLES:');
        const humanStacks = getAvailableSimulationStacks();
        humanStacks.forEach(stack => {
          console.log(`\n   🎭 ${stack.name}:`);
          console.log(`      📝 ${stack.description}`);
          console.log(`      📊 ${stack.layersCount} couches`);
          console.log(`      ⚡ ${stack.expectedImpact.modificationsPerElement} modifs | ${stack.expectedImpact.detectionReduction} anti-détection`);
        });
        break;
        
      case 'help':
      default:
        console.log('\n🔧 === MAIN MODULAIRE - USAGE ===');
        console.log('\nCommandes disponibles:');
        console.log('  workflow [ligne] [stack] [adversarial] [human]  - Exécuter workflow complet');
        console.log('  benchmark [ligne]                                - Benchmark stacks');
        console.log('  stacks                                           - Lister stacks disponibles');
        console.log('  help                                             - Afficher cette aide');
        console.log('\nExemples:');
        console.log('  node main_modulaire.js workflow 2 standardEnhancement light standardSimulation');
        console.log('  node main_modulaire.js workflow 3 adaptive standard heavySimulation');
        console.log('  node main_modulaire.js workflow 2 fullEnhancement none personalityFocus');
        console.log('  node main_modulaire.js benchmark 2');
        console.log('  node main_modulaire.js stacks');
        break;
    }
    
  } catch (error) {
    console.error('\n❌ ERREUR MAIN MODULAIRE:', error.message);
    console.error(error.stack);
    process.exit(1);
  }
}

// Export pour usage programmatique (compatibilité avec l'ancien Main.js)
module.exports = {
  // ✨ NOUVEAU: Interface modulaire principale
  handleModularWorkflow,
  benchmarkStacks,
  
  // 🔄 COMPATIBILITÉ: Alias pour l'ancien handleFullWorkflow
  handleFullWorkflow: async (data) => {
    // 🆕 SYSTÈME DE PIPELINE FLEXIBLE
    // Si pipelineConfig est fourni, utiliser PipelineExecutor au lieu du workflow modulaire classique
    if (data.pipelineConfig) {
      logSh(`🎨 Détection pipeline flexible: ${data.pipelineConfig.name}`, 'INFO');

      const executor = new PipelineExecutor();
      const result = await executor.execute(
        data.pipelineConfig,
        data.rowNumber || 2,
        { stopOnError: data.stopOnError }
      );

      // Formater résultat pour compatibilité
      return {
        success: result.success,
        finalContent: result.finalContent,
        executionLog: result.executionLog,
        stats: {
          totalDuration: result.metadata.totalDuration,
          personality: result.metadata.personality,
          pipelineName: result.metadata.pipelineName,
          totalSteps: result.metadata.totalSteps,
          successfulSteps: result.metadata.successfulSteps
        }
      };
    }

    // Initialiser TrendManager si tendance spécifiée
    let trendManager = null;
    if (data.trendId) {
      trendManager = new TrendManager();
      await trendManager.setTrend(data.trendId);
      logSh(`🎯 Tendance appliquée: ${data.trendId}`, 'INFO');
    }

    // Mapper l'ancien format vers le nouveau format modulaire
    const config = {
      rowNumber: data.rowNumber,
      source: data.source || 'compatibility_mode',
      selectiveStack: data.selectiveStack || 'standardEnhancement',
      adversarialMode: data.adversarialMode || 'light',
      humanSimulationMode: data.humanSimulationMode || 'none',
      patternBreakingMode: data.patternBreakingMode || 'none',
      intensity: data.intensity || 1.0,
      trendManager: trendManager,
      saveIntermediateSteps: data.saveIntermediateSteps || false
    };

    // Si des données CSV sont fournies directement (Make.com style)
    if (data.csvData && data.xmlTemplate) {
      return handleModularWorkflowWithData(data, config);
    }

    // Sinon utiliser le workflow normal
    return handleModularWorkflow(config);
  },
  
  // 🔄 COMPATIBILITÉ: Autres exports utilisés par l'ancien système
  testMainWorkflow: () => {
    return handleModularWorkflow({
      rowNumber: 2,
      selectiveStack: 'standardEnhancement',
      source: 'test_main_nodejs'
    });
  },
  
  launchLogViewer: () => {
    // La fonction launchLogViewer est maintenant intégrée dans handleModularWorkflow
    console.log('✅ Log viewer sera lancé automatiquement avec le workflow');
  }
};

// Exécution CLI si appelé directement
if (require.main === module) {
  main().catch(error => {
    console.error('❌ ERREUR FATALE:', error.message);
    process.exit(1);
  });
}

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/test-manual.js                                          │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: test-manual.js - ENTRY POINT MANUEL
// Description: Test workflow ligne 2 Google Sheets
// Usage: node test-manual.js
// ========================================

require('./polyfills/fetch.cjs');
require('dotenv').config();

const { handleFullWorkflow } = require('./Main');
const { logSh } = require('./ErrorReporting');

/**
 * TEST MANUEL LIGNE 2
 */
async function testWorkflowLigne2() {
  logSh('🚀 === DÉMARRAGE TEST MANUEL LIGNE 2 ===', 'INFO'); // Using logSh instead of console.log
  
  const startTime = Date.now();
  
  try {
    // DONNÉES DE TEST POUR LIGNE 2
    const testData = {
      rowNumber: 2, // Ligne 2 Google Sheets
      source: 'test_manual_nodejs'
    };
    
    logSh('📊 Configuration test:', 'INFO'); // Using logSh instead of console.log
    logSh(`   • Ligne: ${testData.rowNumber}`, 'INFO'); // Using logSh instead of console.log
    logSh(`   • Source: ${testData.source}`, 'INFO'); // Using logSh instead of console.log
    logSh(`   • Timestamp: ${new Date().toISOString()}`, 'INFO'); // Using logSh instead of console.log
    
    // LANCER LE WORKFLOW
    logSh('\n🎯 Lancement workflow principal...', 'INFO'); // Using logSh instead of console.log
    const result = await handleFullWorkflow(testData);
    
    // AFFICHER RÉSULTATS
    const duration = Date.now() - startTime;
    logSh('\n🏆 === WORKFLOW TERMINÉ AVEC SUCCÈS ===', 'INFO'); // Using logSh instead of console.log
    logSh(`⏱️  Durée: ${Math.round(duration/1000)}s`, 'INFO'); // Using logSh instead of console.log
    logSh(`📊 Status: ${result.success ? '✅ SUCCESS' : '❌ ERROR'}`, 'INFO'); // Using logSh instead of console.log
    
    if (result.success) {
      logSh(`📝 Éléments générés: ${result.elementsGenerated}`, 'INFO'); // Using logSh instead of console.log
      logSh(`👤 Personnalité: ${result.personality}`, 'INFO'); // Using logSh instead of console.log
      logSh(`🎯 MC0: ${result.csvData?.mc0 || 'N/A'}`, 'INFO'); // Using logSh instead of console.log
      logSh(`📄 XML length: ${result.stats?.xmlLength || 'N/A'} chars`, 'INFO'); // Using logSh instead of console.log
      logSh(`🔤 Mots total: ${result.stats?.wordCount || 'N/A'}`, 'INFO'); // Using logSh instead of console.log
      logSh(`🧠 LLMs utilisés: ${result.llmsUsed?.join(', ') || 'N/A'}`, 'INFO'); // Using logSh instead of console.log
      
      if (result.articleStorage) {
        logSh(`💾 Article sauvé: ID ${result.articleStorage.articleId}`, 'INFO'); // Using logSh instead of console.log
      }
    }
    
    logSh('\n📋 Résultat complet:', 'DEBUG'); // Using logSh instead of console.log
    logSh(JSON.stringify(result, null, 2), 'DEBUG'); // Using logSh instead of console.log
    
    return result;
    
  } catch (error) {
    const duration = Date.now() - startTime;
    logSh('\n❌ === ERREUR WORKFLOW ===', 'ERROR'); // Using logSh instead of console.error
    logSh(`❌ Message: ${error.message}`, 'ERROR'); // Using logSh instead of console.error
    logSh(`❌ Durée avant échec: ${Math.round(duration/1000)}s`, 'ERROR'); // Using logSh instead of console.error
    
    if (process.env.NODE_ENV === 'development') {
      logSh(`❌ Stack: ${error.stack}`, 'ERROR'); // Using logSh instead of console.error
    }
    
    // Afficher conseils de debug
    logSh('\n🔧 CONSEILS DE DEBUG:', 'INFO'); // Using logSh instead of console.log
    logSh('1. Vérifiez vos variables d\'environnement (.env)', 'INFO'); // Using logSh instead of console.log
    logSh('2. Vérifiez la connexion Google Sheets', 'INFO'); // Using logSh instead of console.log
    logSh('3. Vérifiez les API keys LLM', 'INFO'); // Using logSh instead of console.log
    logSh('4. Regardez les logs détaillés dans ./logs/', 'INFO'); // Using logSh instead of console.log
    
    process.exit(1);
  }
}

/**
 * VÉRIFICATIONS PRÉALABLES
 */
function checkEnvironment() {
  logSh('🔍 Vérification environnement...', 'INFO'); // Using logSh instead of console.log
  
  const required = [
    'GOOGLE_SHEETS_ID',
    'OPENAI_API_KEY'
  ];
  
  const missing = required.filter(key => !process.env[key]);
  
  if (missing.length > 0) {
    logSh('❌ Variables d\'environnement manquantes:', 'ERROR'); // Using logSh instead of console.error
    missing.forEach(key => logSh(`   • ${key}`, 'ERROR')); // Using logSh instead of console.error
    logSh('\n💡 Créez un fichier .env avec ces variables', 'ERROR'); // Using logSh instead of console.error
    process.exit(1);
  }
  
  logSh('✅ Variables d\'environnement OK', 'INFO'); // Using logSh instead of console.log
  
  // Info sur les variables configurées
  logSh('📋 Configuration détectée:', 'INFO'); // Using logSh instead of console.log
  logSh(`   • Google Sheets ID: ${process.env.GOOGLE_SHEETS_ID}`, 'INFO'); // Using logSh instead of console.log
  logSh(`   • OpenAI: ${process.env.OPENAI_API_KEY ? '✅ Configuré' : '❌ Manquant'}`, 'INFO'); // Using logSh instead of console.log
  logSh(`   • Claude: ${process.env.CLAUDE_API_KEY ? '✅ Configuré' : '⚠️ Optionnel'}`, 'INFO'); // Using logSh instead of console.log
  logSh(`   • Gemini: ${process.env.GEMINI_API_KEY ? '✅ Configuré' : '⚠️ Optionnel'}`, 'INFO'); // Using logSh instead of console.log
}

/**
 * POINT D'ENTRÉE PRINCIPAL
 */
async function main() {
  try {
    // Vérifications préalables
    checkEnvironment();
    
    // Test workflow
    await testWorkflowLigne2();
    
    logSh('\n🎉 Test manuel terminé avec succès !', 'INFO'); // Using logSh instead of console.log
    process.exit(0);
    
  } catch (error) {
    logSh('\n💥 Erreur fatale: ' + error.message, 'ERROR'); // Using logSh instead of console.error
    process.exit(1);
  }
}

// Lancer si exécuté directement
if (require.main === module) {
  main();
}

module.exports = { testWorkflowLigne2 };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/prompt-engine/DynamicPromptEngine.js                    │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// DYNAMIC PROMPT ENGINE - SYSTÈME AVANCÉ
// Responsabilité: Génération dynamique de prompts adaptatifs ultra-modulaires
// ========================================

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

/**
 * DYNAMIC PROMPT ENGINE
 * Système avancé de génération de prompts avec composition multi-niveaux
 */
class DynamicPromptEngine {
  constructor() {
    this.name = 'DynamicPromptEngine';
    this.templates = new Map();
    this.contextAnalyzers = new Map();
    this.adaptiveRules = new Map();

    // Initialiser templates par défaut
    this.initializeDefaultTemplates();
    this.initializeContextAnalyzers();
    this.initializeAdaptiveRules();
  }

  // ========================================
  // INITIALISATION TEMPLATES
  // ========================================

  initializeDefaultTemplates() {
    // Templates de base modulaires
    this.templates.set('technical', {
      meta: {
        role: "Tu es un expert {domain} avec {experience} d'expérience",
        expertise: "Spécialisé en {specialization} et {methods}",
        approach: "Adopte une approche {style} et {precision}"
      },
      context: {
        mission: "MISSION: {task_description}",
        domain_context: "CONTEXTE: {sector} - {activity_type}",
        target_audience: "PUBLIC: {audience_level} ({audience_characteristics})",
        constraints: "CONTRAINTES: {content_constraints}"
      },
      task: {
        primary_objective: "OBJECTIF PRINCIPAL: {main_goal}",
        specific_actions: "ACTIONS SPÉCIFIQUES:\n{action_list}",
        quality_criteria: "CRITÈRES DE QUALITÉ: {quality_requirements}",
        success_metrics: "MÉTRIQUES DE SUCCÈS: {success_indicators}"
      },
      instructions: {
        guidelines: "CONSIGNES {instruction_type}:\n{instruction_list}",
        restrictions: "INTERDICTIONS: {avoid_list}",
        emphasis: "PRIORITÉS: {emphasis_list}",
        style_guide: "STYLE: {style_requirements}"
      },
      examples: {
        format: "FORMAT ATTENDU:\n{format_example}",
        sample_input: "EXEMPLE D'ENTRÉE: {input_example}",
        sample_output: "EXEMPLE DE SORTIE: {output_example}"
      }
    });

    this.templates.set('style', {
      meta: {
        role: "Tu es un rédacteur expert en communication {communication_type}",
        personality: "Adopte la personnalité de {personality_profile}",
        tone_master: "Maîtrise parfaitement le ton {target_tone}"
      },
      context: {
        brand_voice: "IDENTITÉ: {brand_characteristics}",
        target_emotion: "ÉMOTION CIBLE: {desired_emotion}",
        communication_goal: "BUT COMMUNICATIONNEL: {communication_objective}",
        audience_psychology: "PSYCHOLOGIE AUDIENCE: {audience_mindset}"
      },
      task: {
        style_transformation: "TRANSFORMATION STYLISTIQUE: {transformation_type}",
        tone_adaptation: "ADAPTATION TONALE: {tone_specifications}",
        personality_injection: "INJECTION PERSONNALITÉ: {personality_traits}",
        emotional_calibration: "CALIBRAGE ÉMOTIONNEL: {emotional_targets}"
      }
    });

    this.templates.set('adversarial', {
      meta: {
        role: "Tu es un expert en rédaction naturelle anti-détection",
        stealth_mode: "Mode furtif niveau {stealth_level}",
        human_mimicry: "Imite parfaitement l'écriture humaine {human_characteristics}"
      },
      context: {
        detection_threats: "MENACES DÉTECTION: {detector_types}",
        target_metrics: "MÉTRIQUES CIBLES: {target_scores}",
        natural_patterns: "PATTERNS NATURELS: {natural_characteristics}",
        human_variance: "VARIANCE HUMAINE: {variance_patterns}"
      },
      task: {
        stealth_rewrite: "RÉÉCRITURE FURTIVE: {stealth_techniques}",
        pattern_breaking: "CASSAGE PATTERNS: {pattern_break_methods}",
        human_errors: "ERREURS HUMAINES: {human_error_types}",
        style_diversification: "DIVERSIFICATION: {diversification_methods}"
      }
    });

    logSh(`✅ ${this.templates.size} templates modulaires initialisés`, 'DEBUG');
  }

  initializeContextAnalyzers() {
    // Analyseurs de contexte automatiques
    this.contextAnalyzers.set('domain_inference', (content, csvData) => {
      const mc0 = csvData?.mc0?.toLowerCase() || '';

      if (mc0.includes('signalétique') || mc0.includes('plaque')) {
        return {
          domain: 'signalétique industrielle',
          specialization: 'communication visuelle B2B',
          sector: 'industrie/signalétique',
          activity_type: 'fabrication sur mesure'
        };
      }

      if (mc0.includes('bijou') || mc0.includes('gravure')) {
        return {
          domain: 'artisanat créatif',
          specialization: 'joaillerie personnalisée',
          sector: 'artisanat/luxe',
          activity_type: 'création artisanale'
        };
      }

      return {
        domain: 'communication visuelle',
        specialization: 'impression numérique',
        sector: 'services/impression',
        activity_type: 'prestation de services'
      };
    });

    this.contextAnalyzers.set('complexity_assessment', (content) => {
      const totalText = Object.values(content).join(' ');
      const technicalTerms = (totalText.match(/\b(technique|procédé|norme|ISO|DIN|matériau|aluminum|PMMA)\b/gi) || []).length;
      const complexity = technicalTerms / totalText.split(' ').length;

      return {
        complexity_level: complexity > 0.05 ? 'élevée' : complexity > 0.02 ? 'moyenne' : 'standard',
        technical_density: complexity,
        recommended_approach: complexity > 0.05 ? 'expert' : 'accessible'
      };
    });

    this.contextAnalyzers.set('audience_inference', (content, csvData, trend) => {
      const personality = csvData?.personality;

      if (trend?.id === 'generation-z') {
        return {
          audience_level: 'digital natives',
          audience_characteristics: 'connectés, inclusifs, authentiques',
          audience_mindset: 'recherche authenticité et transparence'
        };
      }

      if (personality?.style === 'technique') {
        return {
          audience_level: 'professionnels techniques',
          audience_characteristics: 'expérimentés, précis, orientés solutions',
          audience_mindset: 'recherche expertise et fiabilité'
        };
      }

      return {
        audience_level: 'grand public',
        audience_characteristics: 'curieux, pragmatiques, sensibles qualité',
        audience_mindset: 'recherche clarté et valeur ajoutée'
      };
    });

    logSh(`✅ ${this.contextAnalyzers.size} analyseurs de contexte initialisés`, 'DEBUG');
  }

  initializeAdaptiveRules() {
    // Règles d'adaptation conditionnelles
    this.adaptiveRules.set('intensity_scaling', {
      condition: (config) => config.intensity,
      adaptations: {
        low: (config) => ({
          precision: 'accessible',
          style: 'naturel et fluide',
          instruction_type: 'DOUCES',
          stealth_level: 'discret'
        }),
        medium: (config) => ({
          precision: 'équilibrée',
          style: 'professionnel et engageant',
          instruction_type: 'STANDARD',
          stealth_level: 'modéré'
        }),
        high: (config) => ({
          precision: 'maximale',
          style: 'expert et percutant',
          instruction_type: 'STRICTES',
          stealth_level: 'avancé'
        })
      },
      getLevel: (intensity) => {
        if (intensity < 0.7) return 'low';
        if (intensity < 1.2) return 'medium';
        return 'high';
      }
    });

    this.adaptiveRules.set('trend_adaptation', {
      condition: (config) => config.trend,
      adaptations: {
        'eco-responsable': {
          communication_type: 'responsable et engagée',
          desired_emotion: 'confiance et respect',
          brand_characteristics: 'éthique, durable, transparente',
          communication_objective: 'sensibiliser et rassurer'
        },
        'tech-innovation': {
          communication_type: 'moderne et dynamique',
          desired_emotion: 'excitation et confiance',
          brand_characteristics: 'innovante, performante, avant-gardiste',
          communication_objective: 'impressionner et convaincre'
        },
        'artisanal-premium': {
          communication_type: 'authentique et raffinée',
          desired_emotion: 'admiration et désir',
          brand_characteristics: 'traditionnelle, qualitative, exclusive',
          communication_objective: 'valoriser et différencier'
        }
      }
    });

    logSh(`✅ ${this.adaptiveRules.size} règles adaptatives initialisées`, 'DEBUG');
  }

  // ========================================
  // GÉNÉRATION DYNAMIQUE DE PROMPTS
  // ========================================

  /**
   * MAIN METHOD - Génère un prompt adaptatif complet
   */
  async generateAdaptivePrompt(config) {
    return await tracer.run('DynamicPromptEngine.generateAdaptivePrompt()', async () => {
      const {
        templateType = 'technical',
        content = {},
        csvData = null,
        trend = null,
        layerConfig = {},
        customVariables = {}
      } = config;

      await tracer.annotate({
        templateType,
        hasTrend: !!trend,
        contentSize: Object.keys(content).length,
        hasCustomVars: Object.keys(customVariables).length > 0
      });

      logSh(`🧠 Génération prompt adaptatif: ${templateType}`, 'INFO');

      try {
        // 1. ANALYSE CONTEXTUELLE AUTOMATIQUE
        const contextAnalysis = await this.analyzeContext(content, csvData, trend);

        // 2. APPLICATION RÈGLES ADAPTATIVES
        const adaptiveConfig = this.applyAdaptiveRules(layerConfig, trend, contextAnalysis);

        // 3. GÉNÉRATION VARIABLES DYNAMIQUES
        const dynamicVariables = this.generateDynamicVariables(
          contextAnalysis,
          adaptiveConfig,
          customVariables,
          layerConfig
        );

        // 4. COMPOSITION TEMPLATE MULTI-NIVEAUX
        const composedPrompt = this.composeMultiLevelPrompt(
          templateType,
          dynamicVariables,
          layerConfig
        );

        // 5. POST-PROCESSING ADAPTATIF
        const finalPrompt = this.postProcessPrompt(composedPrompt, adaptiveConfig);

        const stats = {
          templateType,
          variablesCount: Object.keys(dynamicVariables).length,
          adaptationRules: Object.keys(adaptiveConfig).length,
          promptLength: finalPrompt.length,
          contextComplexity: contextAnalysis.complexity_level
        };

        logSh(`✅ Prompt adaptatif généré: ${stats.promptLength} chars, ${stats.variablesCount} variables`, 'DEBUG');

        return {
          prompt: finalPrompt,
          metadata: {
            stats,
            contextAnalysis,
            adaptiveConfig,
            dynamicVariables: Object.keys(dynamicVariables)
          }
        };

      } catch (error) {
        logSh(`❌ Erreur génération prompt adaptatif: ${error.message}`, 'ERROR');
        throw error;
      }
    });
  }

  /**
   * ANALYSE CONTEXTUELLE AUTOMATIQUE
   */
  async analyzeContext(content, csvData, trend) {
    const context = {};

    // Exécuter tous les analyseurs
    for (const [analyzerName, analyzer] of this.contextAnalyzers) {
      try {
        const analysis = analyzer(content, csvData, trend);
        Object.assign(context, analysis);

        logSh(`   🔍 ${analyzerName}: ${JSON.stringify(analysis)}`, 'DEBUG');
      } catch (error) {
        logSh(`   ⚠️ Analyseur ${analyzerName} échoué: ${error.message}`, 'WARNING');
      }
    }

    return context;
  }

  /**
   * APPLICATION DES RÈGLES ADAPTATIVES
   */
  applyAdaptiveRules(layerConfig, trend, contextAnalysis) {
    const adaptiveConfig = {};

    for (const [ruleName, rule] of this.adaptiveRules) {
      try {
        if (rule.condition(layerConfig)) {
          let adaptation = {};

          if (ruleName === 'intensity_scaling') {
            const level = rule.getLevel(layerConfig.intensity || 1.0);
            adaptation = rule.adaptations[level](layerConfig);
          } else if (ruleName === 'trend_adaptation' && trend) {
            adaptation = rule.adaptations[trend.id] || {};
          }

          Object.assign(adaptiveConfig, adaptation);
          logSh(`   🎛️ Règle ${ruleName} appliquée`, 'DEBUG');
        }
      } catch (error) {
        logSh(`   ⚠️ Règle ${ruleName} échouée: ${error.message}`, 'WARNING');
      }
    }

    return adaptiveConfig;
  }

  /**
   * GÉNÉRATION VARIABLES DYNAMIQUES
   */
  generateDynamicVariables(contextAnalysis, adaptiveConfig, customVariables, layerConfig) {
    const variables = {
      // Variables contextuelles
      ...contextAnalysis,

      // Variables adaptatives
      ...adaptiveConfig,

      // Variables personnalisées
      ...customVariables,

      // Variables de configuration
      experience: this.generateExperienceLevel(contextAnalysis.complexity_level),
      methods: this.generateMethods(layerConfig),
      task_description: this.generateTaskDescription(layerConfig),
      action_list: this.generateActionList(layerConfig),
      instruction_list: this.generateInstructionList(layerConfig),

      // Variables dynamiques calculées
      timestamp: new Date().toISOString(),
      session_id: this.generateSessionId()
    };

    return variables;
  }

  /**
   * COMPOSITION TEMPLATE MULTI-NIVEAUX
   */
  composeMultiLevelPrompt(templateType, variables, layerConfig) {
    const template = this.templates.get(templateType);
    if (!template) {
      throw new Error(`Template ${templateType} introuvable`);
    }

    const sections = [];

    // Composer chaque niveau du template
    for (const [sectionName, sectionTemplate] of Object.entries(template)) {
      const composedSection = this.composeSection(sectionTemplate, variables);

      if (composedSection.trim()) {
        sections.push(composedSection);
      }
    }

    return sections.join('\n\n');
  }

  /**
   * COMPOSITION SECTION INDIVIDUELLE
   */
  composeSection(sectionTemplate, variables) {
    const lines = [];

    for (const [key, template] of Object.entries(sectionTemplate)) {
      const interpolated = this.interpolateTemplate(template, variables);

      if (interpolated && interpolated.trim() !== template) {
        lines.push(interpolated);
      }
    }

    return lines.join('\n');
  }

  /**
   * INTERPOLATION TEMPLATE AVEC VARIABLES
   */
  interpolateTemplate(template, variables) {
    return template.replace(/\{([^}]+)\}/g, (match, varName) => {
      return variables[varName] || match;
    });
  }

  /**
   * POST-PROCESSING ADAPTATIF
   */
  postProcessPrompt(prompt, adaptiveConfig) {
    let processed = prompt;

    // Suppression des lignes vides multiples
    processed = processed.replace(/\n\n\n+/g, '\n\n');

    // Suppression des variables non résolues
    processed = processed.replace(/\{[^}]+\}/g, '');

    // Suppression des lignes vides après suppression variables
    processed = processed.replace(/\n\s*\n/g, '\n\n');

    return processed.trim();
  }

  // ========================================
  // GÉNÉRATEURS HELPER
  // ========================================

  generateExperienceLevel(complexity) {
    switch (complexity) {
      case 'élevée': return '10+ années';
      case 'moyenne': return '5+ années';
      default: return '3+ années';
    }
  }

  generateMethods(layerConfig) {
    const methods = [];

    if (layerConfig.targetTerms?.length > 0) {
      methods.push('terminologie spécialisée');
    }
    if (layerConfig.focusAreas?.length > 0) {
      methods.push('approche métier');
    }

    return methods.length > 0 ? methods.join(', ') : 'méthodes éprouvées';
  }

  generateTaskDescription(layerConfig) {
    const type = layerConfig.layerType || 'enhancement';
    const descriptions = {
      technical: 'Améliore la précision technique et le vocabulaire spécialisé',
      style: 'Adapte le style et la personnalité du contenu',
      adversarial: 'Rend le contenu plus naturel et humain'
    };

    return descriptions[type] || 'Améliore le contenu selon les spécifications';
  }

  generateActionList(layerConfig) {
    const actions = [];

    if (layerConfig.targetTerms) {
      actions.push(`- Intégrer naturellement: ${layerConfig.targetTerms.slice(0, 5).join(', ')}`);
    }
    if (layerConfig.avoidTerms) {
      actions.push(`- Éviter absolument: ${layerConfig.avoidTerms.slice(0, 3).join(', ')}`);
    }

    actions.push('- Conserver le message original et la structure');
    actions.push('- Maintenir la cohérence stylistique');

    return actions.join('\n');
  }

  generateInstructionList(layerConfig) {
    const instructions = [
      'GARDE exactement le même sens et message',
      'PRÉSERVE la structure et la longueur approximative',
      'ASSURE-TOI que le résultat reste naturel et fluide'
    ];

    if (layerConfig.preservePersonality) {
      instructions.push('MAINTIENS la personnalité et le ton existants');
    }

    return instructions.map(i => `- ${i}`).join('\n');
  }

  generateSessionId() {
    return Math.random().toString(36).substring(2, 15);
  }

  // ========================================
  // API PUBLIQUE ÉTENDUE
  // ========================================

  /**
   * Ajouter template personnalisé
   */
  addCustomTemplate(name, template) {
    this.templates.set(name, template);
    logSh(`✨ Template personnalisé ajouté: ${name}`, 'INFO');
  }

  /**
   * Ajouter analyseur de contexte
   */
  addContextAnalyzer(name, analyzer) {
    this.contextAnalyzers.set(name, analyzer);
    logSh(`🔍 Analyseur personnalisé ajouté: ${name}`, 'INFO');
  }

  /**
   * Ajouter règle adaptative
   */
  addAdaptiveRule(name, rule) {
    this.adaptiveRules.set(name, rule);
    logSh(`🎛️ Règle adaptative ajoutée: ${name}`, 'INFO');
  }

  /**
   * Status du moteur
   */
  getEngineStatus() {
    return {
      templates: Array.from(this.templates.keys()),
      contextAnalyzers: Array.from(this.contextAnalyzers.keys()),
      adaptiveRules: Array.from(this.adaptiveRules.keys()),
      totalComponents: this.templates.size + this.contextAnalyzers.size + this.adaptiveRules.size
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/workflow-configuration/WorkflowEngine.js                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// WORKFLOW ENGINE - SÉQUENCES MODULAIRES CONFIGURABLES
// Responsabilité: Gestion flexible de l'ordre d'exécution des phases modulaires
// ========================================

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

// Import des modules disponibles
const { applySelectiveEnhancement } = require('../selective-enhancement/SelectiveCore');
const { applyAdversarialEnhancement } = require('../adversarial-generation/AdversarialCore');
const { applyHumanSimulation } = require('../human-simulation/HumanSimulationCore');
const { applyPatternBreaking } = require('../pattern-breaking/PatternBreakingCore');

/**
 * WORKFLOW ENGINE
 * Permet de configurer des séquences personnalisées de traitement modulaire
 */
class WorkflowEngine {
  constructor() {
    this.name = 'WorkflowEngine';
    this.predefinedSequences = new Map();
    this.customSequences = new Map();

    // Initialiser les séquences prédéfinies
    this.initializePredefinedSequences();
  }

  // ========================================
  // SÉQUENCES PRÉDÉFINIES
  // ========================================

  initializePredefinedSequences() {
    // Séquence par défaut (workflow actuel)
    this.predefinedSequences.set('default', {
      name: 'Default Workflow',
      description: 'Séquence standard: Selective → Adversarial → Human → Pattern',
      phases: [
        { type: 'selective', config: { enabled: true } },
        { type: 'adversarial', config: { enabled: true } },
        { type: 'human', config: { enabled: true } },
        { type: 'pattern', config: { enabled: true } }
      ]
    });

    // Séquence humanisée d'abord
    this.predefinedSequences.set('human-first', {
      name: 'Human-First Workflow',
      description: 'Humanisation d\'abord: Human → Pattern → Selective → Pattern',
      phases: [
        { type: 'human', config: { enabled: true } },
        { type: 'pattern', config: { enabled: true, iteration: 1 } },
        { type: 'selective', config: { enabled: true } },
        { type: 'pattern', config: { enabled: true, iteration: 2 } }
      ]
    });

    // Séquence anti-détection intensive
    this.predefinedSequences.set('stealth-intensive', {
      name: 'Stealth Intensive',
      description: 'Anti-détection max: Pattern → Adversarial → Human → Pattern → Adversarial',
      phases: [
        { type: 'pattern', config: { enabled: true, iteration: 1 } },
        { type: 'adversarial', config: { enabled: true, iteration: 1 } },
        { type: 'human', config: { enabled: true } },
        { type: 'pattern', config: { enabled: true, iteration: 2 } },
        { type: 'adversarial', config: { enabled: true, iteration: 2 } }
      ]
    });

    // Séquence qualité d'abord
    this.predefinedSequences.set('quality-first', {
      name: 'Quality-First Workflow',
      description: 'Qualité prioritaire: Selective → Human → Selective → Pattern',
      phases: [
        { type: 'selective', config: { enabled: true, iteration: 1 } },
        { type: 'human', config: { enabled: true } },
        { type: 'selective', config: { enabled: true, iteration: 2 } },
        { type: 'pattern', config: { enabled: true } }
      ]
    });

    // Séquence équilibrée
    this.predefinedSequences.set('balanced', {
      name: 'Balanced Workflow',
      description: 'Équilibré: Selective → Human → Adversarial → Pattern → Selective',
      phases: [
        { type: 'selective', config: { enabled: true, iteration: 1 } },
        { type: 'human', config: { enabled: true } },
        { type: 'adversarial', config: { enabled: true } },
        { type: 'pattern', config: { enabled: true } },
        { type: 'selective', config: { enabled: true, iteration: 2, intensity: 0.7 } }
      ]
    });

    logSh(`✅ WorkflowEngine: ${this.predefinedSequences.size} séquences prédéfinies chargées`, 'DEBUG');
  }

  // ========================================
  // EXÉCUTION WORKFLOW CONFIGURABLE
  // ========================================

  /**
   * Exécute un workflow selon une séquence configurée
   */
  async executeConfigurableWorkflow(content, config = {}) {
    return await tracer.run('WorkflowEngine.executeConfigurableWorkflow()', async () => {
      const {
        sequenceName = 'default',
        customSequence = null,
        selectiveConfig = {},
        adversarialConfig = {},
        humanConfig = {},
        patternConfig = {},
        csvData = {},
        personalities = {}
      } = config;

      await tracer.annotate({
        sequenceName: customSequence ? 'custom' : sequenceName,
        isCustomSequence: !!customSequence,
        elementsCount: Object.keys(content).length
      });

      logSh(`🔄 WORKFLOW CONFIGURABLE: ${customSequence ? 'custom' : sequenceName}`, 'INFO');

      let currentContent = { ...content };
      const workflowStats = {
        sequenceName: customSequence ? 'custom' : sequenceName,
        phases: [],
        totalDuration: 0,
        totalModifications: 0,
        versioning: new Map()
      };

      try {
        // Obtenir la séquence à exécuter
        const sequence = customSequence || this.getSequence(sequenceName);
        if (!sequence) {
          throw new Error(`Séquence workflow inconnue: ${sequenceName}`);
        }

        logSh(`   📋 Séquence: ${sequence.name} (${sequence.phases.length} phases)`, 'INFO');
        logSh(`   📝 Description: ${sequence.description}`, 'INFO');

        const startTime = Date.now();

        // Exécuter chaque phase de la séquence
        for (let i = 0; i < sequence.phases.length; i++) {
          const phase = sequence.phases[i];
          const phaseNumber = i + 1;

          logSh(`📊 PHASE ${phaseNumber}/${sequence.phases.length}: ${phase.type.toUpperCase()}${phase.config.iteration ? ` (${phase.config.iteration})` : ''}`, 'INFO');

          const phaseStartTime = Date.now();
          let phaseResult = null;

          try {
            switch (phase.type) {
              case 'selective':
                if (phase.config.enabled) {
                  phaseResult = await this.executeSelectivePhase(currentContent, {
                    ...selectiveConfig,
                    ...phase.config,
                    csvData,
                    personalities
                  });
                }
                break;

              case 'adversarial':
                if (phase.config.enabled) {
                  phaseResult = await this.executeAdversarialPhase(currentContent, {
                    ...adversarialConfig,
                    ...phase.config,
                    csvData,
                    personalities
                  });
                }
                break;

              case 'human':
                if (phase.config.enabled) {
                  phaseResult = await this.executeHumanPhase(currentContent, {
                    ...humanConfig,
                    ...phase.config,
                    csvData,
                    personalities
                  });
                }
                break;

              case 'pattern':
                if (phase.config.enabled) {
                  phaseResult = await this.executePatternPhase(currentContent, {
                    ...patternConfig,
                    ...phase.config,
                    csvData,
                    personalities
                  });
                }
                break;

              default:
                logSh(`⚠️ Type de phase inconnue: ${phase.type}`, 'WARNING');
            }

            // Mettre à jour le contenu et les stats
            if (phaseResult) {
              currentContent = phaseResult.content;

              const phaseDuration = Date.now() - phaseStartTime;
              const phaseStats = {
                type: phase.type,
                iteration: phase.config.iteration || 1,
                duration: phaseDuration,
                modifications: phaseResult.stats?.modifications || 0,
                success: true
              };

              workflowStats.phases.push(phaseStats);
              workflowStats.totalModifications += phaseStats.modifications;

              // Versioning
              const versionKey = `v1.${phaseNumber}`;
              workflowStats.versioning.set(versionKey, {
                phase: `${phase.type}${phase.config.iteration ? `-${phase.config.iteration}` : ''}`,
                content: { ...currentContent },
                timestamp: new Date().toISOString()
              });

              logSh(`   ✅ Phase ${phaseNumber} terminée: ${phaseStats.modifications} modifications en ${phaseDuration}ms`, 'DEBUG');
            } else {
              logSh(`   ⏭️ Phase ${phaseNumber} ignorée (désactivée)`, 'DEBUG');
            }

          } catch (error) {
            logSh(`   ❌ Erreur phase ${phaseNumber} (${phase.type}): ${error.message}`, 'ERROR');

            workflowStats.phases.push({
              type: phase.type,
              iteration: phase.config.iteration || 1,
              duration: Date.now() - phaseStartTime,
              modifications: 0,
              success: false,
              error: error.message
            });
          }
        }

        workflowStats.totalDuration = Date.now() - startTime;

        // Version finale
        workflowStats.versioning.set('v2.0', {
          phase: 'final',
          content: { ...currentContent },
          timestamp: new Date().toISOString()
        });

        logSh(`✅ WORKFLOW TERMINÉ: ${workflowStats.totalModifications} modifications en ${workflowStats.totalDuration}ms`, 'INFO');

        return {
          content: currentContent,
          stats: workflowStats,
          success: true
        };

      } catch (error) {
        logSh(`❌ Erreur workflow configurable: ${error.message}`, 'ERROR');

        workflowStats.totalDuration = Date.now() - startTime;
        workflowStats.error = error.message;

        return {
          content: currentContent,
          stats: workflowStats,
          success: false,
          error: error.message
        };
      }
    });
  }

  // ========================================
  // EXÉCUTION DES PHASES INDIVIDUELLES
  // ========================================

  async executeSelectivePhase(content, config) {
    const result = await applySelectiveEnhancement(content, config);
    return {
      content: result.content || content,
      stats: { modifications: result.stats?.selectiveEnhancements || 0 }
    };
  }

  async executeAdversarialPhase(content, config) {
    const result = await applyAdversarialEnhancement(content, config);
    return {
      content: result.content || content,
      stats: { modifications: result.stats?.adversarialModifications || 0 }
    };
  }

  async executeHumanPhase(content, config) {
    const result = await applyHumanSimulation(content, config);
    return {
      content: result.content || content,
      stats: { modifications: result.stats?.humanSimulationModifications || 0 }
    };
  }

  async executePatternPhase(content, config) {
    const result = await applyPatternBreaking(content, config);
    return {
      content: result.content || content,
      stats: { modifications: result.stats?.patternBreakingModifications || 0 }
    };
  }

  // ========================================
  // GESTION DES SÉQUENCES
  // ========================================

  /**
   * Obtenir une séquence (prédéfinie ou personnalisée)
   */
  getSequence(sequenceName) {
    return this.predefinedSequences.get(sequenceName) || this.customSequences.get(sequenceName);
  }

  /**
   * Créer une séquence personnalisée
   */
  createCustomSequence(name, sequence) {
    this.customSequences.set(name, sequence);
    logSh(`✨ Séquence personnalisée créée: ${name}`, 'INFO');
    return sequence;
  }

  /**
   * Lister toutes les séquences disponibles
   */
  getAvailableSequences() {
    const sequences = [];

    // Séquences prédéfinies
    for (const [name, sequence] of this.predefinedSequences) {
      sequences.push({
        name,
        ...sequence,
        isCustom: false
      });
    }

    // Séquences personnalisées
    for (const [name, sequence] of this.customSequences) {
      sequences.push({
        name,
        ...sequence,
        isCustom: true
      });
    }

    return sequences;
  }

  /**
   * Valider une séquence
   */
  validateSequence(sequence) {
    if (!sequence.name || !sequence.phases || !Array.isArray(sequence.phases)) {
      return false;
    }

    const validTypes = ['selective', 'adversarial', 'human', 'pattern'];

    for (const phase of sequence.phases) {
      if (!phase.type || !validTypes.includes(phase.type)) {
        return false;
      }
      if (!phase.config || typeof phase.config !== 'object') {
        return false;
      }
    }

    return true;
  }

  /**
   * Obtenir le statut du moteur
   */
  getEngineStatus() {
    return {
      predefinedSequences: Array.from(this.predefinedSequences.keys()),
      customSequences: Array.from(this.customSequences.keys()),
      totalSequences: this.predefinedSequences.size + this.customSequences.size,
      availablePhaseTypes: ['selective', 'adversarial', 'human', 'pattern']
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/APIController.js                                        │
└────────────────────────────────────────────────────────────────────┘
*/

/**
 * Contrôleur API RESTful pour SEO Generator
 * Centralise toute la logique API métier
 */

const { logSh } = require('./ErrorReporting');
const { handleFullWorkflow } = require('./Main');
const { getPersonalities, readInstructionsData } = require('./BrainConfig');
const { getStoredArticle, getRecentArticles } = require('./ArticleStorage');
const { DynamicPromptEngine } = require('./prompt-engine/DynamicPromptEngine');
const { TrendManager } = require('./trend-prompts/TrendManager');
const { WorkflowEngine } = require('./workflow-configuration/WorkflowEngine');

class APIController {
  constructor() {
    this.articles = new Map(); // Cache articles en mémoire
    this.projects = new Map(); // Cache projets
    this.templates = new Map(); // Cache templates

    // Initialize prompt engine components
    this.promptEngine = new DynamicPromptEngine();
    this.trendManager = new TrendManager();
    this.workflowEngine = new WorkflowEngine();
  }

  // ========================================
  // GESTION ARTICLES
  // ========================================

  /**
   * GET /api/articles - Liste tous les articles
   */
  async getArticles(req, res) {
    try {
      const { limit = 50, offset = 0, project, status } = req.query;

      logSh(`📋 Récupération articles: limit=${limit}, offset=${offset}`, 'DEBUG');

      // Récupération depuis Google Sheets
      const articles = await getRecentArticles(parseInt(limit));

      // Filtrage optionnel
      let filteredArticles = articles;
      if (project) {
        filteredArticles = articles.filter(a => a.project === project);
      }
      if (status) {
        filteredArticles = filteredArticles.filter(a => a.status === status);
      }

      res.json({
        success: true,
        data: {
          articles: filteredArticles.slice(offset, offset + limit),
          total: filteredArticles.length,
          limit: parseInt(limit),
          offset: parseInt(offset)
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération articles: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des articles',
        message: error.message
      });
    }
  }

  /**
   * GET /api/articles/:id - Récupère un article spécifique
   */
  async getArticle(req, res) {
    try {
      const { id } = req.params;
      const { format = 'json' } = req.query || {};

      logSh(`📄 Récupération article ID: ${id}`, 'DEBUG');

      const article = await getStoredArticle(id);

      if (!article) {
        return res.status(404).json({
          success: false,
          error: 'Article non trouvé',
          id
        });
      }

      // Format de réponse
      if (format === 'html') {
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.send(article.htmlContent || article.content);
      } else if (format === 'text') {
        res.setHeader('Content-Type', 'text/plain; charset=utf-8');
        res.send(article.textContent || article.content);
      } else {
        res.json({
          success: true,
          data: article,
          timestamp: new Date().toISOString()
        });
      }

    } catch (error) {
      logSh(`❌ Erreur récupération article ${req.params.id}: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération de l\'article',
        message: error.message
      });
    }
  }

  /**
   * POST /api/articles - Créer un nouvel article
   */
  async createArticle(req, res) {
    try {
      const {
        keyword,
        rowNumber,
        project = 'api',
        config = {},
        template,
        personalityPreference
      } = req.body;

      // Validation
      if (!keyword && !rowNumber) {
        return res.status(400).json({
          success: false,
          error: 'Mot-clé ou numéro de ligne requis'
        });
      }

      logSh(`✨ Création article: ${keyword || `ligne ${rowNumber}`}`, 'INFO');

      // Configuration par défaut
      const workflowConfig = {
        rowNumber: rowNumber || 2,
        source: 'api',
        project,
        selectiveStack: config.selectiveStack || 'standardEnhancement',
        adversarialMode: config.adversarialMode || 'light',
        humanSimulationMode: config.humanSimulationMode || 'none',
        patternBreakingMode: config.patternBreakingMode || 'none',
        personalityPreference,
        template,
        ...config
      };

      // Si mot-clé fourni, créer données temporaires
      if (keyword && !rowNumber) {
        workflowConfig.csvData = {
          mc0: keyword,
          t0: `Guide complet ${keyword}`,
          personality: personalityPreference || { nom: 'Marc', style: 'professionnel' }
        };
      }

      // Exécution du workflow
      const result = await handleFullWorkflow(workflowConfig);

      res.status(201).json({
        success: true,
        data: {
          id: result.id || result.slug,
          article: result,
          config: workflowConfig
        },
        message: 'Article créé avec succès',
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur création article: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la création de l\'article',
        message: error.message
      });
    }
  }

  // ========================================
  // GESTION PROJETS
  // ========================================

  /**
   * GET /api/projects - Liste tous les projets
   */
  async getProjects(req, res) {
    try {
      const projects = Array.from(this.projects.values());

      res.json({
        success: true,
        data: {
          projects,
          total: projects.length
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération projets: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des projets',
        message: error.message
      });
    }
  }

  /**
   * POST /api/projects - Créer un nouveau projet
   */
  async createProject(req, res) {
    try {
      // Validation body null/undefined
      if (!req.body) {
        return res.status(400).json({
          success: false,
          error: 'Corps de requête requis'
        });
      }

      const { name, description, config = {} } = req.body;

      if (!name) {
        return res.status(400).json({
          success: false,
          error: 'Nom du projet requis'
        });
      }

      const project = {
        id: `project_${Date.now()}`,
        name,
        description,
        config,
        createdAt: new Date().toISOString(),
        articlesCount: 0
      };

      this.projects.set(project.id, project);

      logSh(`📁 Projet créé: ${name}`, 'INFO');

      res.status(201).json({
        success: true,
        data: project,
        message: 'Projet créé avec succès'
      });

    } catch (error) {
      logSh(`❌ Erreur création projet: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la création du projet',
        message: error.message
      });
    }
  }

  // ========================================
  // GESTION TEMPLATES
  // ========================================

  /**
   * GET /api/templates - Liste tous les templates
   */
  async getTemplates(req, res) {
    try {
      const templates = Array.from(this.templates.values());

      res.json({
        success: true,
        data: {
          templates,
          total: templates.length
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération templates: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des templates',
        message: error.message
      });
    }
  }

  /**
   * POST /api/templates - Créer un nouveau template
   */
  async createTemplate(req, res) {
    try {
      const { name, content, description, category = 'custom' } = req.body;

      if (!name || !content) {
        return res.status(400).json({
          success: false,
          error: 'Nom et contenu du template requis'
        });
      }

      const template = {
        id: `template_${Date.now()}`,
        name,
        content,
        description,
        category,
        createdAt: new Date().toISOString()
      };

      this.templates.set(template.id, template);

      logSh(`📋 Template créé: ${name}`, 'INFO');

      res.status(201).json({
        success: true,
        data: template,
        message: 'Template créé avec succès'
      });

    } catch (error) {
      logSh(`❌ Erreur création template: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la création du template',
        message: error.message
      });
    }
  }

  // ========================================
  // CONFIGURATION & MONITORING
  // ========================================

  /**
   * GET /api/config/personalities - Configuration personnalités
   */
  async getPersonalitiesConfig(req, res) {
    try {
      const personalities = await getPersonalities();

      res.json({
        success: true,
        data: {
          personalities,
          total: personalities.length
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur config personnalités: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des personnalités',
        message: error.message
      });
    }
  }

  /**
   * GET /api/health - Health check
   */
  async getHealth(req, res) {
    try {
      const health = {
        status: 'healthy',
        timestamp: new Date().toISOString(),
        version: '1.0.0',
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        environment: process.env.NODE_ENV || 'development'
      };

      res.json({
        success: true,
        data: health
      });

    } catch (error) {
      res.status(500).json({
        success: false,
        error: 'Health check failed',
        message: error.message
      });
    }
  }

  /**
   * GET /api/metrics - Métriques système
   */
  async getMetrics(req, res) {
    try {
      const metrics = {
        articles: {
          total: this.articles.size,
          recent: Array.from(this.articles.values()).filter(
            a => new Date(a.createdAt) > new Date(Date.now() - 24 * 60 * 60 * 1000)
          ).length
        },
        projects: {
          total: this.projects.size
        },
        templates: {
          total: this.templates.size
        },
        system: {
          uptime: process.uptime(),
          memory: process.memoryUsage(),
          platform: process.platform,
          nodeVersion: process.version
        }
      };

      res.json({
        success: true,
        data: metrics,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur métriques: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des métriques',
        message: error.message
      });
    }
  }

  // ========================================
  // PROMPT ENGINE API
  // ========================================

  /**
   * POST /api/generate-prompt - Génère un prompt adaptatif
   */
  async generatePrompt(req, res) {
    try {
      const {
        templateType = 'technical',
        content = {},
        csvData = null,
        trend = null,
        layerConfig = {},
        customVariables = {}
      } = req.body;

      logSh(`🧠 Génération prompt: template=${templateType}, trend=${trend}`, 'INFO');

      // Apply trend if specified
      if (trend) {
        await this.trendManager.setTrend(trend);
      }

      // Generate adaptive prompt
      const result = await this.promptEngine.generateAdaptivePrompt({
        templateType,
        content,
        csvData,
        trend: this.trendManager.getCurrentTrend(),
        layerConfig,
        customVariables
      });

      res.json({
        success: true,
        prompt: result.prompt,
        metadata: result.metadata,
        timestamp: new Date().toISOString()
      });

      logSh(`✅ Prompt généré: ${result.prompt.length} caractères`, 'DEBUG');

    } catch (error) {
      logSh(`❌ Erreur génération prompt: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la génération du prompt',
        message: error.message
      });
    }
  }

  /**
   * GET /api/trends - Liste toutes les tendances disponibles
   */
  async getTrends(req, res) {
    try {
      const trends = this.trendManager.getAvailableTrends();
      const currentTrend = this.trendManager.getCurrentTrend();

      res.json({
        success: true,
        data: {
          trends,
          currentTrend,
          total: trends.length
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération tendances: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des tendances',
        message: error.message
      });
    }
  }

  /**
   * POST /api/trends/:trendId - Applique une tendance
   */
  async setTrend(req, res) {
    try {
      const { trendId } = req.params;
      const { customConfig = null } = req.body;

      logSh(`🎯 Application tendance: ${trendId}`, 'INFO');

      const trend = await this.trendManager.setTrend(trendId, customConfig);

      res.json({
        success: true,
        data: {
          trend,
          applied: true
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur application tendance ${req.params.trendId}: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de l\'application de la tendance',
        message: error.message
      });
    }
  }

  /**
   * GET /api/prompt-engine/status - Status du moteur de prompts
   */
  async getPromptEngineStatus(req, res) {
    try {
      const engineStatus = this.promptEngine.getEngineStatus();
      const trendStatus = this.trendManager.getStatus();
      const workflowStatus = this.workflowEngine.getEngineStatus();

      res.json({
        success: true,
        data: {
          engine: engineStatus,
          trends: trendStatus,
          workflow: workflowStatus,
          health: 'operational'
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur status prompt engine: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération du status',
        message: error.message
      });
    }
  }

  /**
   * GET /api/workflow/sequences - Liste toutes les séquences de workflow
   */
  async getWorkflowSequences(req, res) {
    try {
      const sequences = this.workflowEngine.getAvailableSequences();

      res.json({
        success: true,
        data: {
          sequences,
          total: sequences.length
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération séquences workflow: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la récupération des séquences workflow',
        message: error.message
      });
    }
  }

  /**
   * POST /api/workflow/sequences - Crée une séquence de workflow personnalisée
   */
  async createWorkflowSequence(req, res) {
    try {
      const { name, sequence } = req.body;

      if (!name || !sequence) {
        return res.status(400).json({
          success: false,
          error: 'Nom et séquence requis'
        });
      }

      if (!this.workflowEngine.validateSequence(sequence)) {
        return res.status(400).json({
          success: false,
          error: 'Séquence invalide'
        });
      }

      const createdSequence = this.workflowEngine.createCustomSequence(name, sequence);

      res.json({
        success: true,
        data: {
          name,
          sequence: createdSequence
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur création séquence workflow: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de la création de la séquence workflow',
        message: error.message
      });
    }
  }

  /**
   * POST /api/workflow/execute - Exécute un workflow configurable
   */
  async executeConfigurableWorkflow(req, res) {
    try {
      const {
        content,
        sequenceName = 'default',
        customSequence = null,
        selectiveConfig = {},
        adversarialConfig = {},
        humanConfig = {},
        patternConfig = {},
        csvData = {},
        personalities = {}
      } = req.body;

      if (!content || typeof content !== 'object') {
        return res.status(400).json({
          success: false,
          error: 'Contenu requis (objet)'
        });
      }

      logSh(`🔄 Exécution workflow configurable: ${customSequence ? 'custom' : sequenceName}`, 'INFO');

      const result = await this.workflowEngine.executeConfigurableWorkflow(content, {
        sequenceName,
        customSequence,
        selectiveConfig,
        adversarialConfig,
        humanConfig,
        patternConfig,
        csvData,
        personalities
      });

      res.json({
        success: result.success,
        data: {
          content: result.content,
          stats: result.stats
        },
        error: result.error || null,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur exécution workflow configurable: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lors de l\'exécution du workflow configurable',
        message: error.message
      });
    }
  }
}

module.exports = { APIController };

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/ConfigManager.js                                        │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: ConfigManager.js
// RESPONSABILITÉ: Gestion CRUD des configurations modulaires et pipelines
// STOCKAGE: Fichiers JSON dans configs/ et configs/pipelines/
// ========================================

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

class ConfigManager {
  constructor() {
    this.configDir = path.join(__dirname, '../configs');
    this.pipelinesDir = path.join(__dirname, '../configs/pipelines');
    this.ensureConfigDir();
  }

  async ensureConfigDir() {
    try {
      await fs.mkdir(this.configDir, { recursive: true });
      await fs.mkdir(this.pipelinesDir, { recursive: true });
      logSh(`📁 Dossiers configs vérifiés: ${this.configDir}`, 'DEBUG');
    } catch (error) {
      logSh(`⚠️ Erreur création dossier configs: ${error.message}`, 'WARNING');
    }
  }

  /**
   * Sauvegarder une configuration
   * @param {string} name - Nom de la configuration
   * @param {object} config - Configuration modulaire
   * @returns {object} - { success: true, name: sanitizedName }
   */
  async saveConfig(name, config) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.configDir, `${sanitizedName}.json`);

    const configData = {
      name: sanitizedName,
      displayName: name,
      config,
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString()
    };

    await fs.writeFile(filePath, JSON.stringify(configData, null, 2), 'utf-8');
    logSh(`💾 Config sauvegardée: ${name} → ${sanitizedName}.json`, 'INFO');

    return { success: true, name: sanitizedName };
  }

  /**
   * Charger une configuration
   * @param {string} name - Nom de la configuration
   * @returns {object} - Configuration complète
   */
  async loadConfig(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.configDir, `${sanitizedName}.json`);

    try {
      const data = await fs.readFile(filePath, 'utf-8');
      const configData = JSON.parse(data);
      logSh(`📂 Config chargée: ${name}`, 'DEBUG');
      return configData;
    } catch (error) {
      logSh(`❌ Config non trouvée: ${name}`, 'ERROR');
      throw new Error(`Configuration "${name}" non trouvée`);
    }
  }

  /**
   * Lister toutes les configurations
   * @returns {array} - Liste des configurations avec métadonnées
   */
  async listConfigs() {
    try {
      const files = await fs.readdir(this.configDir);
      const jsonFiles = files.filter(f => f.endsWith('.json'));

      const configs = await Promise.all(
        jsonFiles.map(async (file) => {
          const filePath = path.join(this.configDir, file);
          const data = await fs.readFile(filePath, 'utf-8');
          const configData = JSON.parse(data);

          return {
            name: configData.name,
            displayName: configData.displayName || configData.name,
            createdAt: configData.createdAt,
            updatedAt: configData.updatedAt
          };
        })
      );

      // Trier par date de mise à jour (plus récent en premier)
      return configs.sort((a, b) =>
        new Date(b.updatedAt) - new Date(a.updatedAt)
      );

    } catch (error) {
      logSh(`⚠️ Erreur listing configs: ${error.message}`, 'WARNING');
      return [];
    }
  }

  /**
   * Supprimer une configuration
   * @param {string} name - Nom de la configuration
   * @returns {object} - { success: true }
   */
  async deleteConfig(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.configDir, `${sanitizedName}.json`);

    await fs.unlink(filePath);
    logSh(`🗑️ Config supprimée: ${name}`, 'INFO');

    return { success: true };
  }

  /**
   * Vérifier si une configuration existe
   * @param {string} name - Nom de la configuration
   * @returns {boolean}
   */
  async configExists(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.configDir, `${sanitizedName}.json`);

    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Mettre à jour une configuration existante
   * @param {string} name - Nom de la configuration
   * @param {object} config - Nouvelle configuration
   * @returns {object} - { success: true, name: sanitizedName }
   */
  async updateConfig(name, config) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.configDir, `${sanitizedName}.json`);

    // Charger config existante pour garder createdAt
    const existingData = await this.loadConfig(name);

    const configData = {
      name: sanitizedName,
      displayName: name,
      config,
      createdAt: existingData.createdAt, // Garder date création
      updatedAt: new Date().toISOString()
    };

    await fs.writeFile(filePath, JSON.stringify(configData, null, 2), 'utf-8');
    logSh(`♻️ Config mise à jour: ${name}`, 'INFO');

    return { success: true, name: sanitizedName };
  }

  // ========================================
  // PIPELINE MANAGEMENT
  // ========================================

  /**
   * Sauvegarder un pipeline
   * @param {object} pipelineDefinition - Définition complète du pipeline
   * @returns {object} - { success: true, name: sanitizedName }
   */
  async savePipeline(pipelineDefinition) {
    // Validation du pipeline
    const validation = PipelineDefinition.validate(pipelineDefinition);
    if (!validation.valid) {
      throw new Error(`Pipeline invalide: ${validation.errors.join(', ')}`);
    }

    const sanitizedName = pipelineDefinition.name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.pipelinesDir, `${sanitizedName}.json`);

    // Ajouter metadata de sauvegarde
    const pipelineData = {
      ...pipelineDefinition,
      metadata: {
        ...pipelineDefinition.metadata,
        savedAt: new Date().toISOString()
      }
    };

    await fs.writeFile(filePath, JSON.stringify(pipelineData, null, 2), 'utf-8');
    logSh(`💾 Pipeline sauvegardé: ${pipelineDefinition.name} → ${sanitizedName}.json`, 'INFO');

    return { success: true, name: sanitizedName };
  }

  /**
   * Charger un pipeline
   * @param {string} name - Nom du pipeline
   * @returns {object} - Pipeline complet
   */
  async loadPipeline(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.pipelinesDir, `${sanitizedName}.json`);

    try {
      const data = await fs.readFile(filePath, 'utf-8');
      const pipeline = JSON.parse(data);

      // Validation du pipeline chargé
      const validation = PipelineDefinition.validate(pipeline);
      if (!validation.valid) {
        throw new Error(`Pipeline chargé invalide: ${validation.errors.join(', ')}`);
      }

      logSh(`📂 Pipeline chargé: ${name}`, 'DEBUG');
      return pipeline;
    } catch (error) {
      logSh(`❌ Pipeline non trouvé: ${name}`, 'ERROR');
      throw new Error(`Pipeline "${name}" non trouvé`);
    }
  }

  /**
   * Lister tous les pipelines
   * @returns {array} - Liste des pipelines avec métadonnées
   */
  async listPipelines() {
    try {
      const files = await fs.readdir(this.pipelinesDir);
      const jsonFiles = files.filter(f => f.endsWith('.json'));

      const pipelines = await Promise.all(
        jsonFiles.map(async (file) => {
          const filePath = path.join(this.pipelinesDir, file);
          const data = await fs.readFile(filePath, 'utf-8');
          const pipeline = JSON.parse(data);

          // Obtenir résumé du pipeline
          const summary = PipelineDefinition.getSummary(pipeline);

          return {
            name: pipeline.name,
            description: pipeline.description,
            steps: summary.totalSteps,
            summary: summary.summary,
            estimatedDuration: summary.duration.formatted,
            tags: pipeline.metadata?.tags || [],
            createdAt: pipeline.metadata?.created,
            savedAt: pipeline.metadata?.savedAt
          };
        })
      );

      // Trier par date de sauvegarde (plus récent en premier)
      return pipelines.sort((a, b) => {
        const dateA = new Date(a.savedAt || a.createdAt || 0);
        const dateB = new Date(b.savedAt || b.createdAt || 0);
        return dateB - dateA;
      });

    } catch (error) {
      logSh(`⚠️ Erreur listing pipelines: ${error.message}`, 'WARNING');
      return [];
    }
  }

  /**
   * Supprimer un pipeline
   * @param {string} name - Nom du pipeline
   * @returns {object} - { success: true }
   */
  async deletePipeline(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.pipelinesDir, `${sanitizedName}.json`);

    await fs.unlink(filePath);
    logSh(`🗑️ Pipeline supprimé: ${name}`, 'INFO');

    return { success: true };
  }

  /**
   * Vérifier si un pipeline existe
   * @param {string} name - Nom du pipeline
   * @returns {boolean}
   */
  async pipelineExists(name) {
    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.pipelinesDir, `${sanitizedName}.json`);

    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Mettre à jour un pipeline existant
   * @param {string} name - Nom du pipeline
   * @param {object} pipelineDefinition - Nouvelle définition
   * @returns {object} - { success: true, name: sanitizedName }
   */
  async updatePipeline(name, pipelineDefinition) {
    // Validation
    const validation = PipelineDefinition.validate(pipelineDefinition);
    if (!validation.valid) {
      throw new Error(`Pipeline invalide: ${validation.errors.join(', ')}`);
    }

    const sanitizedName = name.replace(/[^a-zA-Z0-9-_]/g, '_');
    const filePath = path.join(this.pipelinesDir, `${sanitizedName}.json`);

    // Charger pipeline existant pour garder metadata originale
    let existingMetadata = {};
    try {
      const existing = await this.loadPipeline(name);
      existingMetadata = existing.metadata || {};
    } catch {
      // Pipeline n'existe pas encore, on continue
    }

    const pipelineData = {
      ...pipelineDefinition,
      metadata: {
        ...existingMetadata,
        ...pipelineDefinition.metadata,
        created: existingMetadata.created || pipelineDefinition.metadata?.created,
        updated: new Date().toISOString(),
        savedAt: new Date().toISOString()
      }
    };

    await fs.writeFile(filePath, JSON.stringify(pipelineData, null, 2), 'utf-8');
    logSh(`♻️ Pipeline mis à jour: ${name}`, 'INFO');

    return { success: true, name: sanitizedName };
  }

  /**
   * Cloner un pipeline
   * @param {string} sourceName - Nom du pipeline source
   * @param {string} newName - Nom du nouveau pipeline
   * @returns {object} - { success: true, name: sanitizedName }
   */
  async clonePipeline(sourceName, newName) {
    const sourcePipeline = await this.loadPipeline(sourceName);
    const clonedPipeline = PipelineDefinition.clone(sourcePipeline, newName);

    return await this.savePipeline(clonedPipeline);
  }
}

module.exports = { ConfigManager };


/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/StepByStepSessionManager.js                             │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: StepByStepSessionManager.js
// RESPONSABILITÉ: Gestion des sessions step-by-step
// ========================================

// Pas besoin d'uuid externe, on utilise notre générateur simple
const { logSh } = require('./ErrorReporting');

/**
 * GESTIONNAIRE DE SESSIONS STEP-BY-STEP
 * Gère les sessions de test modulaire pas-à-pas avec TTL
 */
class StepByStepSessionManager {
  constructor() {
    this.sessions = new Map();
    this.TTL = 30 * 60 * 1000; // 30 minutes
    
    // Nettoyage automatique toutes les 5 minutes
    setInterval(() => this.cleanupExpiredSessions(), 5 * 60 * 1000);
    
    logSh('🎯 SessionManager initialisé', 'DEBUG');
  }

  // ========================================
  // GESTION DES SESSIONS
  // ========================================
  
  /**
   * Crée une nouvelle session
   */
  createSession(inputData) {
    const sessionId = this.generateUUID();
    const session = {
      id: sessionId,
      createdAt: Date.now(),
      lastAccessedAt: Date.now(),
      inputData: this.validateInputData(inputData),
      currentStep: 0,
      completedSteps: [],
      results: [],
      globalStats: {
        totalDuration: 0,
        totalTokens: 0,
        totalCost: 0,
        llmCalls: [],
        startTime: Date.now(),
        endTime: null
      },
      steps: this.generateStepsList(),
      status: 'initialized'
    };
    
    this.sessions.set(sessionId, session);
    logSh(`✅ Session créée: ${sessionId}`, 'INFO');
    
    return session;
  }
  
  /**
   * Récupère une session
   */
  getSession(sessionId) {
    const session = this.sessions.get(sessionId);
    if (!session) {
      throw new Error(`Session introuvable: ${sessionId}`);
    }
    
    if (this.isSessionExpired(session)) {
      this.deleteSession(sessionId);
      throw new Error(`Session expirée: ${sessionId}`);
    }
    
    session.lastAccessedAt = Date.now();
    return session;
  }
  
  /**
   * Met à jour une session
   */
  updateSession(sessionId, updates) {
    const session = this.getSession(sessionId);
    Object.assign(session, updates);
    session.lastAccessedAt = Date.now();
    
    logSh(`📝 Session mise à jour: ${sessionId}`, 'DEBUG');
    return session;
  }
  
  /**
   * Supprime une session
   */
  deleteSession(sessionId) {
    const deleted = this.sessions.delete(sessionId);
    if (deleted) {
      logSh(`🗑️ Session supprimée: ${sessionId}`, 'INFO');
    }
    return deleted;
  }
  
  /**
   * Liste toutes les sessions actives
   */
  listSessions() {
    const sessions = [];
    for (const [id, session] of this.sessions) {
      if (!this.isSessionExpired(session)) {
        sessions.push({
          id: session.id,
          createdAt: session.createdAt,
          status: session.status,
          currentStep: session.currentStep,
          totalSteps: session.steps.length,
          inputData: {
            mc0: session.inputData.mc0,
            personality: session.inputData.personality
          }
        });
      }
    }
    return sessions;
  }

  // ========================================
  // GESTION DES ÉTAPES
  // ========================================
  
  /**
   * Ajoute le résultat d'une étape
   */
  addStepResult(sessionId, stepId, result) {
    const session = this.getSession(sessionId);
    
    // Marquer l'étape comme complétée
    if (!session.completedSteps.includes(stepId)) {
      session.completedSteps.push(stepId);
    }
    
    // Ajouter le résultat
    const stepResult = {
      stepId: stepId,
      system: result.system,
      timestamp: Date.now(),
      success: result.success,
      result: result.result || null,
      error: result.error || null,
      stats: result.stats || {},
      formatted: result.formatted || null
    };
    
    session.results.push(stepResult);
    
    // Mettre à jour les stats globales
    this.updateGlobalStats(session, result.stats || {});
    
    // Mettre à jour le statut de l'étape
    const step = session.steps.find(s => s.id === stepId);
    if (step) {
      step.status = result.success ? 'completed' : 'error';
      step.duration = (result.stats && result.stats.duration) || 0;
      step.error = result.error || null;
    }
    
    // Mettre à jour currentStep si nécessaire
    if (stepId > session.currentStep) {
      session.currentStep = stepId;
    }
    
    logSh(`📊 Résultat étape ${stepId} ajouté à session ${sessionId}`, 'DEBUG');
    return session;
  }
  
  /**
   * Obtient le résultat d'une étape
   */
  getStepResult(sessionId, stepId) {
    const session = this.getSession(sessionId);
    return session.results.find(r => r.stepId === stepId) || null;
  }
  
  /**
   * Reset une session
   */
  resetSession(sessionId) {
    const session = this.getSession(sessionId);
    
    session.currentStep = 0;
    session.completedSteps = [];
    session.results = [];
    session.globalStats = {
      totalDuration: 0,
      totalTokens: 0,
      totalCost: 0,
      llmCalls: [],
      startTime: Date.now(),
      endTime: null
    };
    session.steps = this.generateStepsList();
    session.status = 'initialized';
    
    logSh(`🔄 Session reset: ${sessionId}`, 'INFO');
    return session;
  }

  // ========================================
  // HELPERS PRIVÉS
  // ========================================
  
  /**
   * Génère un UUID simple
   */
  generateUUID() {
    return Date.now().toString(36) + Math.random().toString(36).substr(2);
  }
  
  /**
   * Valide les données d'entrée
   */
  validateInputData(inputData) {
    const validated = {
      mc0: inputData.mc0 || 'mot-clé principal',
      t0: inputData.t0 || 'titre principal',
      mcPlus1: inputData.mcPlus1 || '',
      tPlus1: inputData.tPlus1 || '',
      personality: inputData.personality || 'random',
      tMinus1: inputData.tMinus1 || '',
      xmlTemplate: inputData.xmlTemplate || null
    };
    
    return validated;
  }
  
  /**
   * Génère la liste des étapes
   */
  generateStepsList() {
    return [
      {
        id: 1,
        system: 'initial-generation',
        name: 'Initial Generation',
        description: 'Génération de contenu initial avec Claude',
        status: 'pending',
        duration: 0,
        error: null
      },
      {
        id: 2,
        system: 'selective',
        name: 'Selective Enhancement', 
        description: 'Amélioration sélective (Technique → Transitions → Style)',
        status: 'pending',
        duration: 0,
        error: null
      },
      {
        id: 3,
        system: 'adversarial',
        name: 'Adversarial Generation',
        description: 'Génération adversariale anti-détection',
        status: 'pending',
        duration: 0,
        error: null
      },
      {
        id: 4,
        system: 'human-simulation',
        name: 'Human Simulation',
        description: 'Simulation comportements humains',
        status: 'pending',
        duration: 0,
        error: null
      },
      {
        id: 5,
        system: 'pattern-breaking',
        name: 'Pattern Breaking',
        description: 'Cassage de patterns IA',
        status: 'pending',
        duration: 0,
        error: null
      }
    ];
  }
  
  /**
   * Met à jour les statistiques globales
   */
  updateGlobalStats(session, stepStats) {
    const global = session.globalStats;
    
    global.totalDuration += stepStats.duration || 0;
    global.totalTokens += stepStats.tokensUsed || 0;
    global.totalCost += stepStats.cost || 0;
    
    if (stepStats.llmCalls && Array.isArray(stepStats.llmCalls)) {
      global.llmCalls.push(...stepStats.llmCalls);
    }
    
    // Marquer la fin si toutes les étapes sont complétées
    if (session.completedSteps.length === session.steps.length) {
      global.endTime = Date.now();
      session.status = 'completed';
    }
  }
  
  /**
   * Vérifie si une session est expirée
   */
  isSessionExpired(session) {
    return (Date.now() - session.lastAccessedAt) > this.TTL;
  }
  
  /**
   * Nettoie les sessions expirées
   */
  cleanupExpiredSessions() {
    let cleaned = 0;
    for (const [id, session] of this.sessions) {
      if (this.isSessionExpired(session)) {
        this.sessions.delete(id);
        cleaned++;
      }
    }
    
    if (cleaned > 0) {
      logSh(`🧹 ${cleaned} sessions expirées nettoyées`, 'DEBUG');
    }
  }

  // ========================================
  // EXPORT/IMPORT
  // ========================================
  
  /**
   * Exporte une session au format JSON
   */
  exportSession(sessionId) {
    const session = this.getSession(sessionId);
    
    return {
      session: {
        id: session.id,
        createdAt: new Date(session.createdAt).toISOString(),
        inputData: session.inputData,
        results: session.results,
        globalStats: session.globalStats,
        steps: session.steps.map(step => ({
          ...step,
          duration: step.duration ? `${step.duration}ms` : '0ms'
        }))
      },
      exportedAt: new Date().toISOString(),
      version: '1.0.0'
    };
  }
}

// Instance singleton
const sessionManager = new StepByStepSessionManager();

module.exports = {
  StepByStepSessionManager,
  sessionManager
};

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/shared/QueueProcessor.js                                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// QUEUE PROCESSOR - CLASSE COMMUNE
// Responsabilité: Logique partagée de queue, retry, persistance
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { handleModularWorkflow } = require('../Main');
const { readInstructionsData } = require('../BrainConfig');
const fs = require('fs').promises;
const path = require('path');

/**
 * QUEUE PROCESSOR BASE
 * Classe commune pour la gestion de queue avec retry logic et persistance
 */
class QueueProcessor {

  constructor(options = {}) {
    this.name = options.name || 'QueueProcessor';
    this.configPath = options.configPath;
    this.statusPath = options.statusPath;
    this.queuePath = options.queuePath;

    // Configuration par défaut
    this.config = {
      selective: 'standardEnhancement',
      adversarial: 'light',
      humanSimulation: 'none',
      patternBreaking: 'none',
      intensity: 1.0,
      rowRange: { start: 2, end: 10 },
      saveIntermediateSteps: false,
      maxRetries: 3,
      delayBetweenItems: 1000,
      batchSize: 1,
      ...options.config
    };

    // État du processeur
    this.isRunning = false;
    this.isPaused = false;
    this.currentRow = null;
    this.queue = [];
    this.processedItems = [];
    this.failedItems = [];

    // Métriques
    this.startTime = null;
    this.processedCount = 0;
    this.errorCount = 0;

    // Stats détaillées
    this.stats = {
      itemsQueued: 0,
      itemsProcessed: 0,
      itemsFailed: 0,
      averageProcessingTime: 0,
      totalProcessingTime: 0,
      startTime: Date.now(),
      lastProcessedAt: null
    };

    // Callbacks optionnels
    this.onStatusUpdate = null;
    this.onProgress = null;
    this.onError = null;
    this.onComplete = null;
    this.onItemProcessed = null;
  }

  // ========================================
  // INITIALISATION
  // ========================================

  /**
   * Initialise le processeur
   */
  async initialize() {
    try {
      await this.loadConfig();
      await this.initializeQueue();
      logSh(`🎯 ${this.name} initialisé`, 'DEBUG');
    } catch (error) {
      logSh(`❌ Erreur initialisation ${this.name}: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Charge la configuration
   */
  async loadConfig() {
    if (!this.configPath) return;

    try {
      const configData = await fs.readFile(this.configPath, 'utf8');
      this.config = { ...this.config, ...JSON.parse(configData) };
      logSh(`📋 Configuration ${this.name} chargée`, 'DEBUG');
    } catch (error) {
      logSh(`⚠️ Configuration non trouvée pour ${this.name}, utilisation valeurs par défaut`, 'WARNING');
    }
  }

  /**
   * Initialise les fichiers de configuration
   */
  async initializeFiles() {
    if (!this.configPath) return;

    try {
      const configDir = path.dirname(this.configPath);
      await fs.mkdir(configDir, { recursive: true });

      // Créer config par défaut si inexistant
      try {
        await fs.access(this.configPath);
      } catch {
        await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
        logSh(`📝 Configuration ${this.name} par défaut créée`, 'DEBUG');
      }

      // Créer status par défaut si inexistant
      if (this.statusPath) {
        const defaultStatus = this.getDefaultStatus();
        try {
          await fs.access(this.statusPath);
        } catch {
          await fs.writeFile(this.statusPath, JSON.stringify(defaultStatus, null, 2));
          logSh(`📊 Status ${this.name} par défaut créé`, 'DEBUG');
        }
      }

    } catch (error) {
      logSh(`❌ Erreur initialisation fichiers ${this.name}: ${error.message}`, 'ERROR');
    }
  }

  // ========================================
  // GESTION QUEUE
  // ========================================

  /**
   * Initialise la queue
   */
  async initializeQueue() {
    try {
      // Essayer de charger la queue existante
      if (this.queuePath) {
        try {
          const queueData = await fs.readFile(this.queuePath, 'utf8');
          const savedQueue = JSON.parse(queueData);

          if (savedQueue.queue && Array.isArray(savedQueue.queue)) {
            this.queue = savedQueue.queue;
            this.processedCount = savedQueue.processedCount || 0;
            logSh(`📊 Queue ${this.name} restaurée: ${this.queue.length} éléments`, 'DEBUG');
          }
        } catch {
          // Queue n'existe pas, on la créera
        }
      }

      // Si queue vide, la populer
      if (this.queue.length === 0) {
        await this.populateQueue();
      }

    } catch (error) {
      logSh(`❌ Erreur initialisation queue ${this.name}: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Popule la queue avec les lignes à traiter
   */
  async populateQueue() {
    try {
      this.queue = [];
      const { start, end } = this.config.rowRange;

      for (let rowNumber = start; rowNumber <= end; rowNumber++) {
        this.queue.push({
          rowNumber,
          status: 'pending',
          attempts: 0,
          maxAttempts: this.config.maxRetries,
          error: null,
          result: null,
          startTime: null,
          endTime: null,
          addedAt: Date.now()
        });
      }

      await this.saveQueue();
      this.stats.itemsQueued = this.queue.length;

      logSh(`📋 Queue ${this.name} populée: ${this.queue.length} lignes (${start} à ${end})`, 'INFO');

    } catch (error) {
      logSh(`❌ Erreur population queue ${this.name}: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Popule la queue depuis Google Sheets (version avancée)
   */
  async populateQueueFromSheets() {
    try {
      this.queue = [];
      let currentRow = this.config.startRow || 2;
      let consecutiveEmptyRows = 0;
      const maxEmptyRows = 5;

      while (currentRow <= (this.config.endRow || 50)) {
        if (this.config.endRow && currentRow > this.config.endRow) {
          break;
        }

        try {
          const csvData = await readInstructionsData(currentRow);

          if (!csvData || !csvData.mc0) {
            consecutiveEmptyRows++;
            if (consecutiveEmptyRows >= maxEmptyRows) {
              logSh(`🛑 Arrêt scan après ${maxEmptyRows} lignes vides consécutives`, 'INFO');
              break;
            }
          } else {
            consecutiveEmptyRows = 0;

            this.queue.push({
              rowNumber: currentRow,
              data: csvData,
              status: 'pending',
              attempts: 0,
              maxAttempts: this.config.maxRetries,
              error: null,
              result: null,
              startTime: null,
              endTime: null,
              addedAt: Date.now()
            });
          }
        } catch (error) {
          consecutiveEmptyRows++;
          if (consecutiveEmptyRows >= maxEmptyRows) {
            break;
          }
        }

        currentRow++;
      }

      await this.saveQueue();
      this.stats.itemsQueued = this.queue.length;

      logSh(`📊 Queue ${this.name} chargée depuis Sheets: ${this.stats.itemsQueued} éléments`, 'INFO');

    } catch (error) {
      logSh(`❌ Erreur chargement queue depuis Sheets: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Sauvegarde la queue
   */
  async saveQueue() {
    if (!this.queuePath) return;

    try {
      const queueData = {
        queue: this.queue,
        processedCount: this.processedCount,
        lastUpdate: new Date().toISOString()
      };

      await fs.writeFile(this.queuePath, JSON.stringify(queueData, null, 2));
    } catch (error) {
      logSh(`❌ Erreur sauvegarde queue ${this.name}: ${error.message}`, 'ERROR');
    }
  }

  // ========================================
  // CONTRÔLES PRINCIPAUX
  // ========================================

  /**
   * Démarre le traitement
   */
  async start() {
    return tracer.run(`${this.name}.start`, async () => {
      if (this.isRunning) {
        throw new Error(`${this.name} est déjà en cours`);
      }

      logSh(`🚀 Démarrage ${this.name}`, 'INFO');

      this.isRunning = true;
      this.isPaused = false;
      this.startTime = new Date();
      this.processedCount = 0;
      this.errorCount = 0;

      await this.loadConfig();

      if (this.queue.length === 0) {
        await this.populateQueue();
      }

      await this.updateStatus();

      // Démarrer le traitement asynchrone
      this.processQueue().catch(error => {
        logSh(`❌ Erreur traitement queue ${this.name}: ${error.message}`, 'ERROR');
        this.handleError(error);
      });

      return this.getStatus();
    });
  }

  /**
   * Arrête le traitement
   */
  async stop() {
    return tracer.run(`${this.name}.stop`, async () => {
      logSh(`🛑 Arrêt ${this.name}`, 'INFO');

      this.isRunning = false;
      this.isPaused = false;
      this.currentRow = null;

      await this.updateStatus();
      return this.getStatus();
    });
  }

  /**
   * Met en pause le traitement
   */
  async pause() {
    return tracer.run(`${this.name}.pause`, async () => {
      if (!this.isRunning) {
        throw new Error(`Aucun traitement ${this.name} en cours`);
      }

      logSh(`⏸️ Mise en pause ${this.name}`, 'INFO');
      this.isPaused = true;

      await this.updateStatus();
      return this.getStatus();
    });
  }

  /**
   * Reprend le traitement
   */
  async resume() {
    return tracer.run(`${this.name}.resume`, async () => {
      if (!this.isRunning || !this.isPaused) {
        throw new Error(`Aucun traitement ${this.name} en pause`);
      }

      logSh(`▶️ Reprise ${this.name}`, 'INFO');
      this.isPaused = false;

      await this.updateStatus();

      // Reprendre le traitement
      this.processQueue().catch(error => {
        logSh(`❌ Erreur reprise traitement ${this.name}: ${error.message}`, 'ERROR');
        this.handleError(error);
      });

      return this.getStatus();
    });
  }

  // ========================================
  // TRAITEMENT QUEUE
  // ========================================

  /**
   * Traite la queue
   */
  async processQueue() {
    return tracer.run(`${this.name}.processQueue`, async () => {
      while (this.isRunning && !this.isPaused) {
        const nextItem = this.queue.find(item => item.status === 'pending' ||
          (item.status === 'error' && item.attempts < item.maxAttempts));

        if (!nextItem) {
          logSh(`✅ Traitement ${this.name} terminé`, 'INFO');
          await this.complete();
          break;
        }

        await this.processItem(nextItem);

        if (this.config.delayBetweenItems > 0) {
          await this.sleep(this.config.delayBetweenItems);
        }
      }
    });
  }

  /**
   * Traite un élément de la queue
   */
  async processItem(item) {
    return tracer.run(`${this.name}.processItem`, async () => {
      logSh(`🔄 Traitement ${this.name} ligne ${item.rowNumber} (tentative ${item.attempts + 1}/${item.maxAttempts})`, 'INFO');

      this.currentRow = item.rowNumber;
      item.status = 'processing';
      item.startTime = new Date().toISOString();
      item.attempts++;

      await this.updateStatus();
      await this.saveQueue();

      try {
        const result = await this.processRow(item.rowNumber, item.data);

        // Succès
        item.status = 'completed';
        item.result = result;
        item.endTime = new Date().toISOString();
        item.error = null;

        this.processedCount++;
        this.processedItems.push(item);

        const duration = Date.now() - new Date(item.startTime).getTime();
        this.stats.itemsProcessed++;
        this.stats.totalProcessingTime += duration;
        this.stats.averageProcessingTime = Math.round(this.stats.totalProcessingTime / this.stats.itemsProcessed);
        this.stats.lastProcessedAt = Date.now();

        logSh(`✅ ${this.name} ligne ${item.rowNumber} traitée avec succès (${duration}ms)`, 'INFO');

        if (this.onItemProcessed) {
          this.onItemProcessed(item, result);
        }

        if (this.onProgress) {
          this.onProgress(item, this.getProgress());
        }

      } catch (error) {
        item.error = {
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        };

        if (item.attempts >= item.maxAttempts) {
          item.status = 'failed';
          this.errorCount++;
          this.failedItems.push(item);

          logSh(`❌ ${this.name} ligne ${item.rowNumber} échouée définitivement après ${item.attempts} tentatives`, 'ERROR');
        } else {
          item.status = 'error';
          logSh(`⚠️ ${this.name} ligne ${item.rowNumber} échouée, retry possible`, 'WARNING');
        }

        if (this.onError) {
          this.onError(item, error);
        }
      }

      this.currentRow = null;
      await this.updateStatus();
      await this.saveQueue();
    });
  }

  /**
   * Traite une ligne spécifique - à surcharger dans les classes enfants
   */
  async processRow(rowNumber, data = null) {
    const rowConfig = this.buildRowConfig(rowNumber, data);
    logSh(`🎯 Configuration ${this.name} ligne ${rowNumber}: ${JSON.stringify(rowConfig)}`, 'DEBUG');

    const result = await handleModularWorkflow(rowConfig);
    logSh(`📊 Résultat ${this.name} ligne ${rowNumber}: ${result ? 'SUCCESS' : 'FAILED'}`, 'INFO');

    return result;
  }

  /**
   * Construit la configuration pour une ligne - à surcharger si nécessaire
   */
  buildRowConfig(rowNumber, data = null) {
    return {
      rowNumber,
      source: `${this.name.toLowerCase()}_row_${rowNumber}`,
      selectiveStack: this.config.selective,
      adversarialMode: this.config.adversarial,
      humanSimulationMode: this.config.humanSimulation,
      patternBreakingMode: this.config.patternBreaking,
      intensity: this.config.intensity,
      saveIntermediateSteps: this.config.saveIntermediateSteps,
      data
    };
  }

  // ========================================
  // GESTION ÉTAT
  // ========================================

  /**
   * Met à jour le status
   */
  async updateStatus() {
    const status = this.getStatus();

    if (this.statusPath) {
      try {
        await fs.writeFile(this.statusPath, JSON.stringify(status, null, 2));
      } catch (error) {
        logSh(`❌ Erreur mise à jour status ${this.name}: ${error.message}`, 'ERROR');
      }
    }

    if (this.onStatusUpdate) {
      this.onStatusUpdate(status);
    }
  }

  /**
   * Retourne le status actuel
   */
  getStatus() {
    const now = new Date();
    const completedItems = this.queue.filter(item => item.status === 'completed').length;
    const failedItems = this.queue.filter(item => item.status === 'failed').length;
    const totalItems = this.queue.length;

    const progress = totalItems > 0 ? ((completedItems + failedItems) / totalItems) * 100 : 0;

    let status = 'idle';
    if (this.isRunning && this.isPaused) {
      status = 'paused';
    } else if (this.isRunning) {
      status = 'running';
    } else if (completedItems + failedItems === totalItems && totalItems > 0) {
      status = 'completed';
    }

    return {
      status,
      currentRow: this.currentRow,
      totalRows: totalItems,
      completedRows: completedItems,
      failedRows: failedItems,
      progress: Math.round(progress),
      startTime: this.startTime ? this.startTime.toISOString() : null,
      estimatedEnd: this.estimateCompletionTime(),
      errors: this.queue.filter(item => item.error).map(item => ({
        rowNumber: item.rowNumber,
        error: item.error,
        attempts: item.attempts
      })),
      lastResult: this.getLastResult(),
      config: this.config,
      queue: this.queue,
      stats: this.stats
    };
  }

  /**
   * Retourne la progression détaillée
   */
  getProgress() {
    // Calcul direct des métriques sans appeler getStatus() pour éviter la récursion
    const now = new Date();
    const elapsed = this.startTime ? now - this.startTime : 0;

    const completedRows = this.processedItems.length;
    const failedRows = this.failedItems.length;
    const totalRows = this.queue.length + completedRows + failedRows;

    const avgTimePerRow = completedRows > 0 ? elapsed / completedRows : 0;
    const remainingRows = totalRows - completedRows - failedRows;
    const estimatedRemaining = avgTimePerRow * remainingRows;

    return {
      status: this.status,
      currentRow: this.currentItem ? this.currentItem.rowNumber : null,
      totalRows: totalRows,
      completedRows: completedRows,
      failedRows: failedRows,
      progress: totalRows > 0 ? Math.round((completedRows / totalRows) * 100) : 0,
      startTime: this.startTime ? this.startTime.toISOString() : null,
      estimatedEnd: null, // Calculé séparément pour éviter récursion
      errors: this.failedItems.map(item => ({ row: item.rowNumber, error: item.error })),
      lastResult: this.processedItems.length > 0 ? this.processedItems[this.processedItems.length - 1].result : null,
      config: this.config,
      queue: this.queue,
      stats: {
        itemsQueued: this.queue.length,
        itemsProcessed: completedRows,
        itemsFailed: failedRows,
        averageProcessingTime: avgTimePerRow,
        totalProcessingTime: elapsed,
        startTime: this.startTime ? this.startTime.getTime() : null,
        lastProcessedAt: this.processedItems.length > 0 ? this.processedItems[this.processedItems.length - 1].endTime : null
      },
      metrics: {
        elapsedTime: elapsed,
        avgTimePerRow: avgTimePerRow,
        estimatedRemaining: estimatedRemaining,
        completionPercentage: totalRows > 0 ? (completedRows / totalRows) * 100 : 0,
        throughput: completedRows > 0 && elapsed > 0 ? (completedRows / (elapsed / 1000 / 60)) : 0
      }
    };
  }

  /**
   * Estime l'heure de fin
   */
  estimateCompletionTime() {
    if (!this.startTime || !this.isRunning || this.isPaused) {
      return null;
    }

    // Calcul direct sans appeler getProgress() pour éviter la récursion
    const now = new Date();
    const elapsed = now - this.startTime;
    const completedRows = this.processedItems.length;

    if (completedRows > 0) {
      const avgTimePerRow = elapsed / completedRows;
      const remainingRows = this.queue.length;
      const estimatedRemaining = avgTimePerRow * remainingRows;

      if (estimatedRemaining > 0) {
        const endTime = new Date(Date.now() + estimatedRemaining);
        return endTime.toISOString();
      }
    }

    return null;
  }

  /**
   * Retourne le dernier résultat
   */
  getLastResult() {
    const completedItems = this.queue.filter(item => item.status === 'completed');
    if (completedItems.length === 0) return null;

    const lastItem = completedItems[completedItems.length - 1];
    return {
      rowNumber: lastItem.rowNumber,
      result: lastItem.result,
      endTime: lastItem.endTime
    };
  }

  /**
   * Status par défaut
   */
  getDefaultStatus() {
    return {
      status: 'idle',
      currentRow: null,
      totalRows: 0,
      progress: 0,
      startTime: null,
      estimatedEnd: null,
      errors: [],
      lastResult: null,
      config: this.config
    };
  }

  // ========================================
  // GESTION ERREURS
  // ========================================

  /**
   * Gère les erreurs critiques
   */
  async handleError(error) {
    logSh(`💥 Erreur critique ${this.name}: ${error.message}`, 'ERROR');

    this.isRunning = false;
    this.isPaused = false;

    await this.updateStatus();

    if (this.onError) {
      this.onError(null, error);
    }
  }

  /**
   * Termine le traitement
   */
  async complete() {
    logSh(`🏁 Traitement ${this.name} terminé`, 'INFO');

    this.isRunning = false;
    this.isPaused = false;
    this.currentRow = null;

    await this.updateStatus();

    if (this.onComplete) {
      this.onComplete(this.getStatus());
    }
  }

  // ========================================
  // UTILITAIRES
  // ========================================

  /**
   * Pause l'exécution
   */
  async sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * Reset la queue
   */
  async resetQueue() {
    logSh(`🔄 Reset de la queue ${this.name}`, 'INFO');

    this.queue = [];
    this.processedCount = 0;
    this.errorCount = 0;

    await this.populateQueue();
    await this.updateStatus();
  }

  /**
   * Configure les callbacks
   */
  setCallbacks({ onStatusUpdate, onProgress, onError, onComplete, onItemProcessed }) {
    this.onStatusUpdate = onStatusUpdate;
    this.onProgress = onProgress;
    this.onError = onError;
    this.onComplete = onComplete;
    this.onItemProcessed = onItemProcessed;
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/batch/BatchProcessor.js                                 │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// BATCH PROCESSOR - REFACTORISÉ
// Responsabilité: Traitement batch interface web avec configuration flexible
// ========================================

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

/**
 * BATCH PROCESSOR
 * Spécialisé pour interface web avec configuration modulaire flexible
 */
class BatchProcessor extends QueueProcessor {

  constructor() {
    super({
      name: 'BatchProcessor',
      configPath: path.join(__dirname, '../../config/batch-config.json'),
      statusPath: path.join(__dirname, '../../config/batch-status.json'),
      queuePath: path.join(__dirname, '../../config/batch-queue.json'),
      config: {
        selective: 'standardEnhancement',
        adversarial: 'light',
        humanSimulation: 'none',
        patternBreaking: 'none',
        intensity: 1.0,
        rowRange: { start: 2, end: 10 },
        saveIntermediateSteps: false,
        maxRetries: 3,
        delayBetweenItems: 1000
      }
    });

    // Initialisation différée pour éviter le blocage au démarrage serveur
    // this.initialize().catch(error => {
    //   logSh(`❌ Erreur initialisation BatchProcessor: ${error.message}`, 'ERROR');
    // });
  }

  /**
   * Alias pour compatibilité - Initialise les fichiers
   */
  async initializeFiles() {
    return await super.initializeFiles();
  }

  /**
   * Alias pour compatibilité - Initialise le processeur
   */
  async initializeProcessor() {
    return await this.initialize();
  }

  /**
   * Construit la configuration spécifique BatchProcessor
   */
  buildRowConfig(rowNumber, data = null) {
    return {
      rowNumber,
      source: 'batch_processor',
      selectiveStack: this.config.selective,
      adversarialMode: this.config.adversarial,
      humanSimulationMode: this.config.humanSimulation,
      patternBreakingMode: this.config.patternBreaking,
      intensity: this.config.intensity,
      saveIntermediateSteps: this.config.saveIntermediateSteps
    };
  }

  /**
   * API spécifique BatchProcessor - Configuration
   */
  async updateConfiguration(newConfig) {
    try {
      // Validation basique
      const requiredFields = ['selective', 'adversarial', 'humanSimulation', 'patternBreaking', 'intensity', 'rowRange'];
      for (const field of requiredFields) {
        if (!(field in newConfig)) {
          throw new Error(`Champ requis manquant: ${field}`);
        }
      }

      // Validation intensité
      if (newConfig.intensity < 0.5 || newConfig.intensity > 1.5) {
        throw new Error('Intensité doit être entre 0.5 et 1.5');
      }

      // Validation rowRange
      if (!newConfig.rowRange.start || !newConfig.rowRange.end || newConfig.rowRange.start >= newConfig.rowRange.end) {
        throw new Error('Plage de lignes invalide');
      }

      // Mettre à jour la configuration
      this.config = { ...this.config, ...newConfig };
      this.config.lastUpdated = new Date().toISOString();

      // Sauvegarder
      if (this.configPath) {
        const fs = require('fs').promises;
        await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
      }

      logSh(`✅ Configuration BatchProcessor mise à jour: ${JSON.stringify(newConfig)}`, 'INFO');

      return { success: true, config: this.config };

    } catch (error) {
      logSh(`❌ Erreur mise à jour configuration: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Retourne les options disponibles
   */
  getAvailableOptions() {
    return {
      selective: ['lightEnhancement', 'standardEnhancement', 'fullEnhancement', 'personalityFocus', 'fluidityFocus'],
      adversarial: ['none', 'light', 'standard', 'heavy', 'adaptive'],
      humanSimulation: ['none', 'lightSimulation', 'personalityFocus', 'adaptive'],
      patternBreaking: ['none', 'syntaxFocus', 'connectorsFocus', 'adaptive'],
      intensityRange: { min: 0.5, max: 1.5, step: 0.1 }
    };
  }

  /**
   * Status étendu avec options disponibles
   */
  getExtendedStatus() {
    const baseStatus = this.getStatus();
    return {
      ...baseStatus,
      availableOptions: this.getAvailableOptions(),
      mode: 'BATCH_MANUAL',
      timestamp: new Date().toISOString()
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/batch/BatchController.js                                │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// BATCH CONTROLLER - API ENDPOINTS
// Responsabilité: Gestion API pour traitement batch avec configuration pipeline
// ========================================

const { logSh } = require('../ErrorReporting');
const fs = require('fs').promises;
const path = require('path');
const { BatchProcessor } = require('./BatchProcessor');
const { DigitalOceanTemplates } = require('./DigitalOceanTemplates');
const { TrendManager } = require('../trend-prompts/TrendManager');

/**
 * BATCH CONTROLLER
 * Gestion complète de l'interface de traitement batch
 */
class BatchController {

  constructor() {
    this.configPath = path.join(__dirname, '../../config/batch-config.json');
    this.statusPath = path.join(__dirname, '../../config/batch-status.json');

    // Initialiser les composants Phase 2
    this.batchProcessor = new BatchProcessor();
    this.digitalOceanTemplates = new DigitalOceanTemplates();
    this.trendManager = new TrendManager();

    // Configuration par défaut
    this.defaultConfig = {
      selective: 'standardEnhancement',
      adversarial: 'light',
      humanSimulation: 'none',
      patternBreaking: 'none',
      intensity: 1.0,
      rowRange: { start: 2, end: 10 },
      saveIntermediateSteps: false,
      trendId: null,  // Tendance à appliquer (optionnel)
      lastUpdated: new Date().toISOString()
    };

    // État par défaut
    this.defaultStatus = {
      status: 'idle',
      currentRow: null,
      totalRows: 0,
      progress: 0,
      startTime: null,
      estimatedEnd: null,
      errors: [],
      lastResult: null,
      config: this.defaultConfig
    };

    this.initializeFiles();
  }

  /**
   * Initialise les fichiers de configuration
   */
  async initializeFiles() {
    try {
      // Créer le dossier config s'il n'existe pas
      const configDir = path.dirname(this.configPath);
      await fs.mkdir(configDir, { recursive: true });

      // Créer config par défaut si inexistant
      try {
        await fs.access(this.configPath);
      } catch {
        await fs.writeFile(this.configPath, JSON.stringify(this.defaultConfig, null, 2));
        logSh('📝 Configuration batch par défaut créée', 'DEBUG');
      }

      // Créer status par défaut si inexistant
      try {
        await fs.access(this.statusPath);
      } catch {
        await fs.writeFile(this.statusPath, JSON.stringify(this.defaultStatus, null, 2));
        logSh('📊 Status batch par défaut créé', 'DEBUG');
      }

    } catch (error) {
      logSh(`❌ Erreur initialisation fichiers batch: ${error.message}`, 'ERROR');
    }
  }

  // ========================================
  // ENDPOINTS CONFIGURATION
  // ========================================

  /**
   * GET /api/batch/config
   * Récupère la configuration actuelle
   */
  async getConfig(req, res) {
    try {
      // Utiliser la nouvelle API du BatchProcessor refactorisé
      const status = this.batchProcessor.getExtendedStatus();

      // Ajouter les tendances disponibles
      const availableTrends = this.trendManager.getAvailableTrends();
      const currentTrend = this.trendManager.getCurrentTrend();

      logSh('📋 Configuration batch récupérée', 'DEBUG');

      res.json({
        success: true,
        config: status.config,
        availableOptions: status.availableOptions,
        trends: {
          available: availableTrends,
          current: currentTrend,
          categories: this.groupTrendsByCategory(availableTrends)
        }
      });

    } catch (error) {
      logSh(`❌ Erreur récupération config: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération configuration',
        details: error.message
      });
    }
  }

  /**
   * POST /api/batch/config
   * Sauvegarde la configuration
   */
  async saveConfig(req, res) {
    try {
      const newConfig = req.body;

      // Utiliser la nouvelle API du BatchProcessor refactorisé
      const result = await this.batchProcessor.updateConfiguration(newConfig);

      res.json({
        success: true,
        message: 'Configuration sauvegardée avec succès',
        config: result.config
      });

    } catch (error) {
      logSh(`❌ Erreur sauvegarde config: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur sauvegarde configuration',
        details: error.message
      });
    }
  }

  // ========================================
  // ENDPOINTS CONTRÔLE TRAITEMENT
  // ========================================

  /**
   * POST /api/batch/start
   * Démarre le traitement batch
   */
  async startBatch(req, res) {
    try {
      // Démarrer le traitement via BatchProcessor
      const status = await this.batchProcessor.start();

      logSh(`🚀 Traitement batch démarré - ${status.totalRows} lignes`, 'INFO');

      res.json({
        success: true,
        message: 'Traitement batch démarré',
        status: status
      });

    } catch (error) {
      logSh(`❌ Erreur démarrage batch: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur démarrage traitement',
        details: error.message
      });
    }
  }

  /**
   * POST /api/batch/stop
   * Arrête le traitement batch
   */
  async stopBatch(req, res) {
    try {
      const status = await this.batchProcessor.stop();

      logSh('🛑 Traitement batch arrêté', 'INFO');

      res.json({
        success: true,
        message: 'Traitement batch arrêté',
        status: status
      });

    } catch (error) {
      logSh(`❌ Erreur arrêt batch: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur arrêt traitement',
        details: error.message
      });
    }
  }

  /**
   * POST /api/batch/pause
   * Met en pause le traitement
   */
  async pauseBatch(req, res) {
    try {
      const status = await this.batchProcessor.pause();

      logSh('⏸️ Traitement batch mis en pause', 'INFO');

      res.json({
        success: true,
        message: 'Traitement mis en pause',
        status: status
      });

    } catch (error) {
      logSh(`❌ Erreur pause batch: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur pause traitement',
        details: error.message
      });
    }
  }

  /**
   * POST /api/batch/resume
   * Reprend le traitement
   */
  async resumeBatch(req, res) {
    try {
      const status = await this.batchProcessor.resume();

      logSh('▶️ Traitement batch repris', 'INFO');

      res.json({
        success: true,
        message: 'Traitement repris',
        status: status
      });

    } catch (error) {
      logSh(`❌ Erreur reprise batch: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur reprise traitement',
        details: error.message
      });
    }
  }

  // ========================================
  // ENDPOINTS MONITORING
  // ========================================

  /**
   * GET /api/batch/status
   * Récupère l'état actuel du traitement
   */
  async getStatus(req, res) {
    try {
      const status = this.batchProcessor.getStatus();

      res.json({
        success: true,
        status: status,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération status: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération status',
        details: error.message
      });
    }
  }

  /**
   * GET /api/batch/progress
   * Récupère la progression détaillée
   */
  async getProgress(req, res) {
    try {
      const progress = this.batchProcessor.getProgress();

      res.json({
        success: true,
        progress: progress,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération progress: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération progression',
        details: error.message
      });
    }
  }

  // ========================================
  // ENDPOINTS TENDANCES
  // ========================================

  /**
   * GET /api/batch/trends
   * Liste toutes les tendances disponibles
   */
  async getTrends(req, res) {
    try {
      const trends = this.trendManager.getAvailableTrends();
      const current = this.trendManager.getCurrentTrend();
      const status = this.trendManager.getStatus();

      res.json({
        success: true,
        trends: {
          available: trends,
          current: current,
          categories: this.groupTrendsByCategory(trends),
          status: status
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération tendances: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération tendances',
        details: error.message
      });
    }
  }

  /**
   * POST /api/batch/trends/select
   * Sélectionne une tendance
   */
  async selectTrend(req, res) {
    try {
      const { trendId } = req.body;

      if (!trendId) {
        return res.status(400).json({
          success: false,
          error: 'ID de tendance requis'
        });
      }

      const result = await this.trendManager.setTrend(trendId);

      logSh(`🎯 Tendance sélectionnée: ${result.name}`, 'INFO');

      res.json({
        success: true,
        trend: result,
        message: `Tendance "${result.name}" appliquée`,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur sélection tendance: ${error.message}`, 'ERROR');
      res.status(400).json({
        success: false,
        error: 'Erreur sélection tendance',
        details: error.message
      });
    }
  }

  /**
   * DELETE /api/batch/trends
   * Désactive la tendance actuelle
   */
  async clearTrend(req, res) {
    try {
      this.trendManager.clearTrend();

      logSh('🔄 Tendance désactivée', 'INFO');

      res.json({
        success: true,
        message: 'Aucune tendance appliquée',
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur désactivation tendance: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur désactivation tendance',
        details: error.message
      });
    }
  }

  // ========================================
  // HELPER METHODS TENDANCES
  // ========================================

  /**
   * Groupe les tendances par catégorie
   */
  groupTrendsByCategory(trends) {
    const categories = {};

    trends.forEach(trend => {
      const category = trend.category || 'autre';
      if (!categories[category]) {
        categories[category] = [];
      }
      categories[category].push(trend);
    });

    return categories;
  }

  // ========================================
  // ENDPOINTS DIGITAL OCEAN
  // ========================================

  /**
   * GET /api/batch/templates
   * Liste les templates disponibles
   */
  async getTemplates(req, res) {
    try {
      const templates = await this.digitalOceanTemplates.listAvailableTemplates();
      const stats = this.digitalOceanTemplates.getCacheStats();

      res.json({
        success: true,
        templates: templates,
        cacheStats: stats,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération templates: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération templates',
        details: error.message
      });
    }
  }

  /**
   * GET /api/batch/templates/:filename
   * Récupère un template spécifique
   */
  async getTemplate(req, res) {
    try {
      const { filename } = req.params;
      const template = await this.digitalOceanTemplates.getTemplate(filename);

      res.json({
        success: true,
        filename: filename,
        template: template,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur récupération template ${req.params.filename}: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération template',
        details: error.message
      });
    }
  }

  /**
   * DELETE /api/batch/cache
   * Vide le cache des templates
   */
  async clearCache(req, res) {
    try {
      await this.digitalOceanTemplates.clearCache();

      res.json({
        success: true,
        message: 'Cache vidé avec succès',
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur vidage cache: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur vidage cache',
        details: error.message
      });
    }
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/batch/BatchProcessor.original.js                        │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// BATCH PROCESSOR - SYSTÈME DE QUEUE
// Responsabilité: Traitement batch des lignes Google Sheets avec pipeline modulaire
// ========================================

const { logSh } = require('../ErrorReporting');
const { tracer } = require('../trace');
const { handleModularWorkflow } = require('../Main');
const { readInstructionsData } = require('../BrainConfig');
const fs = require('fs').promises;
const path = require('path');

/**
 * BATCH PROCESSOR
 * Système de queue pour traiter les lignes Google Sheets une par une
 */
class BatchProcessor {

  constructor() {
    this.statusPath = path.join(__dirname, '../../config/batch-status.json');
    this.configPath = path.join(__dirname, '../../config/batch-config.json');
    this.queuePath = path.join(__dirname, '../../config/batch-queue.json');

    // État du processeur
    this.isRunning = false;
    this.isPaused = false;
    this.currentRow = null;
    this.queue = [];
    this.errors = [];
    this.results = [];

    // Configuration par défaut
    this.config = {
      selective: 'standardEnhancement',
      adversarial: 'light',
      humanSimulation: 'none',
      patternBreaking: 'none',
      intensity: 1.0,
      rowRange: { start: 2, end: 10 },
      saveIntermediateSteps: false
    };

    // Métriques
    this.startTime = null;
    this.processedCount = 0;
    this.errorCount = 0;

    // Callbacks pour updates
    this.onStatusUpdate = null;
    this.onProgress = null;
    this.onError = null;
    this.onComplete = null;

    this.initializeProcessor();
  }

  /**
   * Initialise le processeur
   */
  async initializeProcessor() {
    try {
      // Charger la configuration
      await this.loadConfig();

      // Initialiser la queue si elle n'existe pas
      await this.initializeQueue();

      logSh('🎯 BatchProcessor initialisé', 'DEBUG');

    } catch (error) {
      logSh(`❌ Erreur initialisation BatchProcessor: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Initialise les fichiers de configuration (alias pour compatibilité tests)
   */
  async initializeFiles() {
    try {
      // Créer le dossier config s'il n'existe pas
      const configDir = path.dirname(this.configPath);
      await fs.mkdir(configDir, { recursive: true });

      // Créer config par défaut si inexistant
      try {
        await fs.access(this.configPath);
      } catch {
        await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2));
        logSh('📝 Configuration batch par défaut créée', 'DEBUG');
      }

      // Créer status par défaut si inexistant
      const defaultStatus = {
        status: 'idle',
        currentRow: null,
        totalRows: 0,
        progress: 0,
        startTime: null,
        estimatedEnd: null,
        errors: [],
        lastResult: null,
        config: this.config
      };

      try {
        await fs.access(this.statusPath);
      } catch {
        await fs.writeFile(this.statusPath, JSON.stringify(defaultStatus, null, 2));
        logSh('📊 Status batch par défaut créé', 'DEBUG');
      }

    } catch (error) {
      logSh(`❌ Erreur initialisation fichiers batch: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Charge la configuration
   */
  async loadConfig() {
    try {
      const configData = await fs.readFile(this.configPath, 'utf8');
      this.config = JSON.parse(configData);
      logSh(`📋 Configuration chargée: ${JSON.stringify(this.config)}`, 'DEBUG');
    } catch (error) {
      logSh('⚠️ Configuration non trouvée, utilisation des valeurs par défaut', 'WARNING');
    }
  }

  /**
   * Initialise la queue
   */
  async initializeQueue() {
    try {
      // Essayer de charger la queue existante
      try {
        const queueData = await fs.readFile(this.queuePath, 'utf8');
        const savedQueue = JSON.parse(queueData);

        if (savedQueue.queue && Array.isArray(savedQueue.queue)) {
          this.queue = savedQueue.queue;
          this.processedCount = savedQueue.processedCount || 0;
          logSh(`📊 Queue restaurée: ${this.queue.length} éléments`, 'DEBUG');
        }
      } catch {
        // Queue n'existe pas, on la créera
      }

      // Si queue vide, la populer depuis la configuration
      if (this.queue.length === 0) {
        await this.populateQueue();
      }

    } catch (error) {
      logSh(`❌ Erreur initialisation queue: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Popule la queue avec les lignes à traiter
   */
  async populateQueue() {
    try {
      this.queue = [];

      const { start, end } = this.config.rowRange;

      for (let rowNumber = start; rowNumber <= end; rowNumber++) {
        this.queue.push({
          rowNumber,
          status: 'pending',
          attempts: 0,
          maxAttempts: 3,
          error: null,
          result: null,
          startTime: null,
          endTime: null
        });
      }

      await this.saveQueue();

      logSh(`📋 Queue populée: ${this.queue.length} lignes (${start} à ${end})`, 'INFO');

    } catch (error) {
      logSh(`❌ Erreur population queue: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  /**
   * Sauvegarde la queue
   */
  async saveQueue() {
    try {
      const queueData = {
        queue: this.queue,
        processedCount: this.processedCount,
        lastUpdate: new Date().toISOString()
      };

      await fs.writeFile(this.queuePath, JSON.stringify(queueData, null, 2));
    } catch (error) {
      logSh(`❌ Erreur sauvegarde queue: ${error.message}`, 'ERROR');
    }
  }

  // ========================================
  // CONTRÔLES PRINCIPAUX
  // ========================================

  /**
   * Démarre le traitement batch
   */
  async start() {
    return tracer.run('BatchProcessor.start', async () => {
      if (this.isRunning) {
        throw new Error('Le traitement est déjà en cours');
      }

      logSh('🚀 Démarrage traitement batch', 'INFO');

      this.isRunning = true;
      this.isPaused = false;
      this.startTime = new Date();
      this.processedCount = 0;
      this.errorCount = 0;

      // Charger la configuration la plus récente
      await this.loadConfig();

      // Si queue vide ou configuration changée, repopuler
      if (this.queue.length === 0) {
        await this.populateQueue();
      }

      // Mettre à jour le status
      await this.updateStatus();

      // Démarrer le traitement asynchrone
      this.processQueue().catch(error => {
        logSh(`❌ Erreur traitement queue: ${error.message}`, 'ERROR');
        this.handleError(error);
      });

      return this.getStatus();
    });
  }

  /**
   * Arrête le traitement batch
   */
  async stop() {
    return tracer.run('BatchProcessor.stop', async () => {
      logSh('🛑 Arrêt traitement batch', 'INFO');

      this.isRunning = false;
      this.isPaused = false;
      this.currentRow = null;

      await this.updateStatus();

      return this.getStatus();
    });
  }

  /**
   * Met en pause le traitement
   */
  async pause() {
    return tracer.run('BatchProcessor.pause', async () => {
      if (!this.isRunning) {
        throw new Error('Aucun traitement en cours');
      }

      logSh('⏸️ Mise en pause traitement batch', 'INFO');

      this.isPaused = true;

      await this.updateStatus();

      return this.getStatus();
    });
  }

  /**
   * Reprend le traitement
   */
  async resume() {
    return tracer.run('BatchProcessor.resume', async () => {
      if (!this.isRunning || !this.isPaused) {
        throw new Error('Aucun traitement en pause');
      }

      logSh('▶️ Reprise traitement batch', 'INFO');

      this.isPaused = false;

      await this.updateStatus();

      // Reprendre le traitement
      this.processQueue().catch(error => {
        logSh(`❌ Erreur reprise traitement: ${error.message}`, 'ERROR');
        this.handleError(error);
      });

      return this.getStatus();
    });
  }

  // ========================================
  // TRAITEMENT QUEUE
  // ========================================

  /**
   * Traite la queue élément par élément
   */
  async processQueue() {
    return tracer.run('BatchProcessor.processQueue', async () => {
      while (this.isRunning && !this.isPaused) {
        // Chercher le prochain élément à traiter
        const nextItem = this.queue.find(item => item.status === 'pending' ||
          (item.status === 'error' && item.attempts < item.maxAttempts));

        if (!nextItem) {
          // Queue terminée
          logSh('✅ Traitement queue terminé', 'INFO');
          await this.complete();
          break;
        }

        // Traiter l'élément
        await this.processItem(nextItem);

        // Pause entre les éléments (pour éviter rate limiting)
        await this.sleep(1000);
      }
    });
  }

  /**
   * Traite un élément de la queue
   */
  async processItem(item) {
    return tracer.run('BatchProcessor.processItem', async () => {
      logSh(`🔄 Traitement ligne ${item.rowNumber} (tentative ${item.attempts + 1}/${item.maxAttempts})`, 'INFO');

      this.currentRow = item.rowNumber;
      item.status = 'processing';
      item.startTime = new Date().toISOString();
      item.attempts++;

      await this.updateStatus();
      await this.saveQueue();

      try {
        // Traiter la ligne avec le pipeline modulaire
        const result = await this.processRow(item.rowNumber);

        // Succès
        item.status = 'completed';
        item.result = result;
        item.endTime = new Date().toISOString();
        item.error = null;

        this.processedCount++;

        logSh(`✅ Ligne ${item.rowNumber} traitée avec succès`, 'INFO');

        // Callback succès
        if (this.onProgress) {
          this.onProgress(item, this.getProgress());
        }

      } catch (error) {
        // Erreur
        item.error = {
          message: error.message,
          stack: error.stack,
          timestamp: new Date().toISOString()
        };

        if (item.attempts >= item.maxAttempts) {
          item.status = 'failed';
          this.errorCount++;

          logSh(`❌ Ligne ${item.rowNumber} échouée définitivement après ${item.attempts} tentatives`, 'ERROR');
        } else {
          item.status = 'error';
          logSh(`⚠️ Ligne ${item.rowNumber} échouée, retry possible`, 'WARNING');
        }

        // Callback erreur
        if (this.onError) {
          this.onError(item, error);
        }
      }

      this.currentRow = null;
      await this.updateStatus();
      await this.saveQueue();
    });
  }

  /**
   * Traite une ligne spécifique
   */
  async processRow(rowNumber) {
    return tracer.run('BatchProcessor.processRow', { rowNumber }, async () => {
      // Configuration pour cette ligne
      const rowConfig = {
        rowNumber,
        source: 'batch_processor',
        selectiveStack: this.config.selective,
        adversarialMode: this.config.adversarial,
        humanSimulationMode: this.config.humanSimulation,
        patternBreakingMode: this.config.patternBreaking,
        intensity: this.config.intensity,
        saveIntermediateSteps: this.config.saveIntermediateSteps
      };

      logSh(`🎯 Configuration ligne ${rowNumber}: ${JSON.stringify(rowConfig)}`, 'DEBUG');

      // Exécuter le workflow modulaire
      const result = await handleModularWorkflow(rowConfig);

      logSh(`📊 Résultat ligne ${rowNumber}: ${result ? 'SUCCESS' : 'FAILED'}`, 'INFO');

      return result;
    });
  }

  // ========================================
  // GESTION ÉTAT
  // ========================================

  /**
   * Met à jour le status
   */
  async updateStatus() {
    const status = this.getStatus();

    try {
      await fs.writeFile(this.statusPath, JSON.stringify(status, null, 2));

      // Callback update
      if (this.onStatusUpdate) {
        this.onStatusUpdate(status);
      }

    } catch (error) {
      logSh(`❌ Erreur mise à jour status: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Retourne le status actuel
   */
  getStatus() {
    const now = new Date();
    const completedItems = this.queue.filter(item => item.status === 'completed').length;
    const failedItems = this.queue.filter(item => item.status === 'failed').length;
    const totalItems = this.queue.length;

    const progress = totalItems > 0 ? ((completedItems + failedItems) / totalItems) * 100 : 0;

    let status = 'idle';
    if (this.isRunning && this.isPaused) {
      status = 'paused';
    } else if (this.isRunning) {
      status = 'running';
    } else if (completedItems + failedItems === totalItems && totalItems > 0) {
      status = 'completed';
    }

    return {
      status,
      currentRow: this.currentRow,
      totalRows: totalItems,
      completedRows: completedItems,
      failedRows: failedItems,
      progress: Math.round(progress),
      startTime: this.startTime ? this.startTime.toISOString() : null,
      estimatedEnd: this.estimateCompletionTime(),
      errors: this.queue.filter(item => item.error).map(item => ({
        rowNumber: item.rowNumber,
        error: item.error,
        attempts: item.attempts
      })),
      lastResult: this.getLastResult(),
      config: this.config,
      queue: this.queue
    };
  }

  /**
   * Retourne la progression détaillée
   */
  getProgress() {
    const status = this.getStatus();
    const now = new Date();
    const elapsed = this.startTime ? now - this.startTime : 0;

    const avgTimePerRow = status.completedRows > 0 ? elapsed / status.completedRows : 0;
    const remainingRows = status.totalRows - status.completedRows - status.failedRows;
    const estimatedRemaining = avgTimePerRow * remainingRows;

    return {
      ...status,
      metrics: {
        elapsedTime: elapsed,
        avgTimePerRow: avgTimePerRow,
        estimatedRemaining: estimatedRemaining,
        completionPercentage: status.progress,
        throughput: status.completedRows > 0 && elapsed > 0 ? (status.completedRows / (elapsed / 1000 / 60)) : 0 // rows/minute
      }
    };
  }

  /**
   * Estime l'heure de fin
   */
  estimateCompletionTime() {
    if (!this.startTime || !this.isRunning || this.isPaused) {
      return null;
    }

    const progress = this.getProgress();
    if (progress.metrics.estimatedRemaining > 0) {
      const endTime = new Date(Date.now() + progress.metrics.estimatedRemaining);
      return endTime.toISOString();
    }

    return null;
  }

  /**
   * Retourne le dernier résultat
   */
  getLastResult() {
    const completedItems = this.queue.filter(item => item.status === 'completed');
    if (completedItems.length === 0) return null;

    const lastItem = completedItems[completedItems.length - 1];
    return {
      rowNumber: lastItem.rowNumber,
      result: lastItem.result,
      endTime: lastItem.endTime
    };
  }

  /**
   * Gère les erreurs critiques
   */
  async handleError(error) {
    logSh(`💥 Erreur critique BatchProcessor: ${error.message}`, 'ERROR');

    this.isRunning = false;
    this.isPaused = false;

    await this.updateStatus();

    if (this.onError) {
      this.onError(null, error);
    }
  }

  /**
   * Termine le traitement
   */
  async complete() {
    logSh('🏁 Traitement batch terminé', 'INFO');

    this.isRunning = false;
    this.isPaused = false;
    this.currentRow = null;

    await this.updateStatus();

    if (this.onComplete) {
      this.onComplete(this.getStatus());
    }
  }

  // ========================================
  // UTILITAIRES
  // ========================================

  /**
   * Pause l'exécution
   */
  async sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * Reset la queue
   */
  async resetQueue() {
    logSh('🔄 Reset de la queue', 'INFO');

    this.queue = [];
    this.processedCount = 0;
    this.errorCount = 0;

    await this.populateQueue();
    await this.updateStatus();
  }

  /**
   * Configure les callbacks
   */
  setCallbacks({ onStatusUpdate, onProgress, onError, onComplete }) {
    this.onStatusUpdate = onStatusUpdate;
    this.onProgress = onProgress;
    this.onError = onError;
    this.onComplete = onComplete;
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/modes/AutoProcessor.js                                  │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: AutoProcessor.js  
// RESPONSABILITÉ: Mode AUTO - Traitement Batch Google Sheets
// FONCTIONNALITÉS: Processing queue, scheduling, monitoring
// ========================================

const { logSh } = require('../ErrorReporting');
const { handleModularWorkflow } = require('../Main');
const { readInstructionsData } = require('../BrainConfig');

/**
 * PROCESSEUR MODE AUTO
 * Traitement automatique et séquentiel des lignes Google Sheets
 */
class AutoProcessor {
  
  constructor(options = {}) {
    this.config = {
      batchSize: options.batchSize || 5,                    // Lignes par batch
      delayBetweenItems: options.delayBetweenItems || 2000, // 2s entre chaque ligne
      delayBetweenBatches: options.delayBetweenBatches || 30000, // 30s entre batches
      maxRetries: options.maxRetries || 3,
      startRow: options.startRow || 2,
      endRow: options.endRow || null,                       // null = jusqu'à la fin
      autoMode: options.autoMode || 'standardEnhancement',  // Config par défaut
      monitoringPort: options.monitoringPort || 3001,
      ...options
    };
    
    this.processingQueue = [];
    this.processedItems = [];
    this.failedItems = [];
    
    this.state = {
      isProcessing: false,
      isPaused: false,
      currentItem: null,
      startTime: null,
      lastActivity: null,
      totalProcessed: 0,
      totalErrors: 0
    };
    
    this.stats = {
      itemsQueued: 0,
      itemsProcessed: 0,
      itemsFailed: 0,
      averageProcessingTime: 0,
      totalProcessingTime: 0,
      startTime: Date.now(),
      lastProcessedAt: null
    };
    
    this.monitoringServer = null;
    this.processingInterval = null;
    this.isRunning = false;
  }

  // ========================================
  // DÉMARRAGE ET ARRÊT
  // ========================================
  
  /**
   * Démarre le processeur AUTO complet
   */
  async start() {
    if (this.isRunning) {
      logSh('⚠️ AutoProcessor déjà en cours d\'exécution', 'WARNING');
      return;
    }
    
    logSh('🤖 Démarrage AutoProcessor...', 'INFO');
    
    try {
      // 1. Charger la queue depuis Google Sheets
      await this.loadProcessingQueue();
      
      // 2. Serveur de monitoring (lecture seule)
      await this.startMonitoringServer();
      
      // 3. Démarrer le traitement
      this.startProcessingLoop();
      
      // 4. Monitoring périodique
      this.startHealthMonitoring();
      
      this.isRunning = true;
      this.state.startTime = Date.now();
      
      logSh(`✅ AutoProcessor démarré: ${this.stats.itemsQueued} éléments en queue`, 'INFO');
      logSh(`📊 Monitoring sur http://localhost:${this.config.monitoringPort}`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Erreur démarrage AutoProcessor: ${error.message}`, 'ERROR');
      await this.stop();
      throw error;
    }
  }

  /**
   * Arrête le processeur AUTO
   */
  async stop() {
    if (!this.isRunning) return;
    
    logSh('🛑 Arrêt AutoProcessor...', 'INFO');
    
    try {
      // Marquer comme en arrêt
      this.isRunning = false;
      
      // Arrêter la boucle de traitement
      if (this.processingInterval) {
        clearInterval(this.processingInterval);
        this.processingInterval = null;
      }
      
      // Attendre la fin du traitement en cours
      if (this.state.isProcessing) {
        logSh('⏳ Attente fin traitement en cours...', 'INFO');
        await this.waitForCurrentProcessing();
      }
      
      // Arrêter monitoring
      if (this.healthInterval) {
        clearInterval(this.healthInterval);
        this.healthInterval = null;
      }
      
      // Arrêter serveur monitoring
      if (this.monitoringServer) {
        await new Promise((resolve) => {
          this.monitoringServer.close(() => resolve());
        });
        this.monitoringServer = null;
      }
      
      // Sauvegarder progression
      await this.saveProgress();
      
      logSh('✅ AutoProcessor arrêté', 'INFO');
      
    } catch (error) {
      logSh(`⚠️ Erreur arrêt AutoProcessor: ${error.message}`, 'WARNING');
    }
  }

  // ========================================
  // CHARGEMENT QUEUE
  // ========================================
  
  /**
   * Charge la queue de traitement depuis Google Sheets
   */
  async loadProcessingQueue() {
    logSh('📋 Chargement queue depuis Google Sheets...', 'INFO');
    
    try {
      // Restaurer progression si disponible - TEMPORAIREMENT DÉSACTIVÉ
      // const savedProgress = await this.loadProgress();
      // const processedRows = new Set(savedProgress?.processedRows || []);
      const processedRows = new Set(); // Ignore la progression sauvegardée
      
      // Scanner les lignes disponibles
      let currentRow = this.config.startRow;
      let consecutiveEmptyRows = 0;
      const maxEmptyRows = 5; // Arrêt après 5 lignes vides consécutives
      
      while (currentRow <= (this.config.endRow || 10)) { // 🔧 LIMITE MAX POUR ÉVITER BOUCLE INFINIE
        // Vérifier limite max si définie
        if (this.config.endRow && currentRow > this.config.endRow) {
          break;
        }
        
        try {
          // Tenter de lire la ligne
          const csvData = await readInstructionsData(currentRow);
          
          if (!csvData || !csvData.mc0) {
            // Ligne vide ou invalide
            consecutiveEmptyRows++;
            if (consecutiveEmptyRows >= maxEmptyRows) {
              logSh(`🛑 Arrêt scan après ${maxEmptyRows} lignes vides consécutives à partir de la ligne ${currentRow - maxEmptyRows + 1}`, 'INFO');
              break;
            }
          } else {
            // Ligne valide trouvée
            consecutiveEmptyRows = 0;
            
            // Ajouter à la queue si pas déjà traitée
            if (!processedRows.has(currentRow)) {
              this.processingQueue.push({
                rowNumber: currentRow,
                data: csvData,
                attempts: 0,
                status: 'pending',
                addedAt: Date.now()
              });
            } else {
              logSh(`⏭️ Ligne ${currentRow} déjà traitée, ignorée`, 'DEBUG');
            }
          }
          
        } catch (error) {
          // Erreur de lecture = ligne probablement vide
          consecutiveEmptyRows++;
          if (consecutiveEmptyRows >= maxEmptyRows) {
            break;
          }
        }
        
        currentRow++;
      }
      
      this.stats.itemsQueued = this.processingQueue.length;
      
      logSh(`📊 Queue chargée: ${this.stats.itemsQueued} éléments (lignes ${this.config.startRow}-${currentRow - 1})`, 'INFO');
      
      if (this.stats.itemsQueued === 0) {
        logSh('⚠️ Aucun élément à traiter trouvé', 'WARNING');
      }
      
    } catch (error) {
      logSh(`❌ Erreur chargement queue: ${error.message}`, 'ERROR');
      throw error;
    }
  }

  // ========================================
  // BOUCLE DE TRAITEMENT
  // ========================================
  
  /**
   * Démarre la boucle principale de traitement
   */
  startProcessingLoop() {
    if (this.processingQueue.length === 0) {
      logSh('⚠️ Queue vide, pas de traitement à démarrer', 'WARNING');
      return;
    }
    
    logSh('🔄 Démarrage boucle de traitement...', 'INFO');
    
    // Traitement immédiat du premier batch
    setTimeout(() => {
      this.processNextBatch();
    }, 1000);
    
    // Puis traitement périodique
    this.processingInterval = setInterval(() => {
      if (!this.state.isProcessing && !this.state.isPaused) {
        this.processNextBatch();
      }
    }, this.config.delayBetweenBatches);
  }

  /**
   * Traite le prochain batch d'éléments
   */
  async processNextBatch() {
    if (this.state.isProcessing || this.state.isPaused || !this.isRunning) {
      return;
    }
    
    // Vérifier s'il reste des éléments
    const pendingItems = this.processingQueue.filter(item => item.status === 'pending');
    if (pendingItems.length === 0) {
      logSh('✅ Tous les éléments ont été traités', 'INFO');
      await this.completeProcessing();
      return;
    }
    
    // Prendre le prochain batch
    const batchItems = pendingItems.slice(0, this.config.batchSize);
    
    logSh(`🚀 Traitement batch: ${batchItems.length} éléments`, 'INFO');
    this.state.isProcessing = true;
    this.state.lastActivity = Date.now();
    
    try {
      // Traiter chaque élément du batch séquentiellement
      for (const item of batchItems) {
        if (!this.isRunning) break; // Arrêt demandé
        
        await this.processItem(item);
        
        // Délai entre éléments
        if (this.config.delayBetweenItems > 0) {
          await this.sleep(this.config.delayBetweenItems);
        }
      }
      
      logSh(`✅ Batch terminé: ${batchItems.length} éléments traités`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Erreur traitement batch: ${error.message}`, 'ERROR');
    } finally {
      this.state.isProcessing = false;
      this.state.currentItem = null;
    }
  }

  /**
   * Traite un élément individuel
   */
  async processItem(item) {
    const startTime = Date.now();
    this.state.currentItem = item;
    
    logSh(`🎯 Traitement ligne ${item.rowNumber}: ${item.data.mc0}`, 'INFO');
    
    try {
      item.status = 'processing';
      item.attempts++;
      item.startedAt = startTime;
      
      // Configuration de traitement automatique
      const processingConfig = {
        rowNumber: item.rowNumber,
        selectiveStack: this.config.autoMode,
        adversarialMode: 'light',
        humanSimulationMode: 'lightSimulation',
        patternBreakingMode: 'standardPatternBreaking',
        source: `auto_processor_row_${item.rowNumber}`
      };
      
      // Exécution du workflow modulaire
      const result = await handleModularWorkflow(processingConfig);
      
      const duration = Date.now() - startTime;
      
      // Succès
      item.status = 'completed';
      item.completedAt = Date.now();
      item.duration = duration;
      item.result = {
        stats: result.stats,
        success: true
      };
      
      this.processedItems.push(item);
      this.stats.itemsProcessed++;
      this.stats.totalProcessingTime += duration;
      this.stats.averageProcessingTime = Math.round(this.stats.totalProcessingTime / this.stats.itemsProcessed);
      this.stats.lastProcessedAt = Date.now();
      
      logSh(`✅ Ligne ${item.rowNumber} terminée (${duration}ms) - ${result.stats.totalModifications || 0} modifications`, 'INFO');
      
    } catch (error) {
      const duration = Date.now() - startTime;
      
      // Échec
      item.status = 'failed';
      item.failedAt = Date.now();
      item.duration = duration;
      item.error = error.message;
      
      this.stats.totalErrors++;
      
      logSh(`❌ Échec ligne ${item.rowNumber} (tentative ${item.attempts}/${this.config.maxRetries}): ${error.message}`, 'ERROR');
      
      // Retry si possible
      if (item.attempts < this.config.maxRetries) {
        logSh(`🔄 Retry programmé pour ligne ${item.rowNumber}`, 'INFO');
        item.status = 'pending'; // Remettre en queue
      } else {
        logSh(`💀 Ligne ${item.rowNumber} abandonnée après ${item.attempts} tentatives`, 'WARNING');
        this.failedItems.push(item);
        this.stats.itemsFailed++;
      }
    }
    
    // Sauvegarder progression périodiquement
    if (this.stats.itemsProcessed % 5 === 0) {
      await this.saveProgress();
    }
  }

  // ========================================
  // SERVEUR MONITORING
  // ========================================
  
  /**
   * Démarre le serveur de monitoring (lecture seule)
   */
  async startMonitoringServer() {
    const express = require('express');
    const app = express();
    
    app.use(express.json());
    
    // Page de status principale
    app.get('/', (req, res) => {
      res.send(this.generateStatusPage());
    });
    
    // API status JSON
    app.get('/api/status', (req, res) => {
      res.json(this.getDetailedStatus());
    });
    
    // API stats JSON
    app.get('/api/stats', (req, res) => {
      res.json({
        success: true,
        stats: { ...this.stats },
        queue: {
          total: this.processingQueue.length,
          pending: this.processingQueue.filter(i => i.status === 'pending').length,
          processing: this.processingQueue.filter(i => i.status === 'processing').length,
          completed: this.processingQueue.filter(i => i.status === 'completed').length,
          failed: this.processingQueue.filter(i => i.status === 'failed').length
        },
        timestamp: new Date().toISOString()
      });
    });
    
    // Actions de contrôle (limitées)
    app.post('/api/pause', (req, res) => {
      this.pauseProcessing();
      res.json({ success: true, message: 'Traitement mis en pause' });
    });
    
    app.post('/api/resume', (req, res) => {
      this.resumeProcessing();
      res.json({ success: true, message: 'Traitement repris' });
    });
    
    // 404 pour autres routes
    app.use('*', (req, res) => {
      res.status(404).json({
        success: false,
        error: 'Route non trouvée',
        mode: 'AUTO',
        message: 'Interface de monitoring en lecture seule'
      });
    });
    
    // Démarrage serveur
    return new Promise((resolve, reject) => {
      try {
        this.monitoringServer = app.listen(this.config.monitoringPort, '0.0.0.0', () => {
          logSh(`📊 Serveur monitoring démarré sur http://localhost:${this.config.monitoringPort}`, 'DEBUG');
          resolve();
        });
        
        this.monitoringServer.on('error', (error) => {
          reject(error);
        });
        
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * Génère la page de status HTML
   */
  generateStatusPage() {
    const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000);
    const progress = this.stats.itemsQueued > 0 ? 
      Math.round((this.stats.itemsProcessed / this.stats.itemsQueued) * 100) : 0;
    
    const pendingCount = this.processingQueue.filter(i => i.status === 'pending').length;
    const completedCount = this.processingQueue.filter(i => i.status === 'completed').length;
    const failedCount = this.processingQueue.filter(i => i.status === 'failed').length;
    
    return `
    <!DOCTYPE html>
    <html>
    <head>
        <title>SEO Generator - Mode AUTO</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); min-height: 100vh; }
            .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
            .header { text-align: center; margin-bottom: 40px; }
            .header h1 { color: #2d3748; margin-bottom: 10px; }
            .mode-badge { background: #4299e1; color: white; padding: 8px 16px; border-radius: 20px; font-weight: bold; }
            .progress { background: #e2e8f0; height: 20px; border-radius: 10px; margin: 20px 0; overflow: hidden; }
            .progress-bar { background: linear-gradient(90deg, #4facfe, #00f2fe); height: 100%; width: ${progress}%; transition: width 0.3s; }
            .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 40px; }
            .stat-card { background: #f7fafc; padding: 20px; border-radius: 10px; text-align: center; border: 1px solid #e2e8f0; }
            .stat-card.processing { background: #fef5e7; border-color: #f6ad55; }
            .stat-card.completed { background: #f0fff4; border-color: #48bb78; }
            .stat-card.failed { background: #fed7d7; border-color: #f56565; }
            .stat-number { font-size: 2em; font-weight: bold; color: #2d3748; }
            .stat-label { color: #718096; margin-top: 5px; }
            .section { margin: 30px 0; padding: 25px; border: 1px solid #e2e8f0; border-radius: 10px; background: #f9f9f9; }
            .button { display: inline-block; padding: 12px 24px; margin: 8px; background: linear-gradient(135deg, #4facfe, #00f2fe); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; font-weight: 500; }
            .alert { padding: 15px; margin: 20px 0; border-radius: 8px; border-left: 4px solid; }
            .alert.info { background: #ebf8ff; border-color: #4299e1; color: #2a4365; }
            .alert.warning { background: #fefcbf; border-color: #f6ad55; color: #744210; }
            .current-item { background: #e6fffa; padding: 15px; border-radius: 8px; border: 1px solid #38b2ac; margin: 15px 0; }
        </style>
        <script>
            function refreshPage() { window.location.reload(); }
            function pauseProcessing() { 
                fetch('/api/pause', { method: 'POST' })
                    .then(() => setTimeout(refreshPage, 1000)); 
            }
            function resumeProcessing() { 
                fetch('/api/resume', { method: 'POST' })
                    .then(() => setTimeout(refreshPage, 1000)); 
            }
            setInterval(refreshPage, 30000); // Auto-refresh 30s
        </script>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>🤖 SEO Generator Server</h1>
                <span class="mode-badge">MODE AUTO</span>
                <p style="color: #718096; margin-top: 15px;">Traitement Automatique Google Sheets</p>
            </div>
            
            <div class="alert info">
                <strong>🤖 Mode AUTO Actif</strong><br>
                Traitement batch des Google Sheets • Interface monitoring lecture seule
            </div>
            
            <div class="progress">
                <div class="progress-bar"></div>
            </div>
            <div style="text-align: center; margin-bottom: 20px; color: #4a5568;">
                Progression: ${progress}% (${completedCount}/${this.stats.itemsQueued})
            </div>
            
            <div class="stats">
                <div class="stat-card">
                    <div class="stat-number">${uptime}s</div>
                    <div class="stat-label">Uptime</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${pendingCount}</div>
                    <div class="stat-label">En Attente</div>
                </div>
                <div class="stat-card processing">
                    <div class="stat-number">${this.state.isProcessing ? '1' : '0'}</div>
                    <div class="stat-label">En Traitement</div>
                </div>
                <div class="stat-card completed">
                    <div class="stat-number">${completedCount}</div>
                    <div class="stat-label">Terminés</div>
                </div>
                <div class="stat-card failed">
                    <div class="stat-number">${failedCount}</div>
                    <div class="stat-label">Échecs</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${this.stats.averageProcessingTime}ms</div>
                    <div class="stat-label">Temps Moyen</div>
                </div>
            </div>
            
            ${this.state.currentItem ? `
            <div class="current-item">
                <strong>🎯 Traitement en cours:</strong><br>
                Ligne ${this.state.currentItem.rowNumber}: ${this.state.currentItem.data.mc0}<br>
                <small>Tentative ${this.state.currentItem.attempts}/${this.config.maxRetries}</small>
            </div>
            ` : ''}
            
            <div class="section">
                <h2>🎛️ Contrôles</h2>
                ${this.state.isPaused ? 
                    '<button class="button" onclick="resumeProcessing()">▶️ Reprendre</button>' : 
                    '<button class="button" onclick="pauseProcessing()">⏸️ Pause</button>'
                }
                <button class="button" onclick="refreshPage()">🔄 Actualiser</button>
                <a href="/api/stats" target="_blank" class="button">📊 Stats JSON</a>
            </div>
            
            <div class="section">
                <h2>📋 Configuration</h2>
                <ul style="color: #4a5568; line-height: 1.6;">
                    <li><strong>Batch Size:</strong> ${this.config.batchSize} éléments</li>
                    <li><strong>Délai entre éléments:</strong> ${this.config.delayBetweenItems}ms</li>
                    <li><strong>Délai entre batches:</strong> ${this.config.delayBetweenBatches}ms</li>
                    <li><strong>Max Retries:</strong> ${this.config.maxRetries}</li>
                    <li><strong>Mode Auto:</strong> ${this.config.autoMode}</li>
                    <li><strong>Lignes:</strong> ${this.config.startRow} - ${this.config.endRow || '∞'}</li>
                </ul>
            </div>
        </div>
    </body>
    </html>
    `;
  }

  // ========================================
  // CONTRÔLES ET ÉTAT
  // ========================================
  
  /**
   * Met en pause le traitement
   */
  pauseProcessing() {
    this.state.isPaused = true;
    logSh('⏸️ Traitement mis en pause', 'INFO');
  }

  /**
   * Reprend le traitement
   */
  resumeProcessing() {
    this.state.isPaused = false;
    logSh('▶️ Traitement repris', 'INFO');
  }

  /**
   * Vérifie si le processeur est en cours de traitement
   */
  isProcessing() {
    return this.state.isProcessing;
  }

  /**
   * Attendre la fin du traitement actuel
   */
  async waitForCurrentProcessing(timeout = 30000) {
    const startWait = Date.now();
    
    while (this.state.isProcessing && (Date.now() - startWait) < timeout) {
      await this.sleep(1000);
    }
    
    if (this.state.isProcessing) {
      logSh('⚠️ Timeout attente fin traitement', 'WARNING');
    }
  }

  /**
   * Termine le traitement (tous éléments traités)
   */
  async completeProcessing() {
    logSh('🎉 Traitement terminé - Tous les éléments ont été traités', 'INFO');
    
    const summary = {
      totalItems: this.stats.itemsQueued,
      processed: this.stats.itemsProcessed,
      failed: this.stats.itemsFailed,
      totalTime: Date.now() - this.stats.startTime,
      averageTime: this.stats.averageProcessingTime
    };
    
    logSh(`📊 Résumé final: ${summary.processed}/${summary.totalItems} traités, ${summary.failed} échecs`, 'INFO');
    logSh(`⏱️ Temps total: ${Math.floor(summary.totalTime / 1000)}s, moyenne: ${summary.averageTime}ms/item`, 'INFO');
    
    // Arrêter la boucle
    if (this.processingInterval) {
      clearInterval(this.processingInterval);
      this.processingInterval = null;
    }
    
    // Sauvegarder résultats finaux
    await this.saveProgress();
    
    this.state.isProcessing = false;
  }

  // ========================================
  // MONITORING ET HEALTH
  // ========================================
  
  /**
   * Démarre le monitoring de santé
   */
  startHealthMonitoring() {
    const HEALTH_INTERVAL = 60000; // 1 minute
    
    this.healthInterval = setInterval(() => {
      this.performHealthCheck();
    }, HEALTH_INTERVAL);
    
    logSh('💓 Health monitoring AutoProcessor démarré', 'DEBUG');
  }

  /**
   * Health check périodique
   */
  performHealthCheck() {
    const memUsage = process.memoryUsage();
    const uptime = Date.now() - this.stats.startTime;
    const queueStatus = {
      pending: this.processingQueue.filter(i => i.status === 'pending').length,
      completed: this.processingQueue.filter(i => i.status === 'completed').length,
      failed: this.processingQueue.filter(i => i.status === 'failed').length
    };
    
    logSh(`💓 AutoProcessor Health - Queue: ${queueStatus.pending}P/${queueStatus.completed}C/${queueStatus.failed}F | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE');
    
    // Alertes
    if (memUsage.rss > 2 * 1024 * 1024 * 1024) { // > 2GB
      logSh('⚠️ Utilisation mémoire très élevée', 'WARNING');
    }
    
    if (this.stats.itemsFailed > this.stats.itemsProcessed * 0.5) {
      logSh('⚠️ Taux d\'échec élevé détecté', 'WARNING');
    }
  }

  /**
   * Retourne le status détaillé
   */
  getDetailedStatus() {
    return {
      success: true,
      mode: 'AUTO',
      isRunning: this.isRunning,
      state: { ...this.state },
      stats: {
        ...this.stats,
        uptime: Date.now() - this.stats.startTime
      },
      queue: {
        total: this.processingQueue.length,
        pending: this.processingQueue.filter(i => i.status === 'pending').length,
        processing: this.processingQueue.filter(i => i.status === 'processing').length,
        completed: this.processingQueue.filter(i => i.status === 'completed').length,
        failed: this.processingQueue.filter(i => i.status === 'failed').length
      },
      config: { ...this.config },
      currentItem: this.state.currentItem ? {
        rowNumber: this.state.currentItem.rowNumber,
        data: this.state.currentItem.data.mc0,
        attempts: this.state.currentItem.attempts
      } : null,
      urls: {
        monitoring: `http://localhost:${this.config.monitoringPort}`,
        api: `http://localhost:${this.config.monitoringPort}/api/stats`
      },
      timestamp: new Date().toISOString()
    };
  }

  // ========================================
  // PERSISTANCE ET RÉCUPÉRATION
  // ========================================
  
  /**
   * Sauvegarde la progression
   */
  async saveProgress() {
    try {
      const fs = require('fs').promises;
      const path = require('path');
      
      const progressFile = path.join(__dirname, '../../auto-processor-progress.json');
      const progress = {
        processedRows: this.processedItems.map(item => item.rowNumber),
        failedRows: this.failedItems.map(item => ({ 
          rowNumber: item.rowNumber, 
          error: item.error,
          attempts: item.attempts 
        })),
        stats: { ...this.stats },
        lastSaved: Date.now(),
        timestamp: new Date().toISOString()
      };
      
      await fs.writeFile(progressFile, JSON.stringify(progress, null, 2));
      
    } catch (error) {
      logSh(`⚠️ Erreur sauvegarde progression: ${error.message}`, 'WARNING');
    }
  }

  /**
   * Charge la progression sauvegardée
   */
  async loadProgress() {
    try {
      const fs = require('fs').promises;
      const path = require('path');
      
      const progressFile = path.join(__dirname, '../../auto-processor-progress.json');
      
      try {
        const data = await fs.readFile(progressFile, 'utf8');
        const progress = JSON.parse(data);
        
        logSh(`📂 Progression restaurée: ${progress.processedRows?.length || 0} éléments déjà traités`, 'INFO');
        
        return progress;
        
      } catch (readError) {
        if (readError.code !== 'ENOENT') {
          logSh(`⚠️ Erreur lecture progression: ${readError.message}`, 'WARNING');
        }
        return null;
      }
      
    } catch (error) {
      logSh(`⚠️ Erreur chargement progression: ${error.message}`, 'WARNING');
      return null;
    }
  }

  // ========================================
  // UTILITAIRES
  // ========================================
  
  /**
   * Pause asynchrone
   */
  sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/modes/AutoProcessor.refactored.js                       │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// AUTO PROCESSOR - REFACTORISÉ
// Responsabilité: Mode AUTO - Traitement Batch Google Sheets automatique
// ========================================

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

/**
 * AUTO PROCESSOR
 * Spécialisé pour traitement automatique avec monitoring intégré
 */
class AutoProcessor extends QueueProcessor {

  constructor(options = {}) {
    super({
      name: 'AutoProcessor',
      config: {
        batchSize: options.batchSize || 5,
        delayBetweenItems: options.delayBetweenItems || 2000,
        delayBetweenBatches: options.delayBetweenBatches || 30000,
        maxRetries: options.maxRetries || 3,
        startRow: options.startRow || 2,
        endRow: options.endRow || null,
        selective: 'standardEnhancement',  // Config fixe pour AUTO
        adversarial: 'light',
        humanSimulation: 'lightSimulation',
        patternBreaking: 'standardPatternBreaking',
        intensity: 1.0,
        monitoringPort: options.monitoringPort || 3001,
        ...options
      }
    });

    this.monitoringServer = null;
    this.processingInterval = null;
    this.healthInterval = null;
  }

  // ========================================
  // DÉMARRAGE ET ARRÊT SPÉCIALISÉS
  // ========================================

  /**
   * Démarrage AutoProcessor complet avec monitoring
   */
  async start() {
    if (this.isRunning) {
      logSh('⚠️ AutoProcessor déjà en cours d\'exécution', 'WARNING');
      return;
    }

    logSh('🤖 Démarrage AutoProcessor...', 'INFO');

    try {
      // 1. Charger la queue depuis Google Sheets
      await this.populateQueueFromSheets();

      // 2. Serveur de monitoring
      await this.startMonitoringServer();

      // 3. Démarrer le traitement avec batches
      this.startBatchProcessing();

      // 4. Monitoring périodique
      this.startHealthMonitoring();

      this.isRunning = true;
      this.startTime = new Date();

      logSh(`✅ AutoProcessor démarré: ${this.stats.itemsQueued} éléments en queue`, 'INFO');
      logSh(`📊 Monitoring sur http://localhost:${this.config.monitoringPort}`, 'INFO');

    } catch (error) {
      logSh(`❌ Erreur démarrage AutoProcessor: ${error.message}`, 'ERROR');
      await this.stop();
      throw error;
    }
  }

  /**
   * Arrêt AutoProcessor complet
   */
  async stop() {
    if (!this.isRunning) return;

    logSh('🛑 Arrêt AutoProcessor...', 'INFO');

    try {
      this.isRunning = false;

      // Arrêter la boucle de traitement
      if (this.processingInterval) {
        clearInterval(this.processingInterval);
        this.processingInterval = null;
      }

      // Attendre la fin du traitement en cours
      if (this.currentRow) {
        logSh('⏳ Attente fin traitement en cours...', 'INFO');
        await this.waitForCurrentProcessing();
      }

      // Arrêter monitoring
      if (this.healthInterval) {
        clearInterval(this.healthInterval);
        this.healthInterval = null;
      }

      // Arrêter serveur monitoring
      if (this.monitoringServer) {
        await new Promise((resolve) => {
          this.monitoringServer.close(() => resolve());
        });
        this.monitoringServer = null;
      }

      // Sauvegarder progression
      await this.saveProgress();

      logSh('✅ AutoProcessor arrêté', 'INFO');

    } catch (error) {
      logSh(`⚠️ Erreur arrêt AutoProcessor: ${error.message}`, 'WARNING');
    }
  }

  // ========================================
  // TRAITEMENT BATCH SPÉCIALISÉ
  // ========================================

  /**
   * Démarre le traitement par batches
   */
  startBatchProcessing() {
    if (this.queue.length === 0) {
      logSh('⚠️ Queue vide, pas de traitement à démarrer', 'WARNING');
      return;
    }

    logSh('🔄 Démarrage traitement par batches...', 'INFO');

    // Traitement immédiat du premier batch
    setTimeout(() => {
      this.processNextBatch();
    }, 1000);

    // Puis traitement périodique
    this.processingInterval = setInterval(() => {
      if (!this.isPaused) {
        this.processNextBatch();
      }
    }, this.config.delayBetweenBatches);
  }

  /**
   * Traite le prochain batch
   */
  async processNextBatch() {
    if (this.isPaused || !this.isRunning || this.currentRow) {
      return;
    }

    const pendingItems = this.queue.filter(item => item.status === 'pending');
    if (pendingItems.length === 0) {
      logSh('✅ Tous les éléments ont été traités', 'INFO');
      await this.complete();
      return;
    }

    const batchItems = pendingItems.slice(0, this.config.batchSize);
    logSh(`🚀 Traitement batch: ${batchItems.length} éléments`, 'INFO');

    try {
      for (const item of batchItems) {
        if (!this.isRunning) break;

        await this.processItem(item);

        if (this.config.delayBetweenItems > 0) {
          await this.sleep(this.config.delayBetweenItems);
        }
      }

      logSh(`✅ Batch terminé: ${batchItems.length} éléments traités`, 'INFO');

    } catch (error) {
      logSh(`❌ Erreur traitement batch: ${error.message}`, 'ERROR');
    }
  }

  /**
   * Configuration spécifique AutoProcessor
   */
  buildRowConfig(rowNumber, data = null) {
    return {
      rowNumber,
      selectiveStack: this.config.selective,
      adversarialMode: this.config.adversarial,
      humanSimulationMode: this.config.humanSimulation,
      patternBreakingMode: this.config.patternBreaking,
      source: `auto_processor_row_${rowNumber}`
    };
  }

  // ========================================
  // SERVEUR MONITORING
  // ========================================

  /**
   * Démarre le serveur de monitoring
   */
  async startMonitoringServer() {
    const express = require('express');
    const app = express();

    app.use(express.json());

    // Page de status principale
    app.get('/', (req, res) => {
      res.send(this.generateStatusPage());
    });

    // API status JSON
    app.get('/api/status', (req, res) => {
      res.json(this.getDetailedStatus());
    });

    // API stats JSON
    app.get('/api/stats', (req, res) => {
      res.json({
        success: true,
        stats: { ...this.stats },
        queue: {
          total: this.queue.length,
          pending: this.queue.filter(i => i.status === 'pending').length,
          processing: this.queue.filter(i => i.status === 'processing').length,
          completed: this.queue.filter(i => i.status === 'completed').length,
          failed: this.queue.filter(i => i.status === 'failed').length
        },
        timestamp: new Date().toISOString()
      });
    });

    // Actions de contrôle
    app.post('/api/pause', (req, res) => {
      this.pauseProcessing();
      res.json({ success: true, message: 'Traitement mis en pause' });
    });

    app.post('/api/resume', (req, res) => {
      this.resumeProcessing();
      res.json({ success: true, message: 'Traitement repris' });
    });

    // 404 pour autres routes
    app.use('*', (req, res) => {
      res.status(404).json({
        success: false,
        error: 'Route non trouvée',
        mode: 'AUTO',
        message: 'Interface de monitoring en lecture seule'
      });
    });

    // Démarrage serveur
    return new Promise((resolve, reject) => {
      try {
        this.monitoringServer = app.listen(this.config.monitoringPort, '0.0.0.0', () => {
          logSh(`📊 Serveur monitoring démarré sur http://localhost:${this.config.monitoringPort}`, 'DEBUG');
          resolve();
        });

        this.monitoringServer.on('error', (error) => {
          reject(error);
        });

      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * Génère la page de status HTML
   */
  generateStatusPage() {
    const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000);
    const progress = this.stats.itemsQueued > 0 ?
      Math.round((this.stats.itemsProcessed / this.stats.itemsQueued) * 100) : 0;

    const pendingCount = this.queue.filter(i => i.status === 'pending').length;
    const completedCount = this.queue.filter(i => i.status === 'completed').length;
    const failedCount = this.queue.filter(i => i.status === 'failed').length;

    return `
    <!DOCTYPE html>
    <html>
    <head>
        <title>SEO Generator - Mode AUTO</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); min-height: 100vh; }
            .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
            .header { text-align: center; margin-bottom: 40px; }
            .header h1 { color: #2d3748; margin-bottom: 10px; }
            .mode-badge { background: #4299e1; color: white; padding: 8px 16px; border-radius: 20px; font-weight: bold; }
            .progress { background: #e2e8f0; height: 20px; border-radius: 10px; margin: 20px 0; overflow: hidden; }
            .progress-bar { background: linear-gradient(90deg, #4facfe, #00f2fe); height: 100%; width: ${progress}%; transition: width 0.3s; }
            .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 40px; }
            .stat-card { background: #f7fafc; padding: 20px; border-radius: 10px; text-align: center; border: 1px solid #e2e8f0; }
            .stat-card.processing { background: #fef5e7; border-color: #f6ad55; }
            .stat-card.completed { background: #f0fff4; border-color: #48bb78; }
            .stat-card.failed { background: #fed7d7; border-color: #f56565; }
            .stat-number { font-size: 2em; font-weight: bold; color: #2d3748; }
            .stat-label { color: #718096; margin-top: 5px; }
            .section { margin: 30px 0; padding: 25px; border: 1px solid #e2e8f0; border-radius: 10px; background: #f9f9f9; }
            .button { display: inline-block; padding: 12px 24px; margin: 8px; background: linear-gradient(135deg, #4facfe, #00f2fe); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; font-weight: 500; }
            .alert { padding: 15px; margin: 20px 0; border-radius: 8px; border-left: 4px solid; }
            .alert.info { background: #ebf8ff; border-color: #4299e1; color: #2a4365; }
            .current-item { background: #e6fffa; padding: 15px; border-radius: 8px; border: 1px solid #38b2ac; margin: 15px 0; }
        </style>
        <script>
            function refreshPage() { window.location.reload(); }
            function pauseProcessing() {
                fetch('/api/pause', { method: 'POST' })
                    .then(() => setTimeout(refreshPage, 1000));
            }
            function resumeProcessing() {
                fetch('/api/resume', { method: 'POST' })
                    .then(() => setTimeout(refreshPage, 1000));
            }
            setInterval(refreshPage, 30000); // Auto-refresh 30s
        </script>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>🤖 SEO Generator Server</h1>
                <span class="mode-badge">MODE AUTO - REFACTORISÉ</span>
                <p style="color: #718096; margin-top: 15px;">Traitement Automatique Google Sheets</p>
            </div>

            <div class="alert info">
                <strong>🤖 Mode AUTO Actif</strong><br>
                Traitement batch des Google Sheets • Interface monitoring lecture seule
            </div>

            <div class="progress">
                <div class="progress-bar"></div>
            </div>
            <div style="text-align: center; margin-bottom: 20px; color: #4a5568;">
                Progression: ${progress}% (${completedCount}/${this.stats.itemsQueued})
            </div>

            <div class="stats">
                <div class="stat-card">
                    <div class="stat-number">${uptime}s</div>
                    <div class="stat-label">Uptime</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${pendingCount}</div>
                    <div class="stat-label">En Attente</div>
                </div>
                <div class="stat-card processing">
                    <div class="stat-number">${this.currentRow ? '1' : '0'}</div>
                    <div class="stat-label">En Traitement</div>
                </div>
                <div class="stat-card completed">
                    <div class="stat-number">${completedCount}</div>
                    <div class="stat-label">Terminés</div>
                </div>
                <div class="stat-card failed">
                    <div class="stat-number">${failedCount}</div>
                    <div class="stat-label">Échecs</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${this.stats.averageProcessingTime}ms</div>
                    <div class="stat-label">Temps Moyen</div>
                </div>
            </div>

            ${this.currentRow ? `
            <div class="current-item">
                <strong>🎯 Traitement en cours:</strong><br>
                Ligne ${this.currentRow}<br>
            </div>
            ` : ''}

            <div class="section">
                <h2>🎛️ Contrôles</h2>
                ${this.isPaused ?
                    '<button class="button" onclick="resumeProcessing()">▶️ Reprendre</button>' :
                    '<button class="button" onclick="pauseProcessing()">⏸️ Pause</button>'
                }
                <button class="button" onclick="refreshPage()">🔄 Actualiser</button>
                <a href="/api/stats" target="_blank" class="button">📊 Stats JSON</a>
            </div>

            <div class="section">
                <h2>📋 Configuration AUTO</h2>
                <ul style="color: #4a5568; line-height: 1.6;">
                    <li><strong>Batch Size:</strong> ${this.config.batchSize} éléments</li>
                    <li><strong>Délai entre éléments:</strong> ${this.config.delayBetweenItems}ms</li>
                    <li><strong>Délai entre batches:</strong> ${this.config.delayBetweenBatches}ms</li>
                    <li><strong>Max Retries:</strong> ${this.config.maxRetries}</li>
                    <li><strong>Mode Selective:</strong> ${this.config.selective}</li>
                    <li><strong>Mode Adversarial:</strong> ${this.config.adversarial}</li>
                    <li><strong>Lignes:</strong> ${this.config.startRow} - ${this.config.endRow || '∞'}</li>
                </ul>
            </div>
        </div>
    </body>
    </html>
    `;
  }

  // ========================================
  // CONTRÔLES SPÉCIFIQUES
  // ========================================

  /**
   * Met en pause le traitement
   */
  pauseProcessing() {
    this.isPaused = true;
    logSh('⏸️ Traitement AutoProcessor mis en pause', 'INFO');
  }

  /**
   * Reprend le traitement
   */
  resumeProcessing() {
    this.isPaused = false;
    logSh('▶️ Traitement AutoProcessor repris', 'INFO');
  }

  /**
   * Attendre la fin du traitement actuel
   */
  async waitForCurrentProcessing(timeout = 30000) {
    const startWait = Date.now();

    while (this.currentRow && (Date.now() - startWait) < timeout) {
      await this.sleep(1000);
    }

    if (this.currentRow) {
      logSh('⚠️ Timeout attente fin traitement', 'WARNING');
    }
  }

  // ========================================
  // MONITORING ET HEALTH
  // ========================================

  /**
   * Démarre le monitoring de santé
   */
  startHealthMonitoring() {
    const HEALTH_INTERVAL = 60000; // 1 minute

    this.healthInterval = setInterval(() => {
      this.performHealthCheck();
    }, HEALTH_INTERVAL);

    logSh('💓 Health monitoring AutoProcessor démarré', 'DEBUG');
  }

  /**
   * Health check périodique
   */
  performHealthCheck() {
    const memUsage = process.memoryUsage();
    const queueStatus = {
      pending: this.queue.filter(i => i.status === 'pending').length,
      completed: this.queue.filter(i => i.status === 'completed').length,
      failed: this.queue.filter(i => i.status === 'failed').length
    };

    logSh(`💓 AutoProcessor Health - Queue: ${queueStatus.pending}P/${queueStatus.completed}C/${queueStatus.failed}F | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE');

    // Alertes
    if (memUsage.rss > 2 * 1024 * 1024 * 1024) { // > 2GB
      logSh('⚠️ Utilisation mémoire très élevée', 'WARNING');
    }

    if (this.stats.itemsFailed > this.stats.itemsProcessed * 0.5) {
      logSh('⚠️ Taux d\'échec élevé détecté', 'WARNING');
    }
  }

  /**
   * Retourne le status détaillé
   */
  getDetailedStatus() {
    const baseStatus = this.getStatus();
    return {
      success: true,
      mode: 'AUTO',
      isRunning: this.isRunning,
      state: {
        isRunning: this.isRunning,
        isPaused: this.isPaused,
        currentRow: this.currentRow,
        startTime: this.startTime,
        lastActivity: Date.now()
      },
      stats: {
        ...this.stats,
        uptime: Date.now() - this.stats.startTime
      },
      queue: {
        total: this.queue.length,
        pending: this.queue.filter(i => i.status === 'pending').length,
        processing: this.queue.filter(i => i.status === 'processing').length,
        completed: this.queue.filter(i => i.status === 'completed').length,
        failed: this.queue.filter(i => i.status === 'failed').length
      },
      config: { ...this.config },
      currentItem: this.currentRow ? {
        rowNumber: this.currentRow
      } : null,
      urls: {
        monitoring: `http://localhost:${this.config.monitoringPort}`,
        api: `http://localhost:${this.config.monitoringPort}/api/stats`
      },
      timestamp: new Date().toISOString()
    };
  }

  // ========================================
  // PERSISTANCE
  // ========================================

  /**
   * Sauvegarde la progression
   */
  async saveProgress() {
    try {
      const fs = require('fs').promises;
      const progressFile = path.join(__dirname, '../../auto-processor-progress.json');
      const progress = {
        processedRows: this.processedItems.map(item => item.rowNumber),
        failedRows: this.failedItems.map(item => ({
          rowNumber: item.rowNumber,
          error: item.error,
          attempts: item.attempts
        })),
        stats: { ...this.stats },
        lastSaved: Date.now(),
        timestamp: new Date().toISOString()
      };

      await fs.writeFile(progressFile, JSON.stringify(progress, null, 2));

    } catch (error) {
      logSh(`⚠️ Erreur sauvegarde progression: ${error.message}`, 'WARNING');
    }
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/pipeline/PipelineTemplates.js                           │
└────────────────────────────────────────────────────────────────────┘
*/

/**
 * PipelineTemplates.js
 *
 * Templates prédéfinis pour pipelines modulaires.
 * Fournit des configurations ready-to-use pour différents cas d'usage.
 */

/**
 * Templates de pipelines
 */
const TEMPLATES = {
  /**
   * Light & Fast - Pipeline minimal pour génération rapide
   */
  'light-fast': {
    name: 'Light & Fast',
    description: 'Pipeline rapide pour contenu basique, idéal pour tests et prototypes',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'lightEnhancement', intensity: 0.7 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['fast', 'light', 'basic'],
      estimatedDuration: '35s'
    }
  },

  /**
   * Standard SEO - Pipeline équilibré pour usage quotidien
   */
  'standard-seo': {
    name: 'Standard SEO',
    description: 'Pipeline équilibré avec protection anti-détection standard',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'standardEnhancement', intensity: 1.0 },
      { step: 3, module: 'adversarial', mode: 'light', intensity: 0.8, parameters: { detector: 'general', method: 'enhancement' } },
      { step: 4, module: 'human', mode: 'lightSimulation', intensity: 0.6 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['standard', 'seo', 'balanced'],
      estimatedDuration: '75s'
    }
  },

  /**
   * Premium SEO - Pipeline complet pour contenu premium
   */
  'premium-seo': {
    name: 'Premium SEO',
    description: 'Pipeline complet avec anti-détection avancée et qualité maximale',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'fullEnhancement', intensity: 1.0, saveCheckpoint: true },
      { step: 3, module: 'adversarial', mode: 'standard', intensity: 1.0, parameters: { detector: 'general', method: 'regeneration' } },
      { step: 4, module: 'human', mode: 'standardSimulation', intensity: 0.8, parameters: { fatigueLevel: 0.5, errorRate: 0.3 } },
      { step: 5, module: 'pattern', mode: 'standardPatternBreaking', intensity: 0.9 },
      { step: 6, module: 'adversarial', mode: 'light', intensity: 0.7, parameters: { detector: 'general', method: 'enhancement' } }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['premium', 'complete', 'quality'],
      estimatedDuration: '130s'
    }
  },

  /**
   * Heavy Guard - Protection maximale anti-détection
   */
  'heavy-guard': {
    name: 'Heavy Guard',
    description: 'Protection maximale avec multi-passes adversarial et human simulation',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'fullEnhancement', intensity: 1.0 },
      { step: 3, module: 'adversarial', mode: 'heavy', intensity: 1.2, parameters: { detector: 'gptZero', method: 'regeneration' }, saveCheckpoint: true },
      { step: 4, module: 'human', mode: 'heavySimulation', intensity: 1.0, parameters: { fatigueLevel: 0.7, errorRate: 0.4 } },
      { step: 5, module: 'pattern', mode: 'heavyPatternBreaking', intensity: 1.0 },
      { step: 6, module: 'adversarial', mode: 'adaptive', intensity: 1.5, parameters: { detector: 'originality', method: 'hybrid' } },
      { step: 7, module: 'human', mode: 'personalityFocus', intensity: 1.3 },
      { step: 8, module: 'pattern', mode: 'syntaxFocus', intensity: 1.1 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['heavy', 'protection', 'anti-detection'],
      estimatedDuration: '180s'
    }
  },

  /**
   * Personality Focus - Mise en avant de la personnalité
   */
  'personality-focus': {
    name: 'Personality Focus',
    description: 'Pipeline optimisé pour un style personnel marqué',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'personalityFocus', intensity: 1.2 },
      { step: 3, module: 'human', mode: 'personalityFocus', intensity: 1.5 },
      { step: 4, module: 'adversarial', mode: 'light', intensity: 0.6, parameters: { detector: 'general', method: 'enhancement' } }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['personality', 'style', 'unique'],
      estimatedDuration: '70s'
    }
  },

  /**
   * Fluidity Master - Transitions et fluidité maximale
   */
  'fluidity-master': {
    name: 'Fluidity Master',
    description: 'Pipeline axé sur transitions fluides et connecteurs naturels',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'fluidityFocus', intensity: 1.3 },
      { step: 3, module: 'pattern', mode: 'connectorsFocus', intensity: 1.2 },
      { step: 4, module: 'human', mode: 'standardSimulation', intensity: 0.7 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['fluidity', 'transitions', 'natural'],
      estimatedDuration: '73s'
    }
  },

  /**
   * Adaptive Smart - Pipeline intelligent avec modes adaptatifs
   */
  'adaptive-smart': {
    name: 'Adaptive Smart',
    description: 'Pipeline intelligent qui s\'adapte au contenu',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'adaptive', intensity: 1.0 },
      { step: 3, module: 'adversarial', mode: 'adaptive', intensity: 1.0, parameters: { detector: 'general', method: 'hybrid' } },
      { step: 4, module: 'human', mode: 'adaptiveSimulation', intensity: 1.0 },
      { step: 5, module: 'pattern', mode: 'adaptivePatternBreaking', intensity: 1.0 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['adaptive', 'smart', 'intelligent'],
      estimatedDuration: '105s'
    }
  },

  /**
   * GPTZero Killer - Spécialisé anti-GPTZero
   */
  'gptzero-killer': {
    name: 'GPTZero Killer',
    description: 'Pipeline optimisé pour contourner GPTZero spécifiquement',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'fullEnhancement', intensity: 1.0 },
      { step: 3, module: 'adversarial', mode: 'heavy', intensity: 1.5, parameters: { detector: 'gptZero', method: 'regeneration' } },
      { step: 4, module: 'human', mode: 'heavySimulation', intensity: 1.2 },
      { step: 5, module: 'pattern', mode: 'heavyPatternBreaking', intensity: 1.1 },
      { step: 6, module: 'adversarial', mode: 'standard', intensity: 1.0, parameters: { detector: 'gptZero', method: 'hybrid' } }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['gptzero', 'anti-detection', 'specialized'],
      estimatedDuration: '155s'
    }
  },

  /**
   * Originality Bypass - Spécialisé anti-Originality.ai
   */
  'originality-bypass': {
    name: 'Originality Bypass',
    description: 'Pipeline optimisé pour contourner Originality.ai',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 },
      { step: 2, module: 'selective', mode: 'fullEnhancement', intensity: 1.0 },
      { step: 3, module: 'adversarial', mode: 'heavy', intensity: 1.4, parameters: { detector: 'originality', method: 'regeneration' } },
      { step: 4, module: 'human', mode: 'temporalFocus', intensity: 1.1 },
      { step: 5, module: 'pattern', mode: 'syntaxFocus', intensity: 1.2 },
      { step: 6, module: 'adversarial', mode: 'adaptive', intensity: 1.3, parameters: { detector: 'originality', method: 'hybrid' } }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['originality', 'anti-detection', 'specialized'],
      estimatedDuration: '160s'
    }
  },

  /**
   * Minimal Test - Pipeline minimal pour tests rapides
   */
  'minimal-test': {
    name: 'Minimal Test',
    description: 'Pipeline minimal pour tests de connectivité et validation',
    pipeline: [
      { step: 1, module: 'generation', mode: 'simple', intensity: 1.0 }
    ],
    metadata: {
      author: 'system',
      created: '2025-10-08',
      version: '1.0',
      tags: ['test', 'minimal', 'debug'],
      estimatedDuration: '15s'
    }
  }
};

/**
 * Catégories de templates
 */
const CATEGORIES = {
  basic: ['minimal-test', 'light-fast'],
  standard: ['standard-seo', 'premium-seo'],
  advanced: ['heavy-guard', 'adaptive-smart'],
  specialized: ['gptzero-killer', 'originality-bypass'],
  focus: ['personality-focus', 'fluidity-master']
};

/**
 * Obtenir un template par nom
 */
function getTemplate(name) {
  return TEMPLATES[name] || null;
}

/**
 * Lister tous les templates
 */
function listTemplates() {
  return Object.entries(TEMPLATES).map(([key, template]) => ({
    id: key,
    name: template.name,
    description: template.description,
    steps: template.pipeline.length,
    tags: template.metadata.tags,
    estimatedDuration: template.metadata.estimatedDuration
  }));
}

/**
 * Lister templates par catégorie
 */
function listTemplatesByCategory(category) {
  const templateIds = CATEGORIES[category] || [];
  return templateIds.map(id => ({
    id,
    ...TEMPLATES[id]
  }));
}

/**
 * Obtenir toutes les catégories
 */
function getCategories() {
  return Object.entries(CATEGORIES).map(([name, templateIds]) => ({
    name,
    count: templateIds.length,
    templates: templateIds
  }));
}

/**
 * Rechercher templates par tag
 */
function searchByTag(tag) {
  return Object.entries(TEMPLATES)
    .filter(([_, template]) => template.metadata.tags.includes(tag))
    .map(([id, template]) => ({ id, ...template }));
}

module.exports = {
  TEMPLATES,
  CATEGORIES,
  getTemplate,
  listTemplates,
  listTemplatesByCategory,
  getCategories,
  searchByTag
};


/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/modes/ManualServer.js                                   │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// FICHIER: ManualServer.js
// RESPONSABILITÉ: Mode MANUAL - Interface Client + API + WebSocket
// FONCTIONNALITÉS: Dashboard, tests modulaires, API complète
// ========================================

const express = require('express');
const cors = require('cors');
const path = require('path');
const WebSocket = require('ws');

const { logSh } = require('../ErrorReporting');
const { handleModularWorkflow, benchmarkStacks } = require('../Main');
const { APIController } = require('../APIController');
const { BatchController } = require('../batch/BatchController');

/**
 * SERVEUR MODE MANUAL
 * Interface client complète avec API, WebSocket et dashboard
 */
class ManualServer {
  
  constructor(options = {}) {
    this.config = {
      port: options.port || process.env.MANUAL_PORT || 3000,
      wsPort: options.wsPort || process.env.WS_PORT || 8081,
      host: options.host || '0.0.0.0',
      ...options
    };
    
    this.app = null;
    this.server = null;
    this.wsServer = null;
    this.activeClients = new Set();
    this.stats = {
      sessions: 0,
      requests: 0,
      testsExecuted: 0,
      startTime: Date.now(),
      lastActivity: null
    };

    this.isRunning = false;
    this.apiController = new APIController();
    this.batchController = new BatchController();
  }

  // ========================================
  // DÉMARRAGE ET ARRÊT
  // ========================================
  
  /**
   * Démarre le serveur MANUAL complet
   */
  async start() {
    if (this.isRunning) {
      logSh('⚠️ ManualServer déjà en cours d\'exécution', 'WARNING');
      return;
    }
    
    logSh('🎯 Démarrage ManualServer...', 'INFO');
    
    try {
      // 1. Configuration Express
      await this.setupExpressApp();
      
      // 2. Routes API
      this.setupAPIRoutes();
      
      // 3. Interface Web
      this.setupWebInterface();
      
      // 4. WebSocket pour logs temps réel
      await this.setupWebSocketServer();
      
      // 5. Démarrage serveur HTTP
      await this.startHTTPServer();
      
      // 6. Monitoring
      this.startMonitoring();
      
      this.isRunning = true;
      this.stats.startTime = Date.now();
      
      logSh(`✅ ManualServer démarré sur http://localhost:${this.config.port}`, 'INFO');
      logSh(`📡 WebSocket logs sur ws://localhost:${this.config.wsPort}`, 'INFO');
      
    } catch (error) {
      logSh(`❌ Erreur démarrage ManualServer: ${error.message}`, 'ERROR');
      await this.stop();
      throw error;
    }
  }

  /**
   * Arrête le serveur MANUAL
   */
  async stop() {
    if (!this.isRunning) return;
    
    logSh('🛑 Arrêt ManualServer...', 'INFO');
    
    try {
      // Déconnecter tous les clients WebSocket
      this.disconnectAllClients();
      
      // Arrêter WebSocket server
      if (this.wsServer) {
        this.wsServer.close();
        this.wsServer = null;
      }
      
      // Arrêter serveur HTTP
      if (this.server) {
        await new Promise((resolve) => {
          this.server.close(() => resolve());
        });
        this.server = null;
      }
      
      this.isRunning = false;
      
      logSh('✅ ManualServer arrêté', 'INFO');
      
    } catch (error) {
      logSh(`⚠️ Erreur arrêt ManualServer: ${error.message}`, 'WARNING');
    }
  }

  // ========================================
  // CONFIGURATION EXPRESS
  // ========================================
  
  /**
   * Configure l'application Express
   */
  async setupExpressApp() {
    this.app = express();
    
    // Middleware de base
    this.app.use(express.json({ limit: '10mb' }));
    this.app.use(express.urlencoded({ extended: true }));
    this.app.use(cors());
    
    // Middleware de logs des requêtes
    this.app.use((req, res, next) => {
      this.stats.requests++;
      this.stats.lastActivity = Date.now();
      
      logSh(`📥 ${req.method} ${req.path} - ${req.ip}`, 'TRACE');
      next();
    });
    
    // Fichiers statiques
    this.app.use(express.static(path.join(__dirname, '../../public')));
    
    // Route spécifique pour l'interface step-by-step
    this.app.get('/step-by-step', (req, res) => {
      res.sendFile(path.join(__dirname, '../../public/step-by-step.html'));
    });
    
    logSh('⚙️ Express configuré', 'DEBUG');
  }

  /**
   * Configure les routes API
   */
  setupAPIRoutes() {
    // Route de status
    this.app.get('/api/status', (req, res) => {
      res.json({
        success: true,
        mode: 'MANUAL',
        status: 'running',
        uptime: Date.now() - this.stats.startTime,
        stats: { ...this.stats },
        clients: this.activeClients.size,
        timestamp: new Date().toISOString()
      });
    });

    // Test modulaire individuel
    this.app.post('/api/test-modulaire', async (req, res) => {
      await this.handleTestModulaire(req, res);
    });

    // 🆕 Workflow modulaire avec sauvegarde par étapes
    this.app.post('/api/workflow-modulaire', async (req, res) => {
      await this.handleWorkflowModulaire(req, res);
    });

    // Benchmark modulaire complet
    this.app.post('/api/benchmark-modulaire', async (req, res) => {
      await this.handleBenchmarkModulaire(req, res);
    });

    // Configuration modulaire disponible
    this.app.get('/api/modulaire-config', (req, res) => {
      this.handleModulaireConfig(req, res);
    });

    // Stats détaillées
    this.app.get('/api/stats', (req, res) => {
      res.json({
        success: true,
        stats: {
          ...this.stats,
          uptime: Date.now() - this.stats.startTime,
          activeClients: this.activeClients.size,
          memory: process.memoryUsage(),
          timestamp: new Date().toISOString()
        }
      });
    });

    // Lancer le log viewer avec WebSocket
    this.app.post('/api/start-log-viewer', (req, res) => {
      this.handleStartLogViewer(req, res);
    });

    // ========================================
    // APIs STEP-BY-STEP
    // ========================================
    
    // Initialiser une session step-by-step
    this.app.post('/api/step-by-step/init', async (req, res) => {
      await this.handleStepByStepInit(req, res);
    });
    
    // Exécuter une étape
    this.app.post('/api/step-by-step/execute', async (req, res) => {
      await this.handleStepByStepExecute(req, res);
    });
    
    // Status d'une session
    this.app.get('/api/step-by-step/status/:sessionId', (req, res) => {
      this.handleStepByStepStatus(req, res);
    });
    
    // Reset une session
    this.app.post('/api/step-by-step/reset', (req, res) => {
      this.handleStepByStepReset(req, res);
    });
    
    // Export résultats
    this.app.get('/api/step-by-step/export/:sessionId', (req, res) => {
      this.handleStepByStepExport(req, res);
    });
    
    // Liste des sessions actives
    this.app.get('/api/step-by-step/sessions', (req, res) => {
      this.handleStepByStepSessions(req, res);
    });
    
    // API pour récupérer les personnalités
    this.app.get('/api/personalities', async (req, res) => {
      await this.handleGetPersonalities(req, res);
    });

    // 🆕 API simple pour générer un article avec mot-clé
    this.app.post('/api/generate-simple', async (req, res) => {
      await this.handleGenerateSimple(req, res);
    });

    // ========================================
    // ENDPOINTS GESTION CONFIGURATIONS
    // ========================================

    // Sauvegarder une configuration
    this.app.post('/api/config/save', async (req, res) => {
      try {
        const { name, config } = req.body;

        if (!name || !config) {
          return res.status(400).json({
            success: false,
            error: 'Nom et configuration requis'
          });
        }

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const result = await configManager.saveConfig(name, config);

        res.json({
          success: true,
          message: `Configuration "${name}" sauvegardée`,
          savedName: result.name
        });

      } catch (error) {
        logSh(`❌ Erreur save config: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Lister les configurations
    this.app.get('/api/config/list', async (req, res) => {
      try {
        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const configs = await configManager.listConfigs();

        res.json({
          success: true,
          configs,
          count: configs.length
        });

      } catch (error) {
        logSh(`❌ Erreur list configs: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Charger une configuration
    this.app.get('/api/config/:name', async (req, res) => {
      try {
        const { name } = req.params;

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const configData = await configManager.loadConfig(name);

        res.json({
          success: true,
          config: configData
        });

      } catch (error) {
        logSh(`❌ Erreur load config: ${error.message}`, 'ERROR');
        res.status(404).json({
          success: false,
          error: error.message
        });
      }
    });

    // Supprimer une configuration
    this.app.delete('/api/config/:name', async (req, res) => {
      try {
        const { name } = req.params;

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        await configManager.deleteConfig(name);

        res.json({
          success: true,
          message: `Configuration "${name}" supprimée`
        });

      } catch (error) {
        logSh(`❌ Erreur delete config: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // ========================================
    // ENDPOINTS PIPELINE MANAGEMENT
    // ========================================

    // Sauvegarder un pipeline
    this.app.post('/api/pipeline/save', async (req, res) => {
      try {
        const { pipelineDefinition } = req.body;

        if (!pipelineDefinition) {
          return res.status(400).json({
            success: false,
            error: 'pipelineDefinition requis'
          });
        }

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const result = await configManager.savePipeline(pipelineDefinition);

        res.json({
          success: true,
          message: `Pipeline "${pipelineDefinition.name}" sauvegardé`,
          savedName: result.name
        });

      } catch (error) {
        logSh(`❌ Erreur save pipeline: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Lister les pipelines
    this.app.get('/api/pipeline/list', async (req, res) => {
      try {
        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const pipelines = await configManager.listPipelines();

        res.json({
          success: true,
          pipelines,
          count: pipelines.length
        });

      } catch (error) {
        logSh(`❌ Erreur list pipelines: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Charger un pipeline
    this.app.get('/api/pipeline/:name', async (req, res) => {
      try {
        const { name } = req.params;

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        const pipeline = await configManager.loadPipeline(name);

        res.json({
          success: true,
          pipeline
        });

      } catch (error) {
        logSh(`❌ Erreur load pipeline: ${error.message}`, 'ERROR');
        res.status(404).json({
          success: false,
          error: error.message
        });
      }
    });

    // Supprimer un pipeline
    this.app.delete('/api/pipeline/:name', async (req, res) => {
      try {
        const { name } = req.params;

        const { ConfigManager } = require('../ConfigManager');
        const configManager = new ConfigManager();

        await configManager.deletePipeline(name);

        res.json({
          success: true,
          message: `Pipeline "${name}" supprimé`
        });

      } catch (error) {
        logSh(`❌ Erreur delete pipeline: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Exécuter un pipeline
    this.app.post('/api/pipeline/execute', async (req, res) => {
      try {
        const { pipelineConfig, rowNumber } = req.body;

        if (!pipelineConfig) {
          return res.status(400).json({
            success: false,
            error: 'pipelineConfig requis'
          });
        }

        if (!rowNumber || rowNumber < 2) {
          return res.status(400).json({
            success: false,
            error: 'rowNumber requis (minimum 2)'
          });
        }

        logSh(`🚀 Exécution pipeline: ${pipelineConfig.name} (row ${rowNumber})`, 'INFO');

        const { handleFullWorkflow } = require('../Main');

        const result = await handleFullWorkflow({
          pipelineConfig,
          rowNumber,
          source: 'pipeline_api'
        });

        res.json({
          success: true,
          result: {
            finalContent: result.finalContent,
            executionLog: result.executionLog,
            stats: result.stats
          }
        });

      } catch (error) {
        logSh(`❌ Erreur execute pipeline: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Obtenir templates prédéfinis
    this.app.get('/api/pipeline/templates', async (req, res) => {
      try {
        const { listTemplates, getCategories } = require('../pipeline/PipelineTemplates');

        const templates = listTemplates();
        const categories = getCategories();

        res.json({
          success: true,
          templates,
          categories
        });

      } catch (error) {
        logSh(`❌ Erreur get templates: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Obtenir template par nom
    this.app.get('/api/pipeline/templates/:name', async (req, res) => {
      try {
        const { name } = req.params;
        const { getTemplate } = require('../pipeline/PipelineTemplates');

        const template = getTemplate(name);

        if (!template) {
          return res.status(404).json({
            success: false,
            error: `Template "${name}" non trouvé`
          });
        }

        res.json({
          success: true,
          template
        });

      } catch (error) {
        logSh(`❌ Erreur get template: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Obtenir modules disponibles
    this.app.get('/api/pipeline/modules', async (req, res) => {
      try {
        const { PipelineDefinition } = require('../pipeline/PipelineDefinition');

        const modules = PipelineDefinition.listModules();

        res.json({
          success: true,
          modules
        });

      } catch (error) {
        logSh(`❌ Erreur get modules: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Valider un pipeline
    this.app.post('/api/pipeline/validate', async (req, res) => {
      try {
        const { pipelineDefinition } = req.body;

        if (!pipelineDefinition) {
          return res.status(400).json({
            success: false,
            error: 'pipelineDefinition requis'
          });
        }

        const { PipelineDefinition } = require('../pipeline/PipelineDefinition');

        const validation = PipelineDefinition.validate(pipelineDefinition);

        res.json({
          success: validation.valid,
          valid: validation.valid,
          errors: validation.errors
        });

      } catch (error) {
        logSh(`❌ Erreur validate pipeline: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // Estimer durée/coût d'un pipeline
    this.app.post('/api/pipeline/estimate', async (req, res) => {
      try {
        const { pipelineDefinition } = req.body;

        if (!pipelineDefinition) {
          return res.status(400).json({
            success: false,
            error: 'pipelineDefinition requis'
          });
        }

        const { PipelineDefinition } = require('../pipeline/PipelineDefinition');

        const summary = PipelineDefinition.getSummary(pipelineDefinition);
        const duration = PipelineDefinition.estimateDuration(pipelineDefinition);

        res.json({
          success: true,
          estimate: {
            totalSteps: summary.totalSteps,
            summary: summary.summary,
            estimatedDuration: duration.formatted,
            estimatedSeconds: duration.seconds
          }
        });

      } catch (error) {
        logSh(`❌ Erreur estimate pipeline: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // ========================================
    // ENDPOINT PRODUCTION RUN
    // ========================================

    this.app.post('/api/production-run', async (req, res) => {
      try {
        const {
          rowNumber,
          selectiveStack,
          adversarialMode,
          humanSimulationMode,
          patternBreakingMode,
          saveIntermediateSteps = true
        } = req.body;

        if (!rowNumber) {
          return res.status(400).json({
            success: false,
            error: 'rowNumber requis'
          });
        }

        logSh(`🚀 PRODUCTION RUN: Row ${rowNumber}`, 'INFO');

        // Appel handleFullWorkflow depuis Main.js
        const { handleFullWorkflow } = require('../Main');

        const result = await handleFullWorkflow({
          rowNumber,
          selectiveStack: selectiveStack || 'standardEnhancement',
          adversarialMode: adversarialMode || 'light',
          humanSimulationMode: humanSimulationMode || 'none',
          patternBreakingMode: patternBreakingMode || 'none',
          saveIntermediateSteps,
          source: 'production_web'
        });

        res.json({
          success: true,
          result: {
            wordCount: result.compiledWordCount,
            duration: result.totalDuration,
            llmUsed: result.llmUsed,
            cost: result.estimatedCost,
            slug: result.slug,
            gsheetsLink: `https://docs.google.com/spreadsheets/d/${process.env.GOOGLE_SHEETS_ID}`
          }
        });

      } catch (error) {
        logSh(`❌ Erreur production run: ${error.message}`, 'ERROR');
        res.status(500).json({
          success: false,
          error: error.message
        });
      }
    });

    // ========================================
    // 🚀 NOUVEAUX ENDPOINTS API RESTful
    // ========================================

    // === GESTION ARTICLES ===
    this.app.get('/api/articles', async (req, res) => {
      await this.apiController.getArticles(req, res);
    });

    this.app.get('/api/articles/:id', async (req, res) => {
      await this.apiController.getArticle(req, res);
    });

    this.app.post('/api/articles', async (req, res) => {
      await this.apiController.createArticle(req, res);
    });

    // ========================================
    // 🎯 BATCH PROCESSING API ENDPOINTS
    // ========================================

    // Configuration batch
    this.app.get('/api/batch/config', async (req, res) => {
      await this.batchController.getConfig(req, res);
    });

    this.app.post('/api/batch/config', async (req, res) => {
      await this.batchController.saveConfig(req, res);
    });

    // Contrôle traitement batch
    this.app.post('/api/batch/start', async (req, res) => {
      await this.batchController.startBatch(req, res);
    });

    this.app.post('/api/batch/stop', async (req, res) => {
      await this.batchController.stopBatch(req, res);
    });

    this.app.post('/api/batch/pause', async (req, res) => {
      await this.batchController.pauseBatch(req, res);
    });

    this.app.post('/api/batch/resume', async (req, res) => {
      await this.batchController.resumeBatch(req, res);
    });

    // Monitoring batch
    this.app.get('/api/batch/status', async (req, res) => {
      await this.batchController.getStatus(req, res);
    });

    this.app.get('/api/batch/progress', async (req, res) => {
      await this.batchController.getProgress(req, res);
    });

    // Templates Digital Ocean
    this.app.get('/api/batch/templates', async (req, res) => {
      await this.batchController.getTemplates(req, res);
    });

    this.app.get('/api/batch/templates/:filename', async (req, res) => {
      await this.batchController.getTemplate(req, res);
    });

    this.app.delete('/api/batch/cache', async (req, res) => {
      await this.batchController.clearCache(req, res);
    });

    // === GESTION PROJETS ===
    this.app.get('/api/projects', async (req, res) => {
      await this.apiController.getProjects(req, res);
    });

    this.app.post('/api/projects', async (req, res) => {
      await this.apiController.createProject(req, res);
    });

    // === GESTION TEMPLATES ===
    this.app.get('/api/templates', async (req, res) => {
      await this.apiController.getTemplates(req, res);
    });

    this.app.post('/api/templates', async (req, res) => {
      await this.apiController.createTemplate(req, res);
    });

    // === CONFIGURATION ===
    this.app.get('/api/config/personalities', async (req, res) => {
      await this.apiController.getPersonalitiesConfig(req, res);
    });

    // === MONITORING ===
    this.app.get('/api/health', async (req, res) => {
      await this.apiController.getHealth(req, res);
    });

    this.app.get('/api/metrics', async (req, res) => {
      await this.apiController.getMetrics(req, res);
    });

    // === PROMPT ENGINE API ===
    this.app.post('/api/generate-prompt', async (req, res) => {
      await this.apiController.generatePrompt(req, res);
    });
    this.app.get('/api/trends', async (req, res) => {
      await this.apiController.getTrends(req, res);
    });
    this.app.post('/api/trends/:trendId', async (req, res) => {
      await this.apiController.setTrend(req, res);
    });
    this.app.get('/api/prompt-engine/status', async (req, res) => {
      await this.apiController.getPromptEngineStatus(req, res);
    });

    // === WORKFLOW CONFIGURATION API ===
    this.app.get('/api/workflow/sequences', async (req, res) => {
      await this.apiController.getWorkflowSequences(req, res);
    });
    this.app.post('/api/workflow/sequences', async (req, res) => {
      await this.apiController.createWorkflowSequence(req, res);
    });
    this.app.post('/api/workflow/execute', async (req, res) => {
      await this.apiController.executeConfigurableWorkflow(req, res);
    });

    // Gestion d'erreurs API
    this.app.use('/api/*', (error, req, res, next) => {
      logSh(`❌ Erreur API ${req.path}: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur serveur interne',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    });

    logSh('🛠️ Routes API configurées', 'DEBUG');
  }

  // ========================================
  // HANDLERS API
  // ========================================
  
  /**
   * Gère les tests modulaires individuels
   */
  async handleTestModulaire(req, res) {
    try {
      const config = req.body;
      this.stats.testsExecuted++;
      
      logSh(`🧪 Test modulaire: ${config.selectiveStack} + ${config.adversarialMode} + ${config.humanSimulationMode} + ${config.patternBreakingMode}`, 'INFO');
      
      // Validation des paramètres
      if (!config.rowNumber || config.rowNumber < 2) {
        return res.status(400).json({
          success: false,
          error: 'Numéro de ligne invalide (minimum 2)'
        });
      }

      // Exécution du test
      const result = await handleModularWorkflow({
        ...config,
        source: 'manual_server_api'
      });
      
      logSh(`✅ Test modulaire terminé: ${result.stats.totalDuration}ms`, 'INFO');
      
      res.json({
        success: true,
        message: 'Test modulaire terminé avec succès',
        stats: result.stats,
        config: config,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur test modulaire: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: error.message,
        config: req.body,
        timestamp: new Date().toISOString()
      });
    }
  }

  /**
   * Gère les benchmarks modulaires
   */
  async handleBenchmarkModulaire(req, res) {
    try {
      const { rowNumber = 2 } = req.body;
      
      logSh(`📊 Benchmark modulaire ligne ${rowNumber}...`, 'INFO');
      
      if (rowNumber < 2) {
        return res.status(400).json({
          success: false,
          error: 'Numéro de ligne invalide (minimum 2)'
        });
      }

      const benchResults = await benchmarkStacks(rowNumber);
      
      const successfulTests = benchResults.filter(r => r.success);
      const avgDuration = successfulTests.length > 0 ? 
        successfulTests.reduce((sum, r) => sum + r.duration, 0) / successfulTests.length : 0;
      
      this.stats.testsExecuted += benchResults.length;
      
      logSh(`📊 Benchmark terminé: ${successfulTests.length}/${benchResults.length} tests réussis`, 'INFO');
      
      res.json({
        success: true,
        message: `Benchmark terminé: ${successfulTests.length}/${benchResults.length} tests réussis`,
        summary: {
          totalTests: benchResults.length,
          successfulTests: successfulTests.length,
          failedTests: benchResults.length - successfulTests.length,
          averageDuration: Math.round(avgDuration),
          rowNumber: rowNumber
        },
        results: benchResults,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur benchmark modulaire: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  /**
   * 🆕 Gère les workflows modulaires avec sauvegarde par étapes
   */
  async handleWorkflowModulaire(req, res) {
    try {
      const config = req.body;
      this.stats.testsExecuted++;
      
      // Configuration par défaut avec sauvegarde activée
      const workflowConfig = {
        rowNumber: config.rowNumber || 2,
        selectiveStack: config.selectiveStack || 'standardEnhancement',
        adversarialMode: config.adversarialMode || 'light',
        humanSimulationMode: config.humanSimulationMode || 'none',
        patternBreakingMode: config.patternBreakingMode || 'none',
        saveIntermediateSteps: config.saveIntermediateSteps !== false, // Par défaut true
        source: 'api_manual_server'
      };
      
      logSh(`🔗 Workflow modulaire avec étapes: ligne ${workflowConfig.rowNumber}`, 'INFO');
      logSh(`   📋 Config: ${workflowConfig.selectiveStack} + ${workflowConfig.adversarialMode} + ${workflowConfig.humanSimulationMode} + ${workflowConfig.patternBreakingMode}`, 'DEBUG');
      logSh(`   💾 Sauvegarde étapes: ${workflowConfig.saveIntermediateSteps ? 'ACTIVÉE' : 'DÉSACTIVÉE'}`, 'INFO');
      
      // Validation des paramètres
      if (workflowConfig.rowNumber < 2) {
        return res.status(400).json({
          success: false,
          error: 'Numéro de ligne invalide (minimum 2)'
        });
      }

      // Exécution du workflow complet
      const startTime = Date.now();
      const result = await handleModularWorkflow(workflowConfig);
      const duration = Date.now() - startTime;
      
      // Statistiques finales
      const finalStats = {
        duration,
        success: result.success,
        versionsCreated: result.stats?.versionHistory?.length || 1,
        parentArticleId: result.stats?.parentArticleId,
        finalArticleId: result.storageResult?.articleId,
        totalModifications: {
          selective: result.stats?.selectiveEnhancements || 0,
          adversarial: result.stats?.adversarialModifications || 0,
          human: result.stats?.humanSimulationModifications || 0,
          pattern: result.stats?.patternBreakingModifications || 0
        },
        finalLength: result.stats?.finalLength || 0
      };
      
      logSh(`✅ Workflow modulaire terminé: ${finalStats.versionsCreated} versions créées en ${duration}ms`, 'INFO');
      
      res.json({
        success: true,
        message: `Workflow modulaire terminé avec succès (${finalStats.versionsCreated} versions sauvegardées)`,
        config: workflowConfig,
        stats: finalStats,
        versionHistory: result.stats?.versionHistory,
        result: {
          parentArticleId: finalStats.parentArticleId,
          finalArticleId: finalStats.finalArticleId,
          duration: finalStats.duration,
          modificationsCount: Object.values(finalStats.totalModifications).reduce((sum, val) => sum + val, 0),
          finalWordCount: result.storageResult?.wordCount,
          personality: result.stats?.personality
        },
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur workflow modulaire: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  /**
   * Retourne la configuration modulaire
   */
  handleModulaireConfig(req, res) {
    try {
      const config = {
        selectiveStacks: [
          { value: 'lightEnhancement', name: 'Light Enhancement', description: 'Améliorations légères' },
          { value: 'standardEnhancement', name: 'Standard Enhancement', description: 'Améliorations standard' },
          { value: 'fullEnhancement', name: 'Full Enhancement', description: 'Améliorations complètes' },
          { value: 'personalityFocus', name: 'Personality Focus', description: 'Focus personnalité' },
          { value: 'fluidityFocus', name: 'Fluidity Focus', description: 'Focus fluidité' },
          { value: 'adaptive', name: 'Adaptive', description: 'Adaptation automatique' }
        ],
        adversarialModes: [
          { value: 'none', name: 'None', description: 'Aucune technique adversariale' },
          { value: 'light', name: 'Light', description: 'Techniques adversariales légères' },
          { value: 'standard', name: 'Standard', description: 'Techniques adversariales standard' },
          { value: 'heavy', name: 'Heavy', description: 'Techniques adversariales intensives' },
          { value: 'adaptive', name: 'Adaptive', description: 'Adaptation automatique' }
        ],
        humanSimulationModes: [
          { value: 'none', name: 'None', description: 'Aucune simulation humaine' },
          { value: 'lightSimulation', name: 'Light Simulation', description: 'Simulation légère' },
          { value: 'standardSimulation', name: 'Standard Simulation', description: 'Simulation standard' },
          { value: 'heavySimulation', name: 'Heavy Simulation', description: 'Simulation intensive' },
          { value: 'adaptiveSimulation', name: 'Adaptive Simulation', description: 'Simulation adaptative' },
          { value: 'personalityFocus', name: 'Personality Focus', description: 'Focus personnalité' },
          { value: 'temporalFocus', name: 'Temporal Focus', description: 'Focus temporel' }
        ],
        patternBreakingModes: [
          { value: 'none', name: 'None', description: 'Aucun pattern breaking' },
          { value: 'lightPatternBreaking', name: 'Light Pattern Breaking', description: 'Pattern breaking léger' },
          { value: 'standardPatternBreaking', name: 'Standard Pattern Breaking', description: 'Pattern breaking standard' },
          { value: 'heavyPatternBreaking', name: 'Heavy Pattern Breaking', description: 'Pattern breaking intensif' },
          { value: 'adaptivePatternBreaking', name: 'Adaptive Pattern Breaking', description: 'Pattern breaking adaptatif' },
          { value: 'syntaxFocus', name: 'Syntax Focus', description: 'Focus syntaxe uniquement' },
          { value: 'connectorsFocus', name: 'Connectors Focus', description: 'Focus connecteurs uniquement' }
        ]
      };
      
      res.json({
        success: true,
        config: config,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur config modulaire: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Lance le log viewer avec WebSocket
   */
  handleStartLogViewer(req, res) {
    try {
      const { spawn } = require('child_process');
      const path = require('path');
      const os = require('os');

      // Démarrer le WebSocket pour logs
      process.env.ENABLE_LOG_WS = 'true';
      const { initWebSocketServer } = require('../ErrorReporting');
      initWebSocketServer();

      // Servir le log viewer via une route HTTP au lieu d'un fichier local
      const logViewerUrl = `http://localhost:${this.config.port}/logs-viewer.html`;
      
      // Ouvrir dans le navigateur selon l'OS
      let command, args;
      switch (os.platform()) {
        case 'darwin': // macOS
          command = 'open';
          args = [logViewerUrl];
          break;
        case 'win32': // Windows
          command = 'cmd';
          args = ['/c', 'start', logViewerUrl];
          break;
        default: // Linux et WSL
          // Pour WSL, utiliser explorer.exe de Windows
          if (process.env.WSL_DISTRO_NAME) {
            command = '/mnt/c/Windows/System32/cmd.exe';
            args = ['/c', 'start', logViewerUrl];
          } else {
            command = 'xdg-open';
            args = [logViewerUrl];
          }
          break;
      }
      
      spawn(command, args, { detached: true, stdio: 'ignore' });
      
      const logPort = process.env.LOG_WS_PORT || 8082;
      logSh(`🌐 Log viewer lancé avec WebSocket sur port ${logPort}`, 'INFO');
      
      res.json({
        success: true,
        message: 'Log viewer lancé',
        wsPort: logPort,
        viewerUrl: logViewerUrl,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur lancement log viewer: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur lancement log viewer',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  // ========================================
  // HANDLERS STEP-BY-STEP
  // ========================================
  
  /**
   * Initialise une nouvelle session step-by-step
   */
  async handleStepByStepInit(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      
      const inputData = req.body;
      logSh(`🎯 Initialisation session step-by-step`, 'INFO');
      logSh(`   Input: ${JSON.stringify(inputData)}`, 'DEBUG');
      
      const session = sessionManager.createSession(inputData);
      
      res.json({
        success: true,
        sessionId: session.id,
        steps: session.steps.map(step => ({
          id: step.id,
          system: step.system,
          name: step.name,
          description: step.description,
          status: step.status
        })),
        inputData: session.inputData,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur init step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur initialisation session',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Exécute une étape
   */
  async handleStepByStepExecute(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      const { StepExecutor } = require('../StepExecutor');
      
      const { sessionId, stepId, options = {} } = req.body;
      
      if (!sessionId || !stepId) {
        return res.status(400).json({
          success: false,
          error: 'sessionId et stepId requis',
          timestamp: new Date().toISOString()
        });
      }
      
      logSh(`🚀 Exécution étape ${stepId} pour session ${sessionId}`, 'INFO');
      
      // Récupérer la session
      const session = sessionManager.getSession(sessionId);
      
      // Trouver l'étape
      const step = session.steps.find(s => s.id === stepId);
      if (!step) {
        return res.status(400).json({
          success: false,
          error: `Étape ${stepId} introuvable`,
          timestamp: new Date().toISOString()
        });
      }
      
      // Marquer l'étape comme en cours
      step.status = 'executing';
      
      // Créer l'exécuteur et lancer l'étape
      const executor = new StepExecutor();
      
      logSh(`🚀 Execution step ${step.system} avec données: ${JSON.stringify(session.inputData)}`, 'DEBUG');
      
      // Récupérer le contenu de l'étape précédente pour chaînage
      let inputContent = null;
      if (stepId > 1) {
        const previousResult = session.results.find(r => r.stepId === stepId - 1);
        logSh(`🔍 DEBUG Chaînage: previousResult=${!!previousResult}`, 'DEBUG');
        if (previousResult) {
          logSh(`🔍 DEBUG Chaînage: previousResult.result=${!!previousResult.result}`, 'DEBUG');
          if (previousResult.result) {
            // StepExecutor retourne un objet avec une propriété 'content'
            if (previousResult.result.content) {
              inputContent = previousResult.result.content;
              logSh(`🔄 Chaînage: utilisation contenu.content étape ${stepId - 1}`, 'DEBUG');
            } else {
              // Fallback si c'est juste le contenu directement
              inputContent = previousResult.result;
              logSh(`🔄 Chaînage: utilisation contenu direct étape ${stepId - 1}`, 'DEBUG');
            }
            logSh(`🔍 DEBUG: inputContent type=${typeof inputContent}, keys=${Object.keys(inputContent || {})}`, 'DEBUG');
          } else {
            logSh(`🚨 DEBUG: previousResult.result est vide ou null !`, 'ERROR');
          }
        } else {
          logSh(`🚨 DEBUG: Pas de previousResult trouvé pour stepId=${stepId - 1}`, 'ERROR');
        }
      }
      
      // Ajouter le contenu d'entrée aux options si disponible
      const executionOptions = {
        ...options,
        inputContent: inputContent
      };
      
      const result = await executor.executeStep(step.system, session.inputData, executionOptions);
      
      logSh(`📊 Résultat step ${step.system}: success=${result.success}, content=${Object.keys(result.content || {}).length} éléments, duration=${result.stats?.duration}ms`, 'INFO');
      
      // Si pas d'erreur mais temps < 100ms, forcer une erreur pour debug
      if (result.success && result.stats?.duration < 100) {
        logSh(`⚠️ WARN: Step trop rapide (${result.stats?.duration}ms), probablement pas d'appel LLM réel`, 'WARN');
        result.debugWarning = `⚠️ Exécution suspecte: ${result.stats?.duration}ms (probablement pas d'appel LLM)`;
      }
      
      // Ajouter le résultat à la session
      sessionManager.addStepResult(sessionId, stepId, result);
      
      // Déterminer la prochaine étape
      const nextStep = session.steps.find(s => s.id === stepId + 1);
      
      res.json({
        success: true,
        stepId: stepId,
        system: step.system,
        name: step.name,
        result: {
          success: result.success,
          content: result.result,
          formatted: result.formatted,
          xmlFormatted: result.xmlFormatted,
          error: result.error,
          debugWarning: result.debugWarning
        },
        stats: result.stats,
        nextStep: nextStep ? nextStep.id : null,
        sessionStatus: session.status,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur exécution step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur exécution étape',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Récupère le status d'une session
   */
  handleStepByStepStatus(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      const { sessionId } = req.params;
      
      const session = sessionManager.getSession(sessionId);
      
      res.json({
        success: true,
        session: {
          id: session.id,
          status: session.status,
          createdAt: new Date(session.createdAt).toISOString(),
          currentStep: session.currentStep,
          completedSteps: session.completedSteps,
          totalSteps: session.steps.length,
          inputData: session.inputData,
          steps: session.steps,
          globalStats: session.globalStats,
          results: session.results.map(r => ({
            stepId: r.stepId,
            system: r.system,
            success: r.success,
            timestamp: new Date(r.timestamp).toISOString(),
            stats: r.stats
          }))
        },
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur status step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération status',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Reset une session
   */
  handleStepByStepReset(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      const { sessionId } = req.body;
      
      if (!sessionId) {
        return res.status(400).json({
          success: false,
          error: 'sessionId requis',
          timestamp: new Date().toISOString()
        });
      }
      
      const session = sessionManager.resetSession(sessionId);
      
      res.json({
        success: true,
        sessionId: session.id,
        message: 'Session reset avec succès',
        steps: session.steps,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur reset step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur reset session',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Export les résultats d'une session
   */
  handleStepByStepExport(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      const { sessionId } = req.params;
      
      const exportData = sessionManager.exportSession(sessionId);
      
      res.setHeader('Content-Type', 'application/json');
      res.setHeader('Content-Disposition', `attachment; filename="step-by-step-${sessionId}.json"`);
      res.json(exportData);
      
    } catch (error) {
      logSh(`❌ Erreur export step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur export session',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  /**
   * Liste les sessions actives
   */
  handleStepByStepSessions(req, res) {
    try {
      const { sessionManager } = require('../StepByStepSessionManager');
      
      const sessions = sessionManager.listSessions();
      
      res.json({
        success: true,
        sessions: sessions,
        total: sessions.length,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur list sessions step-by-step: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération sessions',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  /**
   * Handler pour récupérer les personnalités disponibles
   */
  async handleGetPersonalities(req, res) {
    try {
      const { getPersonalities } = require('../BrainConfig');
      
      const personalities = await getPersonalities();
      
      res.json({
        success: true,
        personalities: personalities || [],
        total: (personalities || []).length,
        timestamp: new Date().toISOString()
      });
      
    } catch (error) {
      logSh(`❌ Erreur récupération personnalités: ${error.message}`, 'ERROR');
      res.status(500).json({
        success: false,
        error: 'Erreur récupération personnalités',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  /**
   * 🆕 Handler pour génération simple d'article avec mot-clé
   */
  async handleGenerateSimple(req, res) {
    try {
      const { keyword } = req.body;

      // Validation basique
      if (!keyword || typeof keyword !== 'string' || keyword.trim().length === 0) {
        return res.status(400).json({
          success: false,
          error: 'Mot-clé requis',
          message: 'Le paramètre "keyword" est obligatoire et doit être une chaîne non vide'
        });
      }

      const cleanKeyword = keyword.trim();
      logSh(`🎯 Génération simple pour mot-clé: "${cleanKeyword}"`, 'INFO');

      // Créer un template XML simple basé sur le mot-clé
      const simpleTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<article>
  <h1>|Titre_Principal{{${cleanKeyword}}}{Rédige un titre H1 accrocheur pour "${cleanKeyword}"}|</h1>
  <intro>|Introduction{{${cleanKeyword}}}{Rédige une introduction engageante de 2-3 phrases pour "${cleanKeyword}"}|</intro>
  <section1>
    <h2>|Sous_Titre_1{{${cleanKeyword}}}{Rédige un sous-titre H2 pour "${cleanKeyword}"}|</h2>
    <content>|Contenu_1{{${cleanKeyword}}}{Rédige un paragraphe détaillé sur "${cleanKeyword}"}|</content>
  </section1>
  <section2>
    <h2>|Sous_Titre_2{{${cleanKeyword}}}{Rédige un autre sous-titre H2 pour "${cleanKeyword}"}|</h2>
    <content>|Contenu_2{{${cleanKeyword}}}{Rédige un autre paragraphe sur "${cleanKeyword}"}|</content>
  </section2>
  <conclusion>|Conclusion{{${cleanKeyword}}}{Rédige une conclusion pour l'article sur "${cleanKeyword}"}|</conclusion>
</article>`;

      // Préparer les données pour le workflow
      const workflowData = {
        csvData: {
          mc0: cleanKeyword,
          t0: `Guide complet sur ${cleanKeyword}`,
          personality: { nom: 'Marc', style: 'professionnel' },
          tMinus1: cleanKeyword,
          mcPlus1: `${cleanKeyword},guide ${cleanKeyword},tout savoir ${cleanKeyword}`,
          tPlus1: `Guide ${cleanKeyword},Conseils ${cleanKeyword},${cleanKeyword} pratique`
        },
        xmlTemplate: Buffer.from(simpleTemplate).toString('base64'),
        source: 'api_generate_simple'
      };

      logSh(`📝 Template créé pour "${cleanKeyword}"`, 'DEBUG');

      // Utiliser le workflow modulaire simple (juste génération de base)
      const { handleModularWorkflow } = require('../Main');

      const config = {
        selectiveStack: 'lightEnhancement',
        adversarialMode: 'none',
        humanSimulationMode: 'none',
        patternBreakingMode: 'none',
        saveVersions: false,
        source: 'api_generate_simple'
      };

      logSh(`🚀 Démarrage génération modulaire pour "${cleanKeyword}"`, 'INFO');

      const result = await handleModularWorkflow(workflowData, config);

      logSh(`✅ Génération terminée pour "${cleanKeyword}"`, 'INFO');

      // Réponse simplifiée
      res.json({
        success: true,
        keyword: cleanKeyword,
        article: {
          content: result.compiledText || result.generatedTexts || 'Contenu généré',
          title: result.generatedTexts?.Titre_Principal || `Article sur ${cleanKeyword}`,
          meta: {
            processing_time: result.processingTime || 'N/A',
            personality: result.personality?.nom || 'Marc',
            version: result.version || 'v1.0'
          }
        },
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      logSh(`❌ Erreur génération simple: ${error.message}`, 'ERROR');
      logSh(`Stack: ${error.stack}`, 'DEBUG');

      res.status(500).json({
        success: false,
        error: 'Erreur lors de la génération',
        message: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }

  // ========================================
  // INTERFACE WEB
  // ========================================
  
  /**
   * Configure l'interface web
   */
  setupWebInterface() {
    // Page d'accueil - Dashboard MANUAL
    this.app.get('/', (req, res) => {
      res.send(this.generateManualDashboard());
    });

    // Route pour le log viewer
    this.app.get('/logs-viewer.html', (req, res) => {
      const fs = require('fs');
      const logViewerPath = path.join(__dirname, '../../tools/logs-viewer.html');
      
      try {
        const content = fs.readFileSync(logViewerPath, 'utf-8');
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.send(content);
      } catch (error) {
        logSh(`❌ Erreur lecture log viewer: ${error.message}`, 'ERROR');
        res.status(500).send(`Erreur: ${error.message}`);
      }
    });

    // Route 404
    this.app.use('*', (req, res) => {
      res.status(404).json({
        success: false,
        error: 'Route non trouvée',
        path: req.originalUrl,
        mode: 'MANUAL',
        message: 'Cette route n\'existe pas en mode MANUAL'
      });
    });

    logSh('🌐 Interface web configurée', 'DEBUG');
  }

  /**
   * Génère le dashboard HTML du mode MANUAL
   */
  generateManualDashboard() {
    const uptime = Math.floor((Date.now() - this.stats.startTime) / 1000);
    
    return `
    <!DOCTYPE html>
    <html>
    <head>
        <title>SEO Generator - Mode MANUAL</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 0; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; }
            .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); }
            .header { text-align: center; margin-bottom: 40px; }
            .header h1 { color: #2d3748; margin-bottom: 10px; }
            .mode-badge { background: #48bb78; color: white; padding: 8px 16px; border-radius: 20px; font-weight: bold; }
            .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 40px; }
            .stat-card { background: #f7fafc; padding: 20px; border-radius: 10px; text-align: center; border: 1px solid #e2e8f0; }
            .stat-number { font-size: 2em; font-weight: bold; color: #2d3748; }
            .stat-label { color: #718096; margin-top: 5px; }
            .section { margin: 30px 0; padding: 25px; border: 1px solid #e2e8f0; border-radius: 10px; background: #f9f9f9; }
            .section h2 { color: #2d3748; margin-bottom: 15px; }
            .button { display: inline-block; padding: 12px 24px; margin: 8px; background: linear-gradient(135deg, #667eea, #764ba2); color: white; text-decoration: none; border-radius: 8px; border: none; cursor: pointer; font-weight: 500; transition: all 0.2s; }
            .button:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); }
            .button.success { background: linear-gradient(135deg, #48bb78, #38a169); }
            .button.warning { background: linear-gradient(135deg, #ed8936, #dd6b20); }
            .alert { padding: 15px; margin: 20px 0; border-radius: 8px; border-left: 4px solid; }
            .alert.success { background: #f0fff4; border-color: #48bb78; color: #22543d; }
            .alert.info { background: #ebf8ff; border-color: #4299e1; color: #2a4365; }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>🎯 SEO Generator Server</h1>
                <span class="mode-badge">MODE MANUAL</span>
                <p style="color: #718096; margin-top: 15px;">Interface Client + API + Tests Modulaires</p>
            </div>
            
            <div class="alert success">
                <strong>✅ Mode MANUAL Actif</strong><br>
                Interface complète disponible • WebSocket temps réel • API complète
            </div>

            <div class="stats">
                <div class="stat-card">
                    <div class="stat-number">${uptime}s</div>
                    <div class="stat-label">Uptime</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${this.stats.requests}</div>
                    <div class="stat-label">Requêtes</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${this.activeClients.size}</div>
                    <div class="stat-label">Clients WebSocket</div>
                </div>
                <div class="stat-card">
                    <div class="stat-number">${this.stats.testsExecuted}</div>
                    <div class="stat-label">Tests Exécutés</div>
                </div>
            </div>

            <div class="section">
                <h2>🧪 Interface Test Modulaire</h2>
                <p>Interface avancée pour tester toutes les combinaisons modulaires avec logs temps réel.</p>
                <a href="/test-modulaire.html" target="_blank" class="button">🚀 Ouvrir Interface Test</a>
                <a href="/step-by-step" target="_blank" class="button">⚡ Interface Step-by-Step</a>
                <a href="/api/modulaire-config" target="_blank" class="button success">📋 Configuration API</a>
            </div>

            <div class="section">
                <h2>📊 Monitoring & API</h2>
                <p>Endpoints disponibles en mode MANUAL.</p>
                <a href="/api/status" target="_blank" class="button">📊 Status API</a>
                <a href="/api/stats" target="_blank" class="button">📈 Statistiques</a>
                <button onclick="testConnection()" class="button success">🔍 Test Connexion</button>
            </div>

            <div class="section">
                <h2>🌐 WebSocket Logs</h2>
                <p>Logs temps réel sur <strong>ws://localhost:${this.config.wsPort}</strong></p>
                <button onclick="startLogViewer()" class="button warning">🔍 Ouvrir Log Viewer</button>
                <div id="wsStatus" style="margin-top: 10px; padding: 10px; background: #e2e8f0; border-radius: 5px;">
                    Status: <span id="wsStatusText">Déconnecté</span>
                </div>
            </div>

            <div class="section">
                <h2>💡 Informations Mode MANUAL</h2>
                <ul style="color: #4a5568; line-height: 1.6;">
                    <li><strong>Interface Client</strong> : Dashboard complet et interface de test</li>
                    <li><strong>API Complète</strong> : Tests individuels, benchmarks, configuration</li>
                    <li><strong>WebSocket</strong> : Logs temps réel sur port ${this.config.wsPort}</li>
                    <li><strong>Multi-Client</strong> : Plusieurs utilisateurs simultanés</li>
                    <li><strong>Pas de GSheets</strong> : Données test simulées ou fournies</li>
                </ul>
            </div>
        </div>

        <script>
            let ws = null;
            
            function testConnection() {
                fetch('/api/status')
                    .then(res => res.json())
                    .then(data => {
                        alert('✅ Connexion OK: ' + (data.mode || 'Mode MANUAL actif') + ' - Uptime: ' + Math.floor(data.uptime/1000) + 's');
                    })
                    .catch(err => {
                        alert('❌ Erreur connexion: ' + err.message);
                    });
            }
            
            function startLogViewer() {
                fetch('/api/start-log-viewer', { method: 'POST' })
                    .then(res => res.json())
                    .then(data => {
                        if (data.success) {
                            alert('✅ Log Viewer lancé! WebSocket sur port ' + data.wsPort);
                            // Reconnecter le WebSocket pour voir les logs
                            connectWebSocket();
                        } else {
                            alert('❌ Erreur: ' + data.message);
                        }
                    })
                    .catch(err => {
                        alert('❌ Erreur lancement: ' + err.message);
                    });
            }
            
            let reconnectAttempts = 0;
            const maxReconnectDelay = 30000; // 30s max
            
            function connectWebSocket() {
                try {
                    ws = new WebSocket('ws://localhost:${this.config.wsPort}');
                    
                    ws.onopen = () => {
                        reconnectAttempts = 0; // Reset compteur
                        document.getElementById('wsStatusText').textContent = 'Connecté ✅';
                        document.getElementById('wsStatus').style.background = '#c6f6d5';
                    };
                    
                    ws.onclose = () => {
                        document.getElementById('wsStatusText').textContent = 'Déconnecté ❌';
                        document.getElementById('wsStatus').style.background = '#fed7d7';
                        
                        // Backoff exponentiel pour éviter spam
                        reconnectAttempts++;
                        const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), maxReconnectDelay);
                        console.log('WebSocket fermé, reconnexion dans ' + (delay/1000) + 's (tentative ' + reconnectAttempts + ')');
                        setTimeout(connectWebSocket, delay);
                    };
                    
                } catch (error) {
                    console.warn('WebSocket non disponible:', error.message);
                    // Retry avec backoff en cas d'erreur de connexion
                    reconnectAttempts++;
                    const delay = Math.min(5000 * reconnectAttempts, maxReconnectDelay);
                    setTimeout(connectWebSocket, delay);
                }
            }
            
            // Auto-connect WebSocket
            connectWebSocket();
            
            // Refresh stats every 30s
            setInterval(() => {
                window.location.reload();
            }, 30000);
        </script>
    </body>
    </html>
    `;
  }

  // ========================================
  // WEBSOCKET SERVER
  // ========================================
  
  /**
   * Configure le serveur WebSocket pour logs temps réel
   */
  async setupWebSocketServer() {
    try {
      this.wsServer = new WebSocket.Server({ 
        port: this.config.wsPort,
        host: this.config.host
      });
      
      this.wsServer.on('connection', (ws, req) => {
        this.handleWebSocketConnection(ws, req);
      });
      
      this.wsServer.on('error', (error) => {
        logSh(`❌ Erreur WebSocket: ${error.message}`, 'ERROR');
      });
      
      logSh(`📡 WebSocket Server démarré sur ws://${this.config.host}:${this.config.wsPort}`, 'DEBUG');
      
    } catch (error) {
      logSh(`⚠️ Impossible de démarrer WebSocket: ${error.message}`, 'WARNING');
      // Continue sans WebSocket si erreur
    }
  }

  /**
   * Gère les nouvelles connexions WebSocket
   */
  handleWebSocketConnection(ws, req) {
    const clientId = `client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const clientIP = req.socket.remoteAddress;
    
    const clientData = { id: clientId, ws, ip: clientIP, connectedAt: Date.now() };
    this.activeClients.add(clientData);
    this.stats.sessions++;
    
    logSh(`📡 Nouveau client WebSocket: ${clientId} (${clientIP})`, 'TRACE');
    
    // Message de bienvenue
    ws.send(JSON.stringify({
      type: 'welcome',
      message: 'Connecté aux logs temps réel SEO Generator (Mode MANUAL)',
      clientId: clientId,
      timestamp: new Date().toISOString()
    }));
    
    // Gestion fermeture
    ws.on('close', () => {
      this.activeClients.delete(clientData);
      logSh(`📡 Client WebSocket déconnecté: ${clientId}`, 'TRACE');
    });
    
    // Gestion erreurs
    ws.on('error', (error) => {
      this.activeClients.delete(clientData);
      logSh(`⚠️ Erreur client WebSocket ${clientId}: ${error.message}`, 'WARNING');
    });
  }

  /**
   * Diffuse un message à tous les clients WebSocket
   */
  broadcastToClients(logData) {
    if (this.activeClients.size === 0) return;
    
    const message = JSON.stringify({
      type: 'log',
      ...logData,
      timestamp: new Date().toISOString()
    });
    
    this.activeClients.forEach(client => {
      if (client.ws.readyState === WebSocket.OPEN) {
        try {
          client.ws.send(message);
        } catch (error) {
          // Client déconnecté, le supprimer
          this.activeClients.delete(client);
        }
      }
    });
  }

  /**
   * Déconnecte tous les clients WebSocket
   */
  disconnectAllClients() {
    this.activeClients.forEach(client => {
      try {
        client.ws.close();
      } catch (error) {
        // Ignore les erreurs de fermeture
      }
    });
    
    this.activeClients.clear();
    logSh('📡 Tous les clients WebSocket déconnectés', 'DEBUG');
  }

  // ========================================
  // SERVEUR HTTP
  // ========================================
  
  /**
   * Démarre le serveur HTTP
   */
  async startHTTPServer() {
    return new Promise((resolve, reject) => {
      try {
        this.server = this.app.listen(this.config.port, this.config.host, () => {
          resolve();
        });
        
        this.server.on('error', (error) => {
          reject(error);
        });
        
      } catch (error) {
        reject(error);
      }
    });
  }

  // ========================================
  // MONITORING
  // ========================================
  
  /**
   * Démarre le monitoring du serveur
   */
  startMonitoring() {
    const MONITOR_INTERVAL = 30000; // 30 secondes
    
    this.monitorInterval = setInterval(() => {
      this.performMonitoring();
    }, MONITOR_INTERVAL);
    
    logSh('💓 Monitoring ManualServer démarré', 'DEBUG');
  }

  /**
   * Effectue le monitoring périodique
   */
  performMonitoring() {
    const memUsage = process.memoryUsage();
    const uptime = Date.now() - this.stats.startTime;
    
    logSh(`💓 ManualServer Health - Clients: ${this.activeClients.size} | Requêtes: ${this.stats.requests} | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE');
    
    // Nettoyage clients WebSocket morts
    this.cleanupDeadClients();
  }

  /**
   * Nettoie les clients WebSocket déconnectés
   */
  cleanupDeadClients() {
    let cleaned = 0;
    const deadClients = [];
    
    this.activeClients.forEach(client => {
      if (client.ws.readyState !== WebSocket.OPEN) {
        deadClients.push(client);
        cleaned++;
      }
    });
    
    // Supprimer les clients morts
    deadClients.forEach(client => {
      this.activeClients.delete(client);
    });
    
    if (cleaned > 0) {
      logSh(`🧹 ${cleaned} clients WebSocket morts nettoyés`, 'TRACE');
    }
  }

  // ========================================
  // ÉTAT ET CONTRÔLES
  // ========================================
  
  /**
   * Vérifie s'il y a des clients actifs
   */
  hasActiveClients() {
    return this.activeClients.size > 0;
  }

  /**
   * Retourne l'état du serveur MANUAL
   */
  getStatus() {
    return {
      isRunning: this.isRunning,
      config: { ...this.config },
      stats: {
        ...this.stats,
        uptime: Date.now() - this.stats.startTime
      },
      activeClients: this.activeClients.size,
      urls: {
        dashboard: `http://localhost:${this.config.port}`,
        testInterface: `http://localhost:${this.config.port}/test-modulaire.html`,
        apiStatus: `http://localhost:${this.config.port}/api/status`,
        websocket: `ws://localhost:${this.config.wsPort}`
      }
    };
  }
}

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

/*
┌────────────────────────────────────────────────────────────────────┐
│  File: lib/modes/ModeManager.js                                    │
└────────────────────────────────────────────────────────────────────┘
*/

// ========================================
// 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') {
    logSh('🎛️ Initialisation ModeManager...', 'INFO');
    
    try {
      // Détecter mode selon arguments ou config
      const detectedMode = this.detectIntendedMode(initialMode);
      
      logSh(`🎯 Mode détecté: ${detectedMode.toUpperCase()}`, 'INFO');
      
      // Nettoyer état précédent si nécessaire
      await this.cleanupPreviousState();
      
      // Basculer vers le mode détecté
      await this.switchToMode(detectedMode);
      
      // Sauvegarder état
      this.saveModeState();
      
      logSh(`✅ ModeManager initialisé en mode ${this.currentMode.toUpperCase()}`, '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 { ManualServer } = require('./ManualServer');
    
    logSh('🎯 Démarrage ManualServer...', 'DEBUG');
    
    this.activeServices.manualServer = new ManualServer();
    await this.activeServices.manualServer.start();
    
    logSh('✅ Mode MANUAL démarré', 'DEBUG');
  }

  /**
   * 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 };

