import client from 'prom-client';

// Singleton pattern pour éviter les duplications
const globalForProm = globalThis as unknown as {
  promRegistry: client.Registry | undefined;
  httpRequestsTotal: client.Counter<string> | undefined;
  httpRequestDuration: client.Histogram<string> | undefined;
  httpErrorsTotal: client.Counter<string> | undefined;
  metricsInitialized: boolean | undefined;
};

// Registry singleton
export function getRegistry(): client.Registry {
  if (!globalForProm.promRegistry) {
    globalForProm.promRegistry = new client.Registry();
  }
  return globalForProm.promRegistry;
}

// Initialiser les métriques une seule fois
function ensureMetricsInitialized() {
  if (globalForProm.metricsInitialized) {
    return;
  }

  const register = getRegistry();

  // Métriques par défaut (CPU, mémoire, event loop, etc.)
  client.collectDefaultMetrics({ register });

  // Compteur de requêtes HTTP totales
  globalForProm.httpRequestsTotal = new client.Counter({
    name: 'http_requests_total',
    help: 'Total number of HTTP requests',
    labelNames: ['method', 'path', 'status_code'],
    registers: [register],
  });

  // Histogramme de durée des requêtes
  globalForProm.httpRequestDuration = new client.Histogram({
    name: 'http_request_duration_seconds',
    help: 'Duration of HTTP requests in seconds',
    labelNames: ['method', 'path', 'status_code'],
    buckets: [0.01, 0.05, 0.1, 0.3, 0.5, 0.7, 1, 2, 5, 10],
    registers: [register],
  });

  // Compteur d'erreurs HTTP
  globalForProm.httpErrorsTotal = new client.Counter({
    name: 'http_errors_total',
    help: 'Total number of HTTP errors (4xx and 5xx)',
    labelNames: ['method', 'path', 'status_code'],
    registers: [register],
  });

  globalForProm.metricsInitialized = true;
}

// Getters pour les métriques
export function getHttpRequestsTotal(): client.Counter<string> {
  ensureMetricsInitialized();
  return globalForProm.httpRequestsTotal!;
}

export function getHttpRequestDuration(): client.Histogram<string> {
  ensureMetricsInitialized();
  return globalForProm.httpRequestDuration!;
}

export function getHttpErrorsTotal(): client.Counter<string> {
  ensureMetricsInitialized();
  return globalForProm.httpErrorsTotal!;
}

// Fonction helper pour normaliser les paths (éviter haute cardinalité)
export function normalizePath(path: string): string {
  return path
    // Remplacer les UUIDs
    .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, ':id')
    // Remplacer les IDs numériques
    .replace(/\/\d+/g, '/:id')
    // Remplacer les codes de ticket
    .replace(/\/[A-Z0-9]{6,}/g, '/:code');
}

// Fonction pour enregistrer une requête HTTP
export function recordHttpRequest(
  method: string,
  path: string,
  statusCode: number,
  durationMs: number
): void {
  const normalizedPath = normalizePath(path);
  const labels = {
    method,
    path: normalizedPath,
    status_code: statusCode.toString(),
  };

  getHttpRequestsTotal().inc(labels);
  getHttpRequestDuration().observe(labels, durationMs / 1000);

  if (statusCode >= 400) {
    getHttpErrorsTotal().inc(labels);
  }
}

// Initialiser les métriques au chargement du module
ensureMetricsInitialized();
