/**
 * Service de cache pour les analytics Jira
 * Cache en mémoire avec invalidation manuelle et TTL
 */

import { JiraAnalytics } from '@/lib/types';
import { createHash } from 'crypto';

interface CacheEntry {
  data: JiraAnalytics;
  timestamp: number;
  projectKey: string;
  configHash: string; // Hash de la config Jira pour détecter les changements
  ttl: number; // Time To Live en millisecondes
}

class JiraAnalyticsCacheService {
  private cache = new Map<string, CacheEntry>();
  private readonly CACHE_KEY_PREFIX = 'jira-analytics:';
  private readonly DEFAULT_TTL = 30 * 60 * 1000; // 30 minutes par défaut
  private cleanupInterval: NodeJS.Timeout | null = null;

  /**
   * Génère une clé de cache basée sur la config Jira
   */
  private getCacheKey(projectKey: string, configHash: string): string {
    return `${this.CACHE_KEY_PREFIX}${projectKey}:${configHash}`;
  }

  /**
   * Génère un hash sécurisé de la configuration Jira pour détecter les changements
   */
  private generateConfigHash(config: {
    baseUrl: string;
    email: string;
    apiToken: string;
    projectKey: string;
  }): string {
    const configString = `${config.baseUrl}|${config.email}|${config.apiToken}|${config.projectKey}`;
    return createHash('sha256')
      .update(configString)
      .digest('hex')
      .substring(0, 16);
  }

  /**
   * Récupère les analytics depuis le cache si disponible et non expirées
   */
  get(config: {
    baseUrl: string;
    email: string;
    apiToken: string;
    projectKey: string;
  }): JiraAnalytics | null {
    const configHash = this.generateConfigHash(config);
    const cacheKey = this.getCacheKey(config.projectKey, configHash);

    const entry = this.cache.get(cacheKey);

    if (!entry) {
      console.log(`📋 Cache MISS pour projet ${config.projectKey}`);
      return null;
    }

    // Vérifier que la config n'a pas changé
    if (entry.configHash !== configHash) {
      console.log(
        `🔄 Config changée pour projet ${config.projectKey}, invalidation du cache`
      );
      this.cache.delete(cacheKey);
      return null;
    }

    // Vérifier si l'entrée a expiré
    const now = Date.now();
    const isExpired = now - entry.timestamp > entry.ttl;

    if (isExpired) {
      console.log(
        `⏰ Cache EXPIRÉ pour projet ${config.projectKey} (${this.getAgeDescription(entry.timestamp)})`
      );
      this.cache.delete(cacheKey);
      return null;
    }

    console.log(
      `✅ Cache HIT pour projet ${config.projectKey} (${this.getAgeDescription(entry.timestamp)}, expire dans ${this.getTimeUntilExpiry(entry.timestamp, entry.ttl)})`
    );
    return entry.data;
  }

  /**
   * Stocke les analytics dans le cache avec TTL personnalisé
   */
  set(
    config: {
      baseUrl: string;
      email: string;
      apiToken: string;
      projectKey: string;
    },
    data: JiraAnalytics,
    ttl?: number
  ): void {
    const configHash = this.generateConfigHash(config);
    const cacheKey = this.getCacheKey(config.projectKey, configHash);

    const entry: CacheEntry = {
      data,
      timestamp: Date.now(),
      projectKey: config.projectKey,
      configHash,
      ttl: ttl || this.DEFAULT_TTL,
    };

    this.cache.set(cacheKey, entry);
    console.log(
      `💾 Analytics mises en cache pour projet ${config.projectKey} (TTL: ${this.formatTTL(entry.ttl)})`
    );

    // Démarrer le nettoyage automatique si pas déjà fait
    this.startCleanupInterval();
  }

  /**
   * Invalide le cache pour un projet spécifique
   */
  invalidate(config: {
    baseUrl: string;
    email: string;
    apiToken: string;
    projectKey: string;
  }): void {
    const configHash = this.generateConfigHash(config);
    const cacheKey = this.getCacheKey(config.projectKey, configHash);

    const deleted = this.cache.delete(cacheKey);
    if (deleted) {
      console.log(`🗑️ Cache invalidé pour projet ${config.projectKey}`);
    } else {
      console.log(
        `ℹ️ Aucun cache à invalider pour projet ${config.projectKey}`
      );
    }
  }

  /**
   * Invalide tout le cache
   */
  invalidateAll(): void {
    const size = this.cache.size;
    this.cache.clear();
    console.log(
      `🗑️ Tout le cache analytics invalidé (${size} entrées supprimées)`
    );
  }

