// ========================================
// GLOBAL BUDGET MANAGER - Gestion budget global expressions familières
// Responsabilité: Empêcher spam en distribuant budget limité sur tous les tags
// Architecture: Budget défini par personality, distribué aléatoirement, consommé et tracké
// ========================================

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

/**
 * GLOBAL BUDGET MANAGER
 * Gère un budget global d'expressions familières pour toute une génération
 */
class GlobalBudgetManager {
  constructor(personality, contentMap = {}, config = {}) {
    this.personality = personality;
    this.contentMap = contentMap;
    this.config = config;

    // Paramètre configurable : caractères par expression (default 4000)
    this.charsPerExpression = config.charsPerExpression || 4000;

    // Calculer taille totale du contenu
    const totalChars = Object.values(contentMap).join('').length;
    this.totalChars = totalChars;

    // Budget par défaut (sera écrasé par calcul dynamique)
    this.defaultBudget = {
      costaud: 2,
      nickel: 2,
      tipTop: 1,
      impeccable: 2,
      solide: 3,
      total: 10
    };

    // === ✅ NOUVEAU: Calculer budget dynamiquement ===
    this.budget = this.calculateDynamicBudget(contentMap, personality);

    // Tracking consommation
    this.consumed = {};
    this.totalConsumed = 0;

    // Assignments par tag
    this.tagAssignments = {};
  }

  /**
   * ✅ NOUVEAU: Calculer budget dynamiquement selon taille texte
   * Formule : budgetTotal = Math.floor(totalChars / charsPerExpression)
   * Puis soustraire occurrences existantes
   */
  calculateDynamicBudget(contentMap, personality) {
    const fullText = Object.values(contentMap).join(' ');
    const totalChars = fullText.length;

    // Calculer budget total basé sur taille
    const budgetTotal = Math.max(1, Math.floor(totalChars / this.charsPerExpression));

    logSh(`📏 Taille texte: ${totalChars} chars → Budget calculé: ${budgetTotal} expressions (${this.charsPerExpression} chars/expr)`, 'INFO');

    // Compter occurrences existantes de chaque expression
    const fullTextLower = fullText.toLowerCase();
    const existingOccurrences = {
      costaud: (fullTextLower.match(/costaud/g) || []).length,
      nickel: (fullTextLower.match(/nickel/g) || []).length,
      tipTop: (fullTextLower.match(/tip[\s-]?top/g) || []).length,
      impeccable: (fullTextLower.match(/impeccable/g) || []).length,
      solide: (fullTextLower.match(/solide/g) || []).length
    };

    const totalExisting = Object.values(existingOccurrences).reduce((sum, count) => sum + count, 0);

    logSh(`📊 Occurrences existantes: ${JSON.stringify(existingOccurrences)} (total: ${totalExisting})`, 'DEBUG');

    // Budget disponible = Budget calculé - Occurrences existantes
    let budgetAvailable = Math.max(0, budgetTotal - totalExisting);

    logSh(`💰 Budget disponible après soustraction: ${budgetAvailable}/${budgetTotal}`, 'INFO');

    // Si aucun budget disponible, retourner budget vide
    if (budgetAvailable === 0) {
      logSh(`⚠️ Budget épuisé par occurrences existantes, aucune expression familière supplémentaire autorisée`, 'WARN');
      return {
        costaud: 0,
        nickel: 0,
        tipTop: 0,
        impeccable: 0,
        solide: 0,
        total: 0
      };
    }

    // Distribuer budget disponible selon style personality
    return this.distributeBudgetByStyle(budgetAvailable, personality);
  }

  /**
   * Distribuer budget selon style personality
   */
  distributeBudgetByStyle(budgetTotal, personality) {
    if (!personality || !personality.style) {
      // Fallback: distribution équitable
      return this.equalDistribution(budgetTotal);
    }

    const style = personality.style.toLowerCase();

    if (style.includes('familier') || style.includes('accessible')) {
      // Kévin-like: plus d'expressions familières variées
      return {
        costaud: Math.floor(budgetTotal * 0.25),
        nickel: Math.floor(budgetTotal * 0.25),
        tipTop: Math.floor(budgetTotal * 0.15),
        impeccable: Math.floor(budgetTotal * 0.2),
        solide: Math.floor(budgetTotal * 0.15),
        total: budgetTotal
      };
    } else if (style.includes('technique') || style.includes('précis')) {
      // Marc-like: presque pas d'expressions familières (tout sur "solide")
      return {
        costaud: 0,
        nickel: 0,
        tipTop: 0,
        impeccable: Math.floor(budgetTotal * 0.3),
        solide: Math.floor(budgetTotal * 0.7),
        total: budgetTotal
      };
    }

    // Fallback: distribution équitable
    return this.equalDistribution(budgetTotal);
  }

