const moment = require('moment');

class NLPEngine {
  constructor() {
    this.entityPatterns = {
      gares: ['alger', 'oran', 'constantine', 'annaba', 'béjaïa', 'batna', 'sétif', 'skikda', 'biskra', 'tébessa', 'bechar', 'tlemcen', 'médéa', 'blida', 'boumerdès', 'el oued', 'oughlid', 'mascara', 'tiaret', 'saïda', 'djelfa', 'laghouat', 'batna', 'khenchela', 'oum el bouaghi', 'guelma', 'chlef', 'tipaza', 'ain defla', 'miliana', 'el affine', 'béni ourtilane', 'tizi ouzou', 'bejaia', 'bouchegoub', 'AIN SCC'],
      typesDonnees: {
        recettes: ['recette', 'revenus', 'argent', 'gain', 'montant', 'chiffre', 'CA', 'billet', 'vente', 'titre'],
        frequentation: ['passager', 'voyageur', 'fréquentation', 'trafic', 'client', 'passage', 'nombre'],
        retards: ['retard', 'retards', 'retardé', 'retardée', 'delai', 'délai'],
        flotte: ['bus', 'flotte', 'véhicule', 'parking', 'véhicules', 'disponibilité', 'état'],
        personnel: ['personnel', 'employé', 'employés', 'salarié', 'effectif', 'présence', 'absence', 'absentéisme']
      },
      periodes: {
        'aujourd\'hui': 'today',
        'hier': 'yesterday',
        'cette semaine': 'week',
        'semaine dernière': 'lastWeek',
        'semaine dernière': 'lastWeek',
        'ce mois': 'month',
        'mois dernier': 'lastMonth',
        'cette année': 'year',
        'année dernière': 'lastYear'
      },
      aggregations: {
        'total': 'SUM',
        'somme': 'SUM',
        'sum': 'SUM',
        'moyenne': 'AVG',
        'moyenne': 'AVG',
        'avg': 'AVG',
        'moyenne': 'AVG',
        'nombre': 'COUNT',
        'compter': 'COUNT',
        'count': 'COUNT'
      },
      comparateurs: {
        'plus': 'ASC',
        'moins': 'DESC',
        'meilleur': 'ASC',
        'pire': 'DESC',
        'top': 'ASC',
        'pire': 'DESC',
        'moins rentable': 'DESC',
        'plus rentable': 'ASC',
        'meilleur': 'ASC'
      }
    };

    this.contextMemory = new Map();
    this.maxMemorySize = 10;
  }

  parse(question, userId = 'default') {
    const normalizedQuestion = question.toLowerCase().trim();
    
    const parsed = {
      originalQuestion: question,
      typeDonnees: this.extractTypeDonnees(normalizedQuestion),
      periode: this.extractPeriode(normalizedQuestion),
      gare: this.extractGare(normalizedQuestion),
      ligne: this.extractLigne(normalizedQuestion),
      aggregation: this.extractAggregation(normalizedQuestion),
      comparateur: this.extractComparateur(normalizedQuestion),
      limite: this.extractLimite(normalizedQuestion),
      filters: this.extractFilters(normalizedQuestion),
      isFollowUp: this.isFollowUp(normalizedQuestion, userId),
      previousContext: this.getContext(userId)
    };

    this.setContext(userId, parsed);
    return parsed;
  }

  extractTypeDonnees(question) {
    for (const [type, keywords] of Object.entries(this.entityPatterns.typesDonnees)) {
      for (const keyword of keywords) {
        if (question.includes(keyword)) {
          return type;
        }
      }
    }
    return null;
  }

  extractPeriode(question) {
    const maintenant = moment();
    
    if (question.includes('aujourd\'hui')) {
      return { type: 'today', start: maintenant.startOf('day').format('YYYY-MM-DD'), end: maintenant.endOf('day').format('YYYY-MM-DD') };
    }
    if (question.includes('hier')) {
      const hier = moment().subtract(1, 'day');
      return { type: 'yesterday', start: hier.startOf('day').format('YYYY-MM-DD'), end: hier.endOf('day').format('YYYY-MM-DD') };
    }
    if (question.includes('semaine dernière') || question.includes('semaine der')) {
      return { type: 'lastWeek', start: moment().subtract(1, 'week').startOf('week').format('YYYY-MM-DD'), end: moment().subtract(1, 'week').endOf('week').format('YYYY-MM-DD') };
    }
    if (question.includes('semaine') || question.includes('cette semaine')) {
      return { type: 'week', start: moment().startOf('week').format('YYYY-MM-DD'), end: moment().endOf('week').format('YYYY-MM-DD') };
    }
    if (question.includes('mois dernier')) {
      return { type: 'lastMonth', start: moment().subtract(1, 'month').startOf('month').format('YYYY-MM-DD'), end: moment().subtract(1, 'month').endOf('month').format('YYYY-MM-DD') };
    }
    if (question.includes('mois') || question.includes('ce mois')) {
      return { type: 'month', start: moment().startOf('month').format('YYYY-MM-DD'), end: moment().endOf('month').format('YYYY-MM-DD') };
    }
    if (question.includes('année dernière') || question.includes('annee der')) {
      return { type: 'lastYear', start: moment().subtract(1, 'year').startOf('year').format('YYYY-MM-DD'), end: moment().subtract(1, 'year').endOf('year').format('YYYY-MM-DD') };
    }
    if (question.includes('annee') || question.includes('cette année')) {
      return { type: 'year', start: moment().startOf('year').format('YYYY-MM-DD'), end: moment().endOf('year').format('YYYY-MM-DD') };
    }
    
    return { type: 'week', start: moment().startOf('week').format('YYYY-MM-DD'), end: moment().endOf('week').format('YYYY-MM-DD') };
  }