  /**
   * Retourne les statistiques du cache avec informations TTL
   */
  getStats(): {
    totalEntries: number;
    projects: Array<{
      projectKey: string;
      age: string;
      size: number;
      ttl: string;
      expiresIn: string;
      isExpired: boolean;
    }>;
  } {
    const now = Date.now();
    const projects = Array.from(this.cache.entries()).map(([, entry]) => ({
      projectKey: entry.projectKey,
      age: this.getAgeDescription(entry.timestamp),
      size: JSON.stringify(entry.data).length,
      ttl: this.formatTTL(entry.ttl),
      expiresIn: this.getTimeUntilExpiry(entry.timestamp, entry.ttl),
      isExpired: now - entry.timestamp > entry.ttl,
    }));

    return {
      totalEntries: this.cache.size,
      projects,
    };
  }

  /**
   * Formate l'âge d'une entrée de cache
   */
  private getAgeDescription(timestamp: number): string {
    const ageMs = Date.now() - timestamp;
    const ageMinutes = Math.floor(ageMs / (1000 * 60));
    const ageHours = Math.floor(ageMinutes / 60);

    if (ageHours > 0) {
      return `il y a ${ageHours}h${ageMinutes % 60}m`;
    } else if (ageMinutes > 0) {
      return `il y a ${ageMinutes}m`;
    } else {
      return 'maintenant';
    }
  }

  /**
   * Calcule le temps restant avant expiration
   */
  private getTimeUntilExpiry(timestamp: number, ttl: number): string {
    const now = Date.now();
    const remainingMs = ttl - (now - timestamp);

    if (remainingMs <= 0) return 'expiré';

    const remainingMinutes = Math.floor(remainingMs / (1000 * 60));
    const remainingHours = Math.floor(remainingMinutes / 60);

    if (remainingHours > 0) {
      return `${remainingHours}h${remainingMinutes % 60}m`;
    } else {
      return `${remainingMinutes}m`;
    }
  }

  /**
   * Formate un TTL en texte lisible
   */
  private formatTTL(ttl: number): string {
    const minutes = Math.floor(ttl / (1000 * 60));
    const hours = Math.floor(minutes / 60);

    if (hours > 0) {
      return `${hours}h${minutes % 60}m`;
    } else {
      return `${minutes}m`;
    }
  }

  /**
   * Démarre l'intervalle de nettoyage automatique
   */
  private startCleanupInterval(): void {
    if (this.cleanupInterval) return; // Déjà démarré

    // Nettoyer toutes les 5 minutes
    this.cleanupInterval = setInterval(
      () => {
        this.cleanupExpiredEntries();
      },
      5 * 60 * 1000
    );

    console.log(
      '🧹 Nettoyage automatique du cache démarré (toutes les 5 minutes)'
    );
  }

  /**
   * Nettoie les entrées expirées du cache
   */
  private cleanupExpiredEntries(): void {
    const now = Date.now();
    let cleanedCount = 0;

    for (const [key, entry] of this.cache.entries()) {
      if (now - entry.timestamp > entry.ttl) {
        this.cache.delete(key);
        cleanedCount++;
      }
    }

    if (cleanedCount > 0) {
      console.log(
        `🧹 Nettoyage automatique: ${cleanedCount} entrées expirées supprimées`
      );
    }
  }

  /**
   * Vérifie si une entrée existe pour un projet
   */
  has(config: {
    baseUrl: string;
    email: string;
    apiToken: string;
    projectKey: string;
  }): boolean {
    const configHash = this.generateConfigHash(config);
    const cacheKey = this.getCacheKey(config.projectKey, configHash);
    return this.cache.has(cacheKey);
  }

  /**
   * Arrête le nettoyage automatique
   */
  stopCleanupInterval(): void {
    if (this.cleanupInterval) {
      clearInterval(this.cleanupInterval);
      this.cleanupInterval = null;
      console.log('🛑 Nettoyage automatique du cache arrêté');
    }
  }

  /**
   * Force un nettoyage immédiat des entrées expirées
   */
  forceCleanup(): number {
    const beforeCount = this.cache.size;
    this.cleanupExpiredEntries();
    const afterCount = this.cache.size;
    const cleanedCount = beforeCount - afterCount;

    console.log(`🧹 Nettoyage forcé: ${cleanedCount} entrées supprimées`);
    return cleanedCount;
  }
}

// Instance singleton
export const jiraAnalyticsCache = new JiraAnalyticsCacheService();
