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