import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TeamStore } from './team-store';
import { environment } from '../../../environments/environment';
import { Team } from '../../models/team.model';

describe('TeamStore', () => {
  let store: TeamStore;
  let httpMock: HttpTestingController;

  const team: Team = { id: 5, name: 'Team A', alias: 'team-a', balance: 100 };

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

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

  it('loads and exposes the active team', () => {
    store.loadTeam(5);
    expect(store.loading()).toBe(true);

    const request = httpMock.expectOne(`${environment.apiUrl}teams/5/overview`);
    request.flush(team);

    expect(store.loading()).toBe(false);
    expect(store.team()).toEqual(team);
  });

  it('does not reload for the same team id', () => {
    store.loadTeam(5);
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush(team);

    store.loadTeam(5);

    httpMock.expectNone(`${environment.apiUrl}teams/5/overview`);
  });

  it('reloads when the team id changes', () => {
    store.loadTeam(5);
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush(team);

    store.loadTeam(6);

    httpMock.expectOne(`${environment.apiUrl}teams/6/overview`).flush({ ...team, id: 6 });
    expect(store.team()?.id).toBe(6);
  });

  it('resets loading on error without throwing', () => {
    store.loadTeam(5);

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush('error', {
      status: 500,
      statusText: 'Server Error',
    });

    expect(store.loading()).toBe(false);
    expect(store.team()).toBeNull();
  });

  it('allows retrying the same team after a failed request', () => {
    store.loadTeam(5);
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush('error', {
      status: 500,
      statusText: 'Server Error',
    });

    store.loadTeam(5);
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush(team);

    expect(store.team()).toEqual(team);
    expect(store.loading()).toBe(false);
  });

  it('refreshes an already loaded team on demand', () => {
    store.loadTeam(5);
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush(team);

    store.refreshTeam();
    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({ ...team, balance: 200 });

    expect(store.team()?.balance).toBe(200);
  });

  it('discards a stale response when the requested team changes before it resolves', () => {
    store.loadTeam(5);
    const firstRequest = httpMock.expectOne(`${environment.apiUrl}teams/5/overview`);

    store.loadTeam(6);
    const secondRequest = httpMock.expectOne(`${environment.apiUrl}teams/6/overview`);

    // The second request supersedes the first via switchMap — Angular's test
    // harness refuses to flush a request once its subscription has been
    // cancelled, which is precisely the guarantee this test is after: a late
    // arriving stale response can never reach the store and overwrite it.
    expect(firstRequest.cancelled).toBe(true);

    secondRequest.flush({ ...team, id: 6 });

    expect(store.team()?.id).toBe(6);
  });
});
