import { computed, signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { provideRouter, Router, UrlTree } from '@angular/router';

import { AuthService } from './auth.service';
import { authGuard, guestOnlyGuard } from './auth.guards';

function createAuthServiceStub(isAuthenticated = false) {
  const tokenState = signal<string | null>(isAuthenticated ? 'jwt-token' : null);

  return {
    isAuthenticated: computed(() => tokenState() !== null)
  };
}

describe('auth guards', () => {
  beforeEach(() => {
    TestBed.resetTestingModule();
  });

  it('redirects unauthenticated users to /login', () => {
    TestBed.configureTestingModule({
      providers: [provideRouter([]), { provide: AuthService, useValue: createAuthServiceStub() }]
    });

    const result = TestBed.runInInjectionContext(() =>
      authGuard(null as never, { url: '/checkout/25' } as never),
    );

    expect(result instanceof UrlTree).toBe(true);
    expect(TestBed.inject(Router).serializeUrl(result as UrlTree)).toBe(
      '/login?returnUrl=%2Fcheckout%2F25',
    );
  });

  it('allows authenticated users through authGuard', () => {
    TestBed.configureTestingModule({
      providers: [provideRouter([]), { provide: AuthService, useValue: createAuthServiceStub(true) }]
    });

    const result = TestBed.runInInjectionContext(() =>
      authGuard(null as never, { url: '/checkout/25' } as never),
    );

    expect(result).toBe(true);
  });

  it('redirects authenticated users away from guest routes', () => {
    TestBed.configureTestingModule({
      providers: [provideRouter([]), { provide: AuthService, useValue: createAuthServiceStub(true) }]
    });

    const result = TestBed.runInInjectionContext(() => guestOnlyGuard(null as never, null as never));

    expect(result instanceof UrlTree).toBe(true);
    expect(TestBed.inject(Router).serializeUrl(result as UrlTree)).toBe('/');
  });

  it('allows guests into login/register routes', () => {
    TestBed.configureTestingModule({
      providers: [provideRouter([]), { provide: AuthService, useValue: createAuthServiceStub() }]
    });

    const result = TestBed.runInInjectionContext(() => guestOnlyGuard(null as never, null as never));

    expect(result).toBe(true);
  });
});