  /**
   * Distribution équitable du budget
   */
  equalDistribution(budgetTotal) {
    const perExpression = Math.floor(budgetTotal / 5);
    return {
      costaud: perExpression,
      nickel: perExpression,
      tipTop: perExpression,
      impeccable: perExpression,
      solide: perExpression,
      total: budgetTotal
    };
  }

  /**
   * Initialiser budget depuis personality ou fallback default (LEGACY - non utilisé)
   */
  initializeBudget(personality) {
    if (personality?.budgetExpressions) {
      logSh(`📊 Budget expressions depuis personality: ${JSON.stringify(personality.budgetExpressions)}`, 'DEBUG');
      return { ...personality.budgetExpressions };
    }

    // Fallback: adapter selon style personality
    if (personality?.style) {
      const style = personality.style.toLowerCase();

      if (style.includes('familier') || style.includes('accessible')) {
        // Kévin-like: plus d'expressions familières autorisées
        return {
          costaud: 2,
          nickel: 2,
          tipTop: 1,
          impeccable: 2,
          solide: 3,
          total: 10
        };
      } else if (style.includes('technique') || style.includes('précis')) {
        // Marc-like: presque pas d'expressions familières
        return {
          costaud: 0,
          nickel: 0,
          tipTop: 0,
          impeccable: 1,
          solide: 2,
          total: 3
        };
      }
    }

    // Fallback ultime
    logSh(`📊 Budget expressions par défaut: ${JSON.stringify(this.defaultBudget)}`, 'DEBUG');
    return { ...this.defaultBudget };
  }

  /**
   * Distribuer budget aléatoirement sur tous les tags
   * @param {array} tags - Liste des tags à traiter
   */
  distributeRandomly(tags) {
    logSh(`🎲 Distribution aléatoire du budget sur ${tags.length} tags`, 'DEBUG');

    const assignments = {};

    // Initialiser tous les tags à 0
    tags.forEach(tag => {
      assignments[tag] = {
        costaud: 0,
        nickel: 0,
        tipTop: 0,
        impeccable: 0,
        solide: 0
      };
    });

    // Distribuer chaque expression
    const expressions = ['costaud', 'nickel', 'tipTop', 'impeccable', 'solide'];

    expressions.forEach(expr => {
      const maxCount = this.budget[expr] || 0;

      for (let i = 0; i < maxCount; i++) {
        // Choisir tag aléatoire
        const randomTag = tags[Math.floor(Math.random() * tags.length)];
        assignments[randomTag][expr]++;
      }
    });

    this.tagAssignments = assignments;

    logSh(`✅ Budget distribué: ${JSON.stringify(assignments)}`, 'DEBUG');

    return assignments;
  }

  /**
   * Obtenir budget alloué pour un tag spécifique
   */
  getBudgetForTag(tag) {
    return this.tagAssignments[tag] || {
      costaud: 0,
      nickel: 0,
      tipTop: 0,
      impeccable: 0,
      solide: 0
    };
  }

  /**
   * Consommer budget (marquer comme utilisé)
   */
  consumeBudget(tag, expression, count = 1) {
    if (!this.consumed[tag]) {
      this.consumed[tag] = {
        costaud: 0,
        nickel: 0,
        tipTop: 0,
        impeccable: 0,
        solide: 0
      };
    }

    this.consumed[tag][expression] += count;
    this.totalConsumed += count;

    logSh(`📉 Budget consommé [${tag}] ${expression}: ${count} (total: ${this.totalConsumed}/${this.budget.total})`, 'DEBUG');
  }

  /**
   * Vérifier si on peut encore utiliser une expression
   */
  canUse(tag, expression) {
    const allocated = this.tagAssignments[tag]?.[expression] || 0;
    const used = this.consumed[tag]?.[expression] || 0;

    const canUse = used < allocated && this.totalConsumed < this.budget.total;

    if (!canUse) {
      logSh(`🚫 Budget épuisé pour [${tag}] ${expression} (used: ${used}/${allocated}, total: ${this.totalConsumed}/${this.budget.total})`, 'DEBUG');
    }

    return canUse;
  }

  /**
   * Obtenir budget restant global
   */
  getRemainingBudget() {
    return {
      remaining: this.budget.total - this.totalConsumed,
      total: this.budget.total,
      consumed: this.totalConsumed,
      percentage: ((this.totalConsumed / this.budget.total) * 100).toFixed(1)
    };
  }

  /**
   * Générer rapport final
   */
  getReport() {
    const remaining = this.getRemainingBudget();

    return {
      budget: this.budget,
      totalConsumed: this.totalConsumed,
      remaining: remaining.remaining,
      percentageUsed: remaining.percentage,
      consumedByTag: this.consumed,
      allocatedByTag: this.tagAssignments,
      overBudget: this.totalConsumed > this.budget.total
    };
  }
}

module.exports = { GlobalBudgetManager };
