/**
 * Tests for noLocalAuthGuard.
 *
 * This guard gates the `/auth` route group:
 * - 'password' strategy → returns true (allow, local login form is reachable).
 * - 'authorization-code' strategy → redirects to hub launcher (window.location.href)
 *   and returns false (no local login allowed).
 *
 * It must NOT depend on AuthenticationService (unauthenticated users must be
 * redirected before they ever see the form).
 */
import '@angular/compiler';
import { Injector, runInInjectionContext } from '@angular/core';
import type { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { vi } from 'vitest';

// vi.mock is hoisted so the factory must be self-contained.
// We export the mock object via a module-level variable that the factory closes over,
// then mutate it per-test to simulate each deploy variant.
vi.mock('environments/environment', () => ({
  environment: {
    api: { rest: 'http://localhost:8080/api', graphql: 'http://localhost:8080/graphql' },
    authStrategy: 'password' as 'password' | 'authorization-code',
    lang: { base: 'es', fallback: 'es', langs: ['es', 'en'] },
    oAuth: { applicationCode: 'aurora', applicationSecret: 'secret' },
    production: false,
    debug: false,
  },
}));

// Import AFTER mock is set up so the guard's closure uses the mock object.
import { environment } from 'environments/environment';
import { noLocalAuthGuard } from './no-local-auth.guard';

const fakeRoute = {} as ActivatedRouteSnapshot;
const fakeState = { url: '/auth/sign-in' } as RouterStateSnapshot;

function runGuard(): boolean {
  const injector = Injector.create({ providers: [] });
  return runInInjectionContext(injector, () => noLocalAuthGuard(fakeRoute, fakeState)) as boolean;
}

describe('noLocalAuthGuard — password strategy', () => {
  beforeEach(() => {
    // Mutate the mock object the guard already holds a reference to
    (environment as { authStrategy: string }).authStrategy = 'password';
  });

  it('allows access (returns true) so local login form is reachable', () => {
    const result = runGuard();
    expect(result).toBe(true);
  });

  it('does NOT touch window.location.href', () => {
    let hrefWasSet = false;
    vi.stubGlobal('location', {
      ...window.location,
      set href(_v: string) {
        hrefWasSet = true;
      },
    });

    runGuard();

    expect(hrefWasSet).toBe(false);
    vi.unstubAllGlobals();
  });
});

describe('noLocalAuthGuard — authorization-code strategy', () => {
  beforeEach(() => {
    (environment as { authStrategy: string }).authStrategy = 'authorization-code';
  });

  it('returns false (blocks the route) when strategy is authorization-code', () => {
    vi.stubGlobal('location', {
      ...window.location,
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      set href(_v: string) {},
    });

    const result = runGuard();

    expect(result).toBe(false);
    vi.unstubAllGlobals();
  });

  it('redirects to the hub launcher URL via window.location.href', () => {
    let assignedHref = '';
    vi.stubGlobal('location', {
      ...window.location,
      get href() {
        return assignedHref;
      },
      set href(v: string) {
        assignedHref = v;
      },
    });

    runGuard();

    expect(assignedHref).toBe(`${environment.api.rest}/auth/login`);
    vi.unstubAllGlobals();
  });

  it('hub URL does NOT contain a redirectURL pointing back to /auth (avoids double-redirect)', () => {
    let assignedHref = '';
    vi.stubGlobal('location', {
      ...window.location,
      get href() {
        return assignedHref;
      },
      set href(v: string) {
        assignedHref = v;
      },
    });

    runGuard();

    // Must not ask the hub to redirect back to /auth after auth — that would
    // bring the user to a route that is blocked by this same guard.
    expect(assignedHref).not.toContain('redirectURL');
    vi.unstubAllGlobals();
  });
});
