/**
 * @copyright 2026 NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

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

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private router = inject(Router);
  private http = inject(HttpClient);
  private toast = inject(ToastService);

  private isRefreshing = false;
  private refreshTokenSubject = new BehaviorSubject<boolean | null>(null);

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    // Clone the request to add withCredentials
    const authReq = request.clone({
      withCredentials: true
    });

    return next.handle(authReq).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status === 401 && !request.url.includes('/auth/refresh') && !request.url.includes('/auth/logout')) {
          return this.handle401Error(authReq, next);
        }

        // Show toast for other HTTP errors
        this.showErrorToast(error);
        return throwError(() => error);
      })
    );
  }

  private handle401Error(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    if (!this.isRefreshing) {
      this.isRefreshing = true;
      this.refreshTokenSubject.next(null);

      return this.http.post(
        `${environment.apiUrl}/auth/refresh`,
        {},
        { withCredentials: true }
      ).pipe(
        switchMap(() => {
          this.isRefreshing = false;
          this.refreshTokenSubject.next(true);
          return next.handle(request);
        }),
        catchError((err) => {
          this.isRefreshing = false;
          this.refreshTokenSubject.next(false);
          this.toast.error('Your session has expired. Please log in again.');
          this.router.navigate(['/']);
          return throwError(() => err);
        })
      );
    }

    return this.refreshTokenSubject.pipe(
      filter(result => result !== null),
      take(1),
      switchMap(success => {
        if (success) {
          return next.handle(request);
        }
        return throwError(() => new Error('Token refresh failed'));
      })
    );
  }

  private showErrorToast(error: HttpErrorResponse): void {
    let message = 'Something went wrong. Please try again.';

    switch (error.status) {
      case 400:
        message = error.error?.message || 'Invalid request. Please check your input.';
        break;
      case 403:
        message = 'You do not have permission to perform this action.';
        break;
      case 404:
        message = 'Resource not found.';
        break;
      case 500:
        message = 'Server error. Please try again later.';
        break;
      case 0:
        message = 'Network error. Please check your connection.';
        break;
    }

    this.toast.error(message);
  }
}