/**
 * 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');
const { getLLMProvidersList } = require('../LLMManager');

/**
 * Providers LLM disponibles (source unique depuis LLMManager)
 */
const AVAILABLE_LLM_PROVIDERS = getLLMProvidersList();

/**
 * Modules disponibles dans le pipeline
 */
const AVAILABLE_MODULES = {
  generation: {
    name: 'Generation',
    description: 'Génération initiale du contenu',
    modes: ['simple'],
    defaultIntensity: 1.0,
    defaultLLM: 'claude-sonnet-4-5',
    parameters: {
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'claude-sonnet-4-5' }
    }
  },
  selective: {
    name: 'Selective Enhancement',
    description: 'Amélioration sélective par couches',
    modes: [
      'lightEnhancement',
      'standardEnhancement',
      'fullEnhancement',
      'personalityFocus',
      'fluidityFocus',
      'adaptive'
    ],
    defaultIntensity: 1.0,
    defaultLLM: 'gpt-4o-mini',
    parameters: {
      layers: { type: 'array', description: 'Couches spécifiques à appliquer' },
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'gpt-4o-mini' }
    }
  },
  smarttouch: {
    name: 'SmartTouch (Analyse→Ciblé)',
    description: 'Analyse intelligente puis améliorations précises ciblées (nouvelle génération)',
    modes: [
      'full',                  // Analyse + Technical + Style + Readability
      'analysis_only',         // Analyse uniquement sans amélioration
      'technical_only',        // Améliorations techniques ciblées uniquement
      'style_only',            // Améliorations style ciblées uniquement
      'readability_only'       // Améliorations lisibilité ciblées uniquement
    ],
    defaultIntensity: 1.0,
    defaultLLM: 'gpt-4o-mini',
    parameters: {
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'gpt-4o-mini' },
      skipAnalysis: { type: 'boolean', default: false, description: 'Passer l\'analyse (mode legacy)' },
      layersOrder: { type: 'array', default: ['technical', 'style', 'readability'], description: 'Ordre d\'application des couches' },
      charsPerExpression: { type: 'number', min: 1000, max: 10000, default: 4000, description: 'Caractères par expression familière (budget dynamique)' },
      personalityName: { type: 'string', required: false, description: 'Nom de la personnalité à utiliser (ex: "Sophie", "Marc"). Si non spécifié, utilise celle du csvData.' }
    }
  },
  adversarial: {
    name: 'Adversarial Generation',
    description: 'Techniques anti-détection',
    modes: ['none', 'light', 'standard', 'heavy', 'adaptive'],
    defaultIntensity: 1.0,
    defaultLLM: 'gemini-pro',
    parameters: {
      detector: { type: 'string', enum: ['general', 'gptZero', 'originality'], default: 'general' },
      method: { type: 'string', enum: ['enhancement', 'regeneration', 'hybrid'], default: 'regeneration' },
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'gemini-pro' }
    }
  },
  human: {
    name: 'Human Simulation',
    description: 'Simulation comportement humain',
    modes: [
      'none',
      'lightSimulation',
      'standardSimulation',
      'heavySimulation',
      'adaptiveSimulation',
      'personalityFocus',
      'temporalFocus'
    ],
    defaultIntensity: 1.0,
    defaultLLM: 'mistral-small',
    parameters: {
      fatigueLevel: { type: 'number', min: 0, max: 1, default: 0.5 },
      errorRate: { type: 'number', min: 0, max: 1, default: 0.3 },
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'mistral-small' }
    }
  },
  pattern: {
    name: 'Pattern Breaking',
    description: 'Cassage patterns LLM',
    modes: [
      'none',
      'lightPatternBreaking',
      'standardPatternBreaking',
      'heavyPatternBreaking',
      'adaptivePatternBreaking',
      'syntaxFocus',
      'connectorsFocus'
    ],
    defaultIntensity: 1.0,
    defaultLLM: 'deepseek-chat',
    parameters: {
      focus: { type: 'string', enum: ['syntax', 'connectors', 'both'], default: 'both' },
      llmProvider: { type: 'string', enum: AVAILABLE_LLM_PROVIDERS.map(p => p.id), default: 'deepseek-chat' }
    }
  }
};

/**
 * 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,
      smarttouch: 25,    // ✅ AJOUTÉ: smarttouch (analyse + améliorations ciblées)
      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,
  AVAILABLE_LLM_PROVIDERS,
  PIPELINE_SCHEMA,
  STEP_SCHEMA
};
