import {
  HttpErrorResponse,
  HttpEvent,
  HttpHandler,
  HttpInterceptor,
  HttpRequest,
} from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, throwError, BehaviorSubject } from 'rxjs';
import { catchError, switchMap, filter, take } from 'rxjs/operators';
import { AuthenticationService } from 'src/app/core/services/authentication.service';
import { ToastService } from 'src/app/services/toast.service';
import { environment } from '../../environments/environment';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class GlobalHttpInterceptor implements HttpInterceptor {
  private isRefreshing = false;
  private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
  private isRedirecting = false;

  constructor(
    private authService: AuthenticationService,
    private toast: ToastService,
    private router: Router
  ) {}

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    console.log(`🌐 Intercepteur - Requête vers: ${req.url}`);

    // Ne pas intercepter les requêtes de refresh token, login et user
    const publicPaths = ['/refresh', '/login', '/register', '/forgot-password', '/user'];
    if (publicPaths.some(path => req.url.includes(path))) {
      console.log(`⚪ Requête publique ignorée (pas d'interception): ${req.url}`);
      return next.handle(req);
    }

    // Vérifier si la requête nécessite une authentification
    const requiresAuth = this.requiresAuth(req.url);
    console.log(`🔐 Nécessite authentification: ${requiresAuth}`);

    if (requiresAuth) {
      const authState = this.authService.getCurrentAuthState();
      console.log(`👤 État auth:`, {
        hasState: !!authState,
        hasToken: !!authState?.token,
        hasAccessToken: !!authState?.token?.accessToken,
        accessTokenPreview: authState?.token?.accessToken?.substring(0, 20) + '...'
      });

      if (authState && authState.token && authState.token.accessToken) {
        const reqCloned = this.addAuthToRequest(req, authState.token.accessToken);
        console.log(`✅ Headers ajoutés à la requête (Bearer + X-API-KEY)`);

        return next.handle(reqCloned).pipe(
          catchError((error: HttpErrorResponse) => {
            console.log(`❌ Erreur HTTP ${error.status} sur ${req.url}`);
            console.log(`❌ Détails erreur:`, error);

            // Gérer les erreurs 401 ET 403 avec message d'auth
            const isAuthError = error.status === 401 ||
              (error.status === 403 && error.error?.message === 'auth.user_unauthorized');

            if (isAuthError) {
              // Vérifier si cette requête a déjà été retryée après refresh
              const hasBeenRetried = req.headers.has('X-Retry-After-Refresh');
              console.log(`🔍 ${error.status} détecté - hasBeenRetried: ${hasBeenRetried}`);

              if (hasBeenRetried) {
                // Si déjà retryée et encore 401/403, rediriger vers login
                console.error(`❌ ${error.status} après refresh token - redirection vers login`);
                this.toast.showError('Session expirée. Veuillez vous reconnecter.');
                this.redirectToLogin();
                return throwError(() => new Error('Authentication failed after token refresh'));
              }

              console.log(`🔄 Tentative de gestion du ${error.status} avec refresh token`);
              return this.handle401Error(reqCloned, next);
            }
            return this.handleHttpError(error);
          })
        );
      } else {
        // Si pas de token, rediriger vers login
        console.error(`❌ Pas de token valide - redirection vers login`);
        this.redirectToLogin();
        return throwError(() => new Error('Unauthorized - No valid token'));
      }
    }

    // Pour les requêtes qui ne nécessitent pas d'auth
    console.log(`⚪ Requête sans auth requise`);
    const modified = req.clone({
      reportProgress: true,
    });

    return next.handle(modified).pipe(
      catchError((error: HttpErrorResponse) => {
        return this.handleHttpError(error);
      })
    );
  }

  /**
   * Gérer les erreurs 401 avec retry après refresh token
   */
  private handle401Error(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      const token = this.authService.currentToken;

      if (token && token.refreshToken) {
        console.log('🔄 Tentative de rafraîchissement du token...');
        return this.authService.refreshToken().pipe(
          switchMap((newToken: any) => {
            this.isRefreshing = false;
            this.refreshTokenSubject.next(newToken.accessToken);

            console.log('✅ Token rafraîchi - retry de la requête');
            // Marquer la requête comme retryée après refresh
            const retryRequest = this.addAuthToRequest(request, newToken.accessToken).clone({
              setHeaders: { 'X-Retry-After-Refresh': 'true' }
            });

            return next.handle(retryRequest);
          }),
          catchError((error) => {
            this.isRefreshing = false;
            console.error('❌ Échec du refresh token - redirection vers login');
            this.toast.showError('Session expirée. Veuillez vous reconnecter.');
            this.redirectToLogin();
            return throwError(() => error);
          })
        );
      } else {
        this.isRefreshing = false;
        console.warn('⚠️ Pas de refresh token disponible - redirection vers login');
        this.redirectToLogin();
        return throwError(() => new Error('No refresh token available'));
      }
    } else {
      // Si un refresh est déjà en cours, attendre qu'il se termine
      console.log('⏳ Refresh en cours - mise en attente de la requête');
      return this.refreshTokenSubject.pipe(
        filter(token => token !== null),
        take(1),
        switchMap((token) => {
          // Marquer aussi les requêtes en attente comme retryées
          const retryRequest = this.addAuthToRequest(request, token).clone({
            setHeaders: { 'X-Retry-After-Refresh': 'true' }
          });
          return next.handle(retryRequest);
        })
      );
    }
  }

  /**
   * Rediriger vers la page de login
   */
  private redirectToLogin(): void {
    // Éviter les appels multiples simultanés
    if (this.isRedirecting) {
      console.log('⚠️ Redirection déjà en cours, skip');
      return;
    }

    // Éviter une boucle infinie si on est déjà sur la page de login
    if (this.router.url.includes('/login')) {
      console.log('⚠️ Déjà sur la page de login, skip redirection');
      return;
    }

    this.isRedirecting = true;
    console.log('🚪 redirectToLogin() appelée');

    // Nettoyer immédiatement l'état d'authentification
    this.authService.logout().subscribe({
      next: () => {
        console.log('🚪 Logout réussi, navigation vers /login');
        this.router.navigate(['/login']).then(success => {
          if (success) {
            console.log('✅ Navigation vers /login réussie');
            this.isRedirecting = false;
          } else {
            console.error('❌ Navigation vers /login échouée, fallback vers window.location');
            // Fallback: forcer la navigation
            window.location.href = '/login';
          }
        }).catch(err => {
          console.error('❌ Erreur navigation:', err);
          window.location.href = '/login';
        });
      },
      error: (err) => {
        console.error('❌ Erreur lors du logout:', err);
        // Même en cas d'erreur, rediriger vers login
        this.router.navigate(['/login']).catch(() => {
          console.error('❌ Fallback: utilisation de window.location');
          window.location.href = '/login';
        });
      }
    });
  }
  
  /**
   * Vérifier si une URL nécessite une authentification
   */
  private requiresAuth(url: string): boolean {
    // URLs qui ne nécessitent PAS d'authentification
    const publicUrls = [
      'auth/login',
      'auth/register',
      'auth/forgot-password',
      'auth/reset-password',
      'public/'
    ];

    // Si l'URL est publique, pas besoin d'auth
    if (publicUrls.some(pattern => url.includes(pattern))) {
      return false;
    }

    // Toutes les requêtes vers les API nécessitent une authentification
    return url.includes(environment.API_URL) ||
           url.includes(environment.DATA_URL) ||
           url.includes(environment.AUTH_URL) ||
           url.includes('/v1/') ||
           url.includes('/api/');
  }

  /**
   * Ajouter les informations d'authentification à la requête
   */
  private addAuthToRequest(req: HttpRequest<any>, token: string): HttpRequest<any> {
    // Déterminer la bonne API key selon l'URL
    let apiKey = environment.X_APY_KEY; // Par défaut CHAPS

    console.log('🔍 URL de la requête:', req.url);
    console.log('🔍 Contient DATA_URL?', req.url.includes(environment.DATA_URL));
    console.log('🔍 DATA_URL:', environment.DATA_URL);

    if (req.url.includes(environment.DATA_URL)) {
      apiKey = environment.DATA_APY_KEY; // ESTAIR
      console.log('✅ Utilisation de DATA_APY_KEY pour ESTAIR');
    } else if (req.url.includes(environment.AUTH_URL)) {
      apiKey = environment.AUTH_APY_KEY; // AUTH
      console.log('✅ Utilisation de AUTH_APY_KEY pour AUTH');
    } else {
      console.log('✅ Utilisation de X_APY_KEY pour CHAPS (défaut)');
    }

    console.log('🔑 API Key utilisée (10 premiers car.):', apiKey.substring(0, 10) + '...');

    // Headers à ajouter
    const headers: { [key: string]: string } = {
      'Authorization': `Bearer ${token}`,
      'X-API-KEY': apiKey
    };

    console.log('📤 Headers qui seront ajoutés:', Object.keys(headers));

    // Ne pas ajouter Content-Type pour FormData (le navigateur le gère automatiquement avec boundary)
    if (!(req.body instanceof FormData)) {
      headers['Content-Type'] = 'application/json';
    }

    // Ajouter account_uuid comme query param sur ESTAIR/CHAPS (pas AUTH)
    let params = req.params;
    if (!req.url.includes(environment.AUTH_URL)) {
      const user = this.authService.currentUser;
      if (user?.account_uuid) {
        params = params.set('account_uuid', user.account_uuid);
      }
    }

    return req.clone({
      setHeaders: headers,
      params: params
    });
  }

  /**
   * Gérer les erreurs HTTP
   */
  private handleHttpError(error: HttpErrorResponse): Observable<never> {
    let errorMsg = '';

    if (error.error instanceof ErrorEvent) {
      // Erreur côté client
      console.log('Client-side error:', error.error.message);
      errorMsg = `Error: ${error.error.message}`;
      this.toast.showError('Erreur de connexion réseau');
    } else {
      // Erreur côté serveur
      console.log('Server-side error:', error.status, error.message);
      errorMsg = `Error Code: ${error.status}, Message: ${error.message}`;

      if (error.status === 403) {
        // Ne pas afficher d'erreur pour 403 auth (géré par l'interceptor)
        if (error.error?.message !== 'auth.user_unauthorized') {
          this.toast.showError('Accès interdit');
        }
      } else if (error.status === 404) {
        // Ne pas afficher d'erreur pour 404, laisser le composant gérer
      } else if (error.status >= 500) {
        this.toast.showError("Erreur serveur, merci de contacter l'administrateur");
      } else if (error.status === 0) {
        // Erreur de connexion réseau
        this.toast.showError('Impossible de contacter le serveur');
      }
    }

    console.error('HTTP Error:', errorMsg);
    return throwError(() => error);
  }
}
