import 'reflect-metadata';

import { ValidationPipe } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Test } from '@nestjs/testing';
import request from 'supertest';
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';

import { requestContextMiddleware } from '@adapters/http/RequestContext';
import { AuthenticationGuard } from '../auth/AuthenticationGuard';
import { AuthorizationGuard } from '../auth/AuthorizationGuard';
import { IDENTITY_SESSION_PORT_TOKEN } from '../auth/AuthProviders';
import { FeatureAvailabilityGuard } from '../policy/FeatureAvailabilityGuard';

describe('Team domain (HTTP, module-wiring)', () => {
  const originalEnv = { ...process.env };

  let app: import("@nestjs/common").INestApplication;

  beforeAll(async () => {
    vi.resetModules();

    process.env.GRIDPILOT_API_PERSISTENCE = 'inmemory';
    process.env.GRIDPILOT_API_BOOTSTRAP = 'true';
    delete process.env.DATABASE_URL;

    const { AppModule } = await import('../../app.module');

    const module = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = module.createNestApplication();

    // Ensure AsyncLocalStorage request context is present for getActorFromRequestContext()
    app.use(requestContextMiddleware);

    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
      }),
    );

    const reflector = new Reflector();
    const sessionPort = module.get(IDENTITY_SESSION_PORT_TOKEN);

    const authorizationService = {
      getRolesForUser: () => [],
    };

    const policyService = {
      getSnapshot: async () => ({
        policyVersion: 1,
        operationalMode: 'normal',
        maintenanceAllowlist: { view: [], mutate: [] },
        capabilities: {},
        loadedFrom: 'defaults',
        loadedAtIso: new Date(0).toISOString(),
      }),
    };

    app.useGlobalGuards(
      new AuthenticationGuard(sessionPort as never),
      new AuthorizationGuard(reflector, authorizationService as never),
      new FeatureAvailabilityGuard(reflector, policyService as never),
    );

    await app.init();
  }, 20_000);

  afterAll(async () => {
    await app?.close();

    process.env = originalEnv;
    vi.restoreAllMocks();
  });

  it('module compiles and app is initialized', () => {
    expect(app).toBeDefined();
    expect(app.getHttpServer()).toBeDefined();
  });

  it('allows public access to all teams (happy path)', async () => {
    await request(app.getHttpServer())
      .get('/teams/all')
      .expect(200);
  });

  it('returns leaderboard with non-zero ratings and wins', async () => {
    const response = await request(app.getHttpServer())
      .get('/teams/leaderboard')
      .expect(200);

    expect(response.body).toBeDefined();
    expect(response.body.teams).toBeDefined();
    expect(Array.isArray(response.body.teams)).toBe(true);
    
    // Verify that teams have non-zero ratings and wins
    if (response.body.teams.length > 0) {
      const team = response.body.teams[0];
      expect(team).toBeDefined();
      // Teams may have null ratings if they have no race results
      if (team.rating !== null) {
        expect(typeof team.rating).toBe('number');
        expect(team.rating).toBeGreaterThan(0);
        expect(team.totalWins).toBeGreaterThan(0);
        expect(team.totalRaces).toBeGreaterThan(0);
      }
    }
  });

  it('rejects unauthenticated actor on create team (401)', async () => {
    await request(app.getHttpServer())
      .post('/teams')
      .send({
        name: 'Test Team',
        tag: 'TST',
      })
      .expect(401);
  });
});