  extractGare(question) {
    for (const gare of this.entityPatterns.gares) {
      if (question.includes(gare)) {
        return gare;
      }
    }
    return null;
  }

  extractLigne(question) {
    const ligneMatch = question.match(/ligne\s*(\d+)/i);
    if (ligneMatch) {
      return ligneMatch[1];
    }
    return null;
  }

  extractAggregation(question) {
    for (const [agg, keyword] of Object.entries(this.entityPatterns.aggregations)) {
      if (question.includes(keyword)) {
        return agg;
      }
    }
    return 'SUM';
  }

  extractComparateur(question) {
    for (const [comp, keyword] of Object.entries(this.entityPatterns.comparateurs)) {
      if (question.includes(keyword)) {
        return comp;
      }
    }
    return null;
  }

  extractLimite(question) {
    const match = question.match(/top\s*(\d+)|les?\s*(\d+)\s*(?:premier|première|premiers|premières|plus|mieux)/i);
    if (match) {
      return parseInt(match[1] || match[2]) || 10;
    }
    return 10;
  }

  extractFilters(question) {
    const filters = {};
    
    if (question.includes('retard') && question.includes('hier')) {
      filters.retardHier = true;
    }
    
    return filters;
  }

  isFollowUp(question, userId) {
    const followUpPhrases = ['et', 'aussi', 'ensuite', 'puis', 'et maintenant', 'et la', 'et le', 'et les', 'avec', 'également', 'aussi'];
    
    for (const phrase of followUpPhrases) {
      if (question.startsWith(phrase + ' ') || question.includes(' ' + phrase + ' ')) {
        return true;
      }
    }
    
    return false;
  }

  getContext(userId) {
    return this.contextMemory.get(userId) || null;
  }

  setContext(userId, parsed) {
    this.contextMemory.set(userId, parsed);
    
    if (this.contextMemory.size > this.maxMemorySize) {
      const firstKey = this.contextMemory.keys().next().value;
      this.contextMemory.delete(firstKey);
    }
  }

  resolveFollowUp(question, userId) {
    const context = this.getContext(userId);
    if (!context) return null;
    
    const parsed = this.parse(question, userId);
    
    if (parsed.isFollowUp) {
      return {
        ...parsed,
        periode: parsed.periode.type === context.periode.type && parsed.periode.type !== 'week' && parsed.periode.type !== 'month'
          ? this.getPreviousPeriode(context.periode.type)
          : parsed.periode,
        typeDonnees: parsed.typeDonnees || context.typeDonnees,
        gare: parsed.gare || context.gare,
        ligne: parsed.ligne || context.ligne
      };
    }
    
    return parsed;
  }

  getPreviousPeriode(periodeType) {
    const translations = {
      'today': 'yesterday',
      'yesterday': 'dayBeforeYesterday',
      'week': 'lastWeek',
      'lastWeek': 'twoWeeksAgo',
      'month': 'lastMonth',
      'lastMonth': 'twoMonthsAgo',
      'year': 'lastYear'
    };
    
    const type = translations[periodeType] || 'week';
    const maintenant = moment();
    
    switch (type) {
      case 'yesterday':
        return { type, start: maintenant.subtract(1, 'day').startOf('day').format('YYYY-MM-DD'), end: maintenant.endOf('day').format('YYYY-MM-DD') };
      case 'lastWeek':
        return { type, start: maintenant.subtract(1, 'week').startOf('week').format('YYYY-MM-DD'), end: maintenant.subtract(1, 'week').endOf('week').format('YYYY-MM-DD') };
      case 'lastMonth':
        return { type, start: maintenant.subtract(1, 'month').startOf('month').format('YYYY-MM-DD'), end: maintenant.subtract(1, 'month').endOf('month').format('YYYY-MM-DD') };
      case 'lastYear':
        return { type, start: maintenant.subtract(1, 'year').startOf('year').format('YYYY-MM-DD'), end: maintenant.subtract(1, 'year').endOf('year').format('YYYY-MM-DD') };
      default:
        return { type: 'week', start: maintenant.startOf('week').format('YYYY-MM-DD'), end: maintenant.endOf('week').format('YYYY-MM-DD') };
    }
  }

  generateContextualResponse(previousResponse, currentParsed, newResults) {
    const parts = [];
    
    if (currentParsed.isFollowUp && previousResponse) {
      parts.push(`Voici les données pour la période précédente:`);
    }
    
    parts.push(this.formatResults(newResults, currentParsed));
    
    return parts.join('\n');
  }

  formatResults(results, parsed) {
    if (!results || results.length === 0) {
      return 'Aucune donnée disponible pour cette requête.';
    }

    if (parsed.aggregation === 'COUNT') {
      return `Nombre total: ${results[0].total || results[0].count || results.length}`;
    }
    
    if (parsed.aggregation === 'AVG') {
      const value = results[0].moyenne || results[0].average;
      return `Moyenne: ${value ? value.toFixed(2) : 'N/A'}`;
    }

    const value = results[0].total || results[0].somme || results[0].montant;
    if (value !== undefined) {
      return `Total: ${parseFloat(value).toFixed(2)} DA`;
    }

    return JSON.stringify(results, null, 2);
  }
}

module.exports = new NLPEngine();