import { Test, TestingModule } from '@nestjs/testing';
import { TenantMiddleware } from './tenant.middleware';
import { PrismaService } from '../../prisma/prisma.service';

describe('TenantMiddleware', () => {
  let middleware: TenantMiddleware;
  let mockPrisma: { setTenantId: jest.Mock };
  let mockNext: jest.Mock;
  let mockRes: Partial<Record<string, unknown>>;

  beforeEach(async () => {
    jest.clearAllMocks();

    mockPrisma = {
      setTenantId: jest.fn().mockResolvedValue(undefined),
    };

    mockNext = jest.fn();
    mockRes = {};

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        TenantMiddleware,
        {
          provide: PrismaService,
          useValue: mockPrisma,
        },
      ],
    }).compile();

    middleware = module.get<TenantMiddleware>(TenantMiddleware);
  });

  it('should call setTenantId when user has clubId', async () => {
    const req = { user: { clubId: 'club-001' } } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).toHaveBeenCalledTimes(1);
    expect(mockPrisma.setTenantId).toHaveBeenCalledWith('club-001');
    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should always call next()', async () => {
    const req = { user: { clubId: 'club-001' } } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should not call setTenantId when there is no user on request', async () => {
    const req = {} as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).not.toHaveBeenCalled();
    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should not call setTenantId when user has no clubId', async () => {
    const req = { user: { name: 'John' } } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).not.toHaveBeenCalled();
    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should not call setTenantId when user is undefined', async () => {
    const req = { user: undefined } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).not.toHaveBeenCalled();
    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should not call setTenantId when user is null', async () => {
    const req = { user: null } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).not.toHaveBeenCalled();
    expect(mockNext).toHaveBeenCalledTimes(1);
  });

  it('should call next() even after setTenantId succeeds', async () => {
    mockPrisma.setTenantId.mockResolvedValue(undefined);
    const req = { user: { clubId: 'club-xyz' } } as any;

    await middleware.use(req, mockRes as any, mockNext);

    expect(mockPrisma.setTenantId).toHaveBeenCalledWith('club-xyz');
    expect(mockNext).toHaveBeenCalledTimes(1);
  });
});
