import { signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { of } from 'rxjs';
import { App } from './app';
import { AuthApi } from './core/auth/auth-api';
import { AuthStore } from './core/auth/auth-store';

describe('App', () => {
  const token = signal<string | null>(null);
  const updateUser = vi.fn();
  const meResponse = signal<Record<string, unknown>>({
    id: 1,
    email: 'a@b.de',
    firstName: 'Alex',
    lastName: 'Muster',
  });
  const me = vi.fn(() => of(meResponse()));
  const setSession = vi.fn();

  beforeEach(async () => {
    token.set(null);
    meResponse.set({ id: 1, email: 'a@b.de', firstName: 'Alex', lastName: 'Muster' });
    updateUser.mockClear();
    setSession.mockClear();
    me.mockClear();
    await TestBed.configureTestingModule({
      imports: [App],
      providers: [
        provideRouter([]),
        { provide: AuthStore, useValue: { token, updateUser, setSession } },
        { provide: AuthApi, useValue: { me } },
      ],
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(App);
    expect(fixture.componentInstance).toBeTruthy();
  });

  it('validates and refreshes a restored session on startup', () => {
    token.set('stored-token');

    TestBed.createComponent(App);

    expect(me).toHaveBeenCalled();
    expect(updateUser).toHaveBeenCalledWith({
      id: 1,
      email: 'a@b.de',
      firstName: 'Alex',
      lastName: 'Muster',
    });
  });

  it('replaces an expired stored token when me returns a refreshed token', () => {
    token.set('expired-token');
    meResponse.set({
      id: 1,
      email: 'a@b.de',
      firstName: 'Alex',
      lastName: 'Muster',
      token: 'refreshed-token',
    });

    TestBed.createComponent(App);

    expect(setSession).toHaveBeenCalledWith('refreshed-token', {
      id: 1,
      email: 'a@b.de',
      firstName: 'Alex',
      lastName: 'Muster',
    });
    expect(updateUser).not.toHaveBeenCalled();
  });
});
