import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios';
import { TokenStorage } from '../tokenStorage';
import { refreshToken } from '../tokenRefresh';

/**
 * Client API avec interceptors pour refresh automatique des tokens
 * T0177: Interceptor axios pour détecter 401 et refresh automatique
 */

// Configuration de base
const API_BASE_URL =
  import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080/api/v1';

// Client API réutilisable
export const apiClient = axios.create({
  baseURL: API_BASE_URL,
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Flag pour éviter les refresh en boucle
let isRefreshing = false;
let failedQueue: Array<{
  resolve: (value?: any) => void;
  reject: (error?: any) => void;
}> = [];

// T0177: Fonction pour traiter la queue de requêtes en attente
const processQueue = (error: Error | null, token: string | null = null) => {
  failedQueue.forEach(prom => {
    if (error) {
      prom.reject(error);
    } else {
      prom.resolve(token);
    }
  });

  failedQueue = [];
};

// T0177: Interceptor de requête pour ajouter le token d'accès
apiClient.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    const token = TokenStorage.getAccessToken();
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// T0177: Interceptor de réponse pour détecter 401 et refresh automatique
apiClient.interceptors.response.use(
  (response) => {
    return response;
  },
  async (error: AxiosError) => {
    const originalRequest = error.config as InternalAxiosRequestConfig & {
      _retry?: boolean;
    };

    // T0177: Détecter 401 et refresh automatiquement
    if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
      // Éviter les refresh multiples simultanés
      if (isRefreshing) {
        // Si un refresh est en cours, mettre la requête en queue
        return new Promise((resolve, reject) => {
          failedQueue.push({ resolve, reject });
        })
          .then((token) => {
            if (originalRequest.headers) {
              originalRequest.headers.Authorization = `Bearer ${token}`;
            }
            return apiClient(originalRequest);
          })
          .catch((err) => {
            return Promise.reject(err);
          });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      try {
        // T0177: Refresh automatique du token
        await refreshToken();
        const newToken = TokenStorage.getAccessToken();
        
        if (newToken && originalRequest.headers) {
          originalRequest.headers.Authorization = `Bearer ${newToken}`;
        }

        // T0177: Traiter la queue et retry la requête originale
        processQueue(null, newToken);
        return apiClient(originalRequest);
      } catch (refreshError) {
        // T0177: Gérer cas refresh échoué
        // T0178: Rediriger vers login si refresh échoue et afficher message
        processQueue(refreshError as Error, null);
        
        // T0178: Nettoyer les tokens
        TokenStorage.clearTokens();
        
        // T0178: Stocker un message d'erreur pour l'afficher après redirection
        sessionStorage.setItem('auth_error', 'Your session has expired. Please log in again.');
        
        // T0178: Rediriger vers login si refresh échoue
        // Utiliser window.location pour forcer un rechargement complet et nettoyer l'état
        if (typeof window !== 'undefined') {
          window.location.href = '/login';
        }
        
        return Promise.reject(refreshError);
      } finally {
        isRefreshing = false;
      }
    }

    // T0178: Détecter les erreurs liées à l'expiration du token (header X-Token-Expired)
    if (error.response?.status === 401 && error.response.headers?.['x-token-expired'] === 'true') {
      // Token expiré détecté via header
      // Tenter le refresh automatique sera géré par le bloc ci-dessus lors du prochain 401
      // Pour l'instant, on laisse passer l'erreur pour que le refresh automatique se déclenche
    }

    return Promise.reject(error);
  }
);

