import { HttpHandlerFn, HttpInterceptorFn, HttpRequest } from '@angular/common/http'; import { inject } from '@angular/core'; import { throwError } from 'rxjs'; import { catchError, filter, switchMap, take } from 'rxjs/operators'; import { AuthService } from './auth.service'; export const AuthInterceptor: HttpInterceptorFn = (req: HttpRequest, next: HttpHandlerFn) => { const authService = inject(AuthService); const attachHeaders = (token: string | null) => { const activeRole = authService.getActiveRole(); return req.clone({ setHeaders: { authorization: token ?? '', 'active-role': activeRole?.code ?? '' } }); }; /** * Ejecuta el refresh del token y reintenta la petición original. * Si hay un refresh en curso, encola la petición hasta que el nuevo * token esté disponible. */ const refreshAndRetry = () => { if (authService.isRefreshing) { return authService.refreshTokenSubject.pipe( filter((token): token is string => token !== null), take(1), switchMap(token => next(attachHeaders(token))) ); } authService.isRefreshing = true; authService.refreshTokenSubject.next(null); return authService.refreshAccessToken().pipe( switchMap(newToken => { authService.isRefreshing = false; return next(attachHeaders(newToken)); }), catchError(error => { authService.isRefreshing = false; return throwError(() => error); }) ); }; const token = authService.getToken(); // Refresh proactivo: el token existe pero ya expiró if (token && authService.isTokenExpired() && authService.getRefreshToken()) { return refreshAndRetry(); } // Flujo normal + fallback 401 por si el servidor rechaza el token return next(attachHeaders(token)).pipe( catchError(error => { if (error.status === 401 && authService.getRefreshToken()) { return refreshAndRetry(); } return throwError(() => error); }) ); };