import { TestBed } from '@angular/core/testing';
import { BehaviorSubject } from 'rxjs';
import { ActivatedRoute, convertToParamMap, provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { Shell } from './shell';
import { environment } from '../../../../environments/environment';
import { AuthStore } from '../../auth/auth-store';
import { Player } from '../../../models/player.model';

describe('Shell', () => {
  let httpMock: HttpTestingController;
  let authStore: AuthStore;
  let routeParams: BehaviorSubject<ReturnType<typeof convertToParamMap>>;

  beforeEach(async () => {
    localStorage.clear();
    routeParams = new BehaviorSubject(convertToParamMap({ id: '5' }));
    await TestBed.configureTestingModule({
      imports: [Shell],
      providers: [
        provideHttpClient(),
        provideHttpClientTesting(),
        provideRouter([]),
        {
          provide: ActivatedRoute,
          useValue: { paramMap: routeParams.asObservable() },
        },
      ],
    }).compileComponents();

    httpMock = TestBed.inject(HttpTestingController);
    authStore = TestBed.inject(AuthStore);
    authStore.setSession('token', { id: 42, email: 'a@b.de', firstName: 'A', lastName: 'B' });
  });

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

  it('renders the bottom navigation with four tabs', () => {
    const fixture = TestBed.createComponent(Shell);
    fixture.detectChanges();

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({
      id: 5,
      name: 'Team A',
      alias: 'a',
      balance: 0,
    });
    httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]);

    const links = fixture.nativeElement.querySelectorAll('.shell-bottom-nav__item');
    expect(links.length).toBe(4);
  });

  it('loads the team for the route id and shows its name in the header', async () => {
    const fixture = TestBed.createComponent(Shell);
    fixture.detectChanges();

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({
      id: 5,
      name: 'Team A',
      alias: 'a',
      balance: 0,
    });
    httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]);
    await fixture.whenStable();
    fixture.detectChanges();

    expect(fixture.nativeElement.querySelector('.shell-header')?.textContent).toContain('Team A');
  });

  it('shows a team switcher when the user belongs to more than one team', async () => {
    const players: Player[] = [
      {
        id: 1,
        firstName: 'A',
        lastName: 'B',
        balance: 0,
        active: true,
        team: { id: 5, name: 'Team A', alias: 'a', balance: 0 },
      },
      {
        id: 2,
        firstName: 'A',
        lastName: 'B',
        balance: 0,
        active: true,
        team: { id: 6, name: 'Team B', alias: 'b', balance: 0 },
      },
    ];

    const fixture = TestBed.createComponent(Shell);
    fixture.detectChanges();

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({
      id: 5,
      name: 'Team A',
      alias: 'a',
      balance: 0,
    });
    httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush(players);
    await fixture.whenStable();
    fixture.detectChanges();

    expect(fixture.nativeElement.querySelector('.shell-team-switcher')).toBeTruthy();
  });

  it('does not show a team switcher when the user belongs to only one team', async () => {
    const players: Player[] = [
      {
        id: 1,
        firstName: 'A',
        lastName: 'B',
        balance: 0,
        active: true,
        team: { id: 5, name: 'Team A', alias: 'a', balance: 0 },
      },
    ];

    const fixture = TestBed.createComponent(Shell);
    fixture.detectChanges();

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({
      id: 5,
      name: 'Team A',
      alias: 'a',
      balance: 0,
    });
    httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush(players);
    await fixture.whenStable();
    fixture.detectChanges();

    expect(fixture.nativeElement.querySelector('.shell-team-switcher')).toBeFalsy();
  });

  it('ignores missing, non-positive, fractional, and non-numeric team ids', () => {
    const fixture = TestBed.createComponent(Shell);
    fixture.detectChanges();

    httpMock.expectOne(`${environment.apiUrl}teams/5/overview`).flush({
      id: 5,
      name: 'Team A',
      alias: 'a',
      balance: 0,
    });
    httpMock.expectOne(`${environment.apiUrl}users/42/teams`).flush([]);

    for (const id of [null, '0', '-1', '1.5', 'abc']) {
      routeParams.next(convertToParamMap(id === null ? {} : { id }));
    }

    expect(httpMock.match((request) => request.url.includes('/teams/')).length).toBe(0);
  });
});
