import { TestBed } from '@angular/core/testing';
import { HttpClient, provideHttpClient, withInterceptors } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { provideRouter, Router } from '@angular/router';
import { MatSnackBar } from '@angular/material/snack-bar';
import { errorInterceptor } from './error-interceptor';
import { AuthStore } from '../auth/auth-store';

describe('errorInterceptor', () => {
  let httpMock: HttpTestingController;
  let httpClient: HttpClient;
  let authStore: AuthStore;
  let router: Router;
  let snackBar: MatSnackBar;

  beforeEach(() => {
    localStorage.clear();
    TestBed.configureTestingModule({
      providers: [
        provideHttpClient(withInterceptors([errorInterceptor])),
        provideHttpClientTesting(),
        provideRouter([]),
      ],
    });
    httpMock = TestBed.inject(HttpTestingController);
    httpClient = TestBed.inject(HttpClient);
    authStore = TestBed.inject(AuthStore);
    router = TestBed.inject(Router);
    snackBar = TestBed.inject(MatSnackBar);
  });

  afterEach(() => {
    httpMock.verify();
  });

  it('clears the session and redirects to login on a 401 response', () => {
    authStore.setSession('abc123', { id: 1, email: 'a@b.de', firstName: 'A', lastName: 'B' });
    const navigateSpy = vi.spyOn(router, 'navigate');

    httpClient.get('/secure').subscribe({ error: () => undefined });
    httpMock
      .expectOne('/secure')
      .flush('unauthorized', { status: 401, statusText: 'Unauthorized' });

    expect(authStore.isLoggedIn()).toBe(false);
    expect(navigateSpy).toHaveBeenCalledWith(['/auth/login']);
  });

  it('shows the backend message for other 4xx errors without clearing the session', () => {
    authStore.setSession('abc123', { id: 1, email: 'a@b.de', firstName: 'A', lastName: 'B' });
    const navigateSpy = vi.spyOn(router, 'navigate');
    const snackSpy = vi.spyOn(snackBar, 'open');

    httpClient.get('/secure').subscribe({ error: () => undefined });
    httpMock
      .expectOne('/secure')
      .flush(
        { message: 'Ungültige Eingabe.' },
        { status: 422, statusText: 'Unprocessable Entity' },
      );

    expect(snackSpy).toHaveBeenCalledWith('Ungültige Eingabe.', 'OK', { duration: 5000 });
    expect(authStore.isLoggedIn()).toBe(true);
    expect(navigateSpy).not.toHaveBeenCalled();
  });

  it('shows a generic message for 4xx errors without a backend message', () => {
    const snackSpy = vi.spyOn(snackBar, 'open');

    httpClient.get('/secure').subscribe({ error: () => undefined });
    httpMock.expectOne('/secure').flush(null, { status: 404, statusText: 'Not Found' });

    expect(snackSpy).toHaveBeenCalledWith('Es ist ein Fehler aufgetreten.', 'OK', {
      duration: 5000,
    });
  });

  it('shows a generic message for 5xx errors without clearing the session', () => {
    authStore.setSession('abc123', { id: 1, email: 'a@b.de', firstName: 'A', lastName: 'B' });
    const navigateSpy = vi.spyOn(router, 'navigate');
    const snackSpy = vi.spyOn(snackBar, 'open');

    httpClient.get('/secure').subscribe({ error: () => undefined });
    httpMock
      .expectOne('/secure')
      .flush('server error', { status: 500, statusText: 'Server Error' });

    expect(snackSpy).toHaveBeenCalledWith(
      'Es ist ein Fehler aufgetreten. Bitte versuche es später erneut.',
      'OK',
      { duration: 5000 },
    );
    expect(authStore.isLoggedIn()).toBe(true);
    expect(navigateSpy).not.toHaveBeenCalled();
  });
});
