//! Service CSRF pour la protection contre les attaques Cross-Site Request Forgery
//!
//! Ce service gère:
//! - Récupération des tokens CSRF depuis les cookies
//! - Envoi des tokens CSRF dans les requêtes
//! - Gestion des erreurs CSRF

import { ApiError } from '@/types';

export class CsrfService {
  private static instance: CsrfService;
  private csrfToken: string | null = null;
  private tokenExpiry: number | null = null;

  private constructor() {
    this.loadCsrfToken();
  }

  public static getInstance(): CsrfService {
    if (!CsrfService.instance) {
      CsrfService.instance = new CsrfService();
    }
    return CsrfService.instance;
  }

  /**
   * Charge le token CSRF depuis les cookies
   */
  private loadCsrfToken(): void {
    try {
      // Le token CSRF est stocké dans un cookie httpOnly
      // On doit le récupérer via une requête spéciale
      this.fetchCsrfToken();
    } catch (error) {
      console.warn('Erreur lors du chargement du token CSRF:', error);
    }
  }

  /**
   * Récupère le token CSRF depuis le serveur
   */
  private async fetchCsrfToken(): Promise<void> {
    try {
      const response = await fetch('/api/v1/csrf-token', {
        method: 'GET',
        credentials: 'include', // Important pour les cookies
        headers: {
          'Content-Type': 'application/json',
        },
      });

      if (!response.ok) {
        throw new Error(`Erreur HTTP: ${response.status}`);
      }

      const data = await response.json();
      this.csrfToken = data.csrf_token;
      this.tokenExpiry = data.expires_at
        ? new Date(data.expires_at).getTime()
        : null;

      console.debug('Token CSRF chargé:', this.csrfToken);
    } catch (error) {
      console.error('Erreur lors de la récupération du token CSRF:', error);
      throw new ApiError('Impossible de récupérer le token CSRF', 'CSRF_ERROR');
    }
  }

  /**
   * Obtient le token CSRF actuel
   */
  public getCsrfToken(): string | null {
    // Vérifier si le token est expiré
    if (this.tokenExpiry && Date.now() > this.tokenExpiry) {
      console.warn('Token CSRF expiré, rechargement...');
      this.csrfToken = null;
      this.tokenExpiry = null;
    }

    return this.csrfToken;
  }

  /**
   * Force le rechargement du token CSRF
   */
  public async refreshCsrfToken(): Promise<void> {
    this.csrfToken = null;
    this.tokenExpiry = null;
    await this.fetchCsrfToken();
  }

  /**
   * Vérifie si un token CSRF est disponible
   */
  public hasCsrfToken(): boolean {
    return this.getCsrfToken() !== null;
  }

  /**
   * Obtient les headers CSRF pour les requêtes
   */
  public getCsrfHeaders(): Record<string, string> {
    const token = this.getCsrfToken();
    if (!token) {
      return {};
    }

    return {
      'X-CSRF-Token': token,
    };
  }

  /**
   * Gère les erreurs CSRF
   */
  public handleCsrfError(error: any): void {
    if (error?.code === 'CSRF_ERROR' || error?.message?.includes('CSRF')) {
      console.warn('Erreur CSRF détectée, rechargement du token...');
      this.refreshCsrfToken();
    }
  }

  /**
   * Nettoie le token CSRF (lors de la déconnexion)
   */
  public clearCsrfToken(): void {
    this.csrfToken = null;
    this.tokenExpiry = null;
  }
}

// Instance singleton
export const csrfService = CsrfService.getInstance();
