import { describe, expect, it, vi } from 'vitest';
import { AuthenticationGuard } from './AuthenticationGuard';

function createExecutionContext(request: Record<string, unknown>) {
  return {
    switchToHttp: () => ({
      getRequest: () => request,
    }),
  };
}

describe('AuthenticationGuard', () => {
  it('attaches request.user.userId from session when missing', async () => {
    const request: unknown = {};
    const sessionPort = {
      getCurrentSession: vi.fn(async () => ({ token: 't', user: { id: 'user-1' } })),
    };

    const guard = new AuthenticationGuard(sessionPort as never);

    await expect(guard.canActivate(createExecutionContext(request as Record<string, unknown>) as never)).resolves.toBe(true);

    expect(sessionPort.getCurrentSession).toHaveBeenCalledTimes(1);
    expect((request as { user?: unknown }).user).toEqual({ userId: 'user-1' });
  });

  it('does not override request.user.userId if already present', async () => {
    const request: unknown = { user: { userId: 'already-set' } };
    const sessionPort = {
      getCurrentSession: vi.fn(async () => ({ token: 't', user: { id: 'user-1' } })),
    };

    const guard = new AuthenticationGuard(sessionPort as never);

    await expect(guard.canActivate(createExecutionContext(request as Record<string, unknown>) as never)).resolves.toBe(true);

    expect(sessionPort.getCurrentSession).not.toHaveBeenCalled();
    expect((request as { user?: unknown }).user).toEqual({ userId: 'already-set' });
  });

  it('leaves request.user undefined when no session exists', async () => {
    const request: unknown = {};
    const sessionPort = {
      getCurrentSession: vi.fn(async () => null),
    };

    const guard = new AuthenticationGuard(sessionPort as never);

    await expect(guard.canActivate(createExecutionContext(request as Record<string, unknown>) as never)).resolves.toBe(true);

    expect(sessionPort.getCurrentSession).toHaveBeenCalledTimes(1);
    expect((request as { user?: unknown }).user).toBeUndefined();
  });
});