import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { AuthApi, RegistrationRequest } from './auth-api';
import { environment } from '../../../environments/environment';
import { User } from '../../models/user.model';

describe('AuthApi', () => {
  let service: AuthApi;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [provideHttpClient(), provideHttpClientTesting()],
    });
    service = TestBed.inject(AuthApi);
    httpMock = TestBed.inject(HttpTestingController);
  });

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

  it('posts credentials to the login endpoint', () => {
    const user: User = { id: 1, email: 'a@b.de', firstName: 'A', lastName: 'B' };

    service.login('a@b.de', 'secret').subscribe((response) => {
      expect(response).toEqual({ token: 'jwt-token', user });
    });

    const request = httpMock.expectOne(`${environment.apiUrl}auth/email/login`);
    expect(request.request.method).toBe('POST');
    expect(request.request.body).toEqual({ email: 'a@b.de', password: 'secret' });
    request.flush({ token: 'jwt-token', user });
  });

  it('fetches the current user from the me endpoint', () => {
    const user: User = { id: 1, email: 'a@b.de', firstName: 'A', lastName: 'B' };

    service.me().subscribe((response) => {
      expect(response).toEqual(user);
    });

    const request = httpMock.expectOne(`${environment.apiUrl}auth/me`);
    expect(request.request.method).toBe('GET');
    request.flush(user);
  });

  it('verifies an invitation token', () => {
    const invitation = { teamId: 5, teamName: 'Team A', playerId: 7, playerName: 'Alex' };

    service
      .verifyInvite('invite-token')
      .subscribe((response) => expect(response).toEqual(invitation));

    const request = httpMock.expectOne(`${environment.apiUrl}auth/verify-invite`);
    expect(request.request.method).toBe('POST');
    expect(request.request.body).toEqual({ token: 'invite-token' });
    request.flush(invitation);
  });

  it('registers with only the supported account fields', () => {
    const registrationWithLegacyField = {
      email: 'alex@example.de',
      password: 'secret1',
      firstName: 'Alex',
      lastName: 'Muster',
      linkPlayerId: 7,
    };

    service.register(registrationWithLegacyField as RegistrationRequest).subscribe();

    const request = httpMock.expectOne(`${environment.apiUrl}auth/email/register`);
    expect(request.request.method).toBe('POST');
    expect(request.request.body).toEqual({
      email: 'alex@example.de',
      password: 'secret1',
      firstName: 'Alex',
      lastName: 'Muster',
    });
    request.flush(null);
  });

  it('requests a password reset email', () => {
    service.forgotPassword('alex@example.de').subscribe();

    const request = httpMock.expectOne(`${environment.apiUrl}auth/forgot/password`);
    expect(request.request.body).toEqual({ email: 'alex@example.de' });
    request.flush(null);
  });

  it('sets a new password using a reset hash', () => {
    service.resetPassword('reset-hash', 'new-secret').subscribe();

    const request = httpMock.expectOne(`${environment.apiUrl}auth/reset/password`);
    expect(request.request.body).toEqual({ hash: 'reset-hash', password: 'new-secret' });
    request.flush(null);
  });

  it('creates a personalized team invitation', () => {
    const invitation = {
      teamId: 5,
      teamName: 'Team A',
      playerId: 7,
      playerName: 'Alex Muster',
    };
    service.createInvite(invitation).subscribe((response) => expect(response.token).toBe('invite'));

    const request = httpMock.expectOne(`${environment.apiUrl}auth/invite`);
    expect(request.request.method).toBe('POST');
    expect(request.request.body).toEqual(invitation);
    request.flush({ token: 'invite' });
  });

  it('updates the current profile', () => {
    const update = { firstName: 'Alex', lastName: 'Neu' };
    const user: User = { id: 1, email: 'a@b.de', ...update };
    service.updateProfile(update).subscribe((response) => expect(response).toEqual(user));

    const request = httpMock.expectOne(`${environment.apiUrl}auth/me`);
    expect(request.request.method).toBe('PATCH');
    expect(request.request.body).toEqual(update);
    request.flush(user);
  });
});
