import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from '../src/app.module';
import { ReportPeriod } from '../src/domain/value-objects';

describe('Reporting Service (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    app.setGlobalPrefix('api/v1');
    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
        transformOptions: {
          enableImplicitConversion: true,
        },
      }),
    );
    // TransformInterceptor and GlobalExceptionFilter are already registered in AppModule
    // Don't add them again to avoid double-wrapping responses
    await app.init();
  });

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

  describe('Health Check', () => {
    it('/api/v1/health (GET) should return ok status', () => {
      return request(app.getHttpServer())
        .get('/api/v1/health')
        .expect(200)
        .expect((res) => {
          // Response is wrapped by TransformInterceptor: { success: true, data: { ... }, timestamp: ... }
          expect(res.body.success).toBe(true);
          expect(res.body.data).toBeDefined();
          expect(res.body.data.status).toBe('ok');
          expect(res.body.data.service).toBe('reporting-service');
        });
    });

    it('/api/v1/health/ready (GET) should return ready status', () => {
      return request(app.getHttpServer())
        .get('/api/v1/health/ready')
        .expect(200)
        .expect((res) => {
          expect(res.body.success).toBe(true);
          expect(res.body.data).toBeDefined();
          expect(res.body.data.status).toBe('ready');
        });
    });
  });

  describe('Reports API', () => {
    describe('GET /api/v1/reports/definitions', () => {
      it('should return list of report definitions', () => {
        return request(app.getHttpServer())
          .get('/api/v1/reports/definitions')
          .expect(200)
          .expect((res) => {
            expect(res.body.success).toBe(true);
            expect(res.body.data).toBeDefined();
            expect(Array.isArray(res.body.data)).toBe(true);
          });
      });
    });

    describe('GET /api/v1/reports/definitions/:code', () => {
      it('should return 404 for non-existent report code', () => {
        return request(app.getHttpServer())
          .get('/api/v1/reports/definitions/NON_EXISTENT_CODE')
          .expect(404)
          .expect((res) => {
            expect(res.body.statusCode).toBe(404);
          });
      });
    });

    describe('POST /api/v1/reports/generate', () => {
      it('should validate request body', () => {
        return request(app.getHttpServer())
          .post('/api/v1/reports/generate')
          .send({})
          .expect(400);
      });

      it('should reject invalid report period', () => {
        return request(app.getHttpServer())
          .post('/api/v1/reports/generate')
          .send({
            reportCode: 'RPT_LEADERBOARD',
            reportPeriod: 'INVALID_PERIOD',
            startDate: '2024-01-01',
            endDate: '2024-01-31',
          })
          .expect(400);
      });

      it('should return 404 for non-existent report code', () => {
        return request(app.getHttpServer())
          .post('/api/v1/reports/generate')
          .send({
            reportCode: 'NON_EXISTENT',
            reportPeriod: ReportPeriod.DAILY,
            startDate: '2024-01-01',
            endDate: '2024-01-01',
          })
          .expect(404);
      });
    });

    describe('GET /api/v1/reports/snapshots', () => {
      it('should return empty array when no report code provided', () => {
        return request(app.getHttpServer())
          .get('/api/v1/reports/snapshots')
          .expect(200)
          .expect((res) => {
            expect(res.body.success).toBe(true);
            expect(res.body.data).toBeDefined();
            expect(Array.isArray(res.body.data)).toBe(true);
          });
      });

      it('should filter snapshots by report code', () => {
        return request(app.getHttpServer())
          .get('/api/v1/reports/snapshots')
          .query({ reportCode: 'RPT_LEADERBOARD' })
          .expect(200)
          .expect((res) => {
            expect(res.body.success).toBe(true);
            expect(res.body.data).toBeDefined();
            expect(Array.isArray(res.body.data)).toBe(true);
          });
      });
    });

    describe('GET /api/v1/reports/snapshots/:code/latest', () => {
      it('should return 404 when no snapshots exist', () => {
        return request(app.getHttpServer())
          .get('/api/v1/reports/snapshots/RPT_LEADERBOARD/latest')
          .expect(404);
      });
    });
  });

  describe('Export API', () => {
    describe('POST /api/v1/export', () => {
      it('should validate request body', () => {
        return request(app.getHttpServer())
          .post('/api/v1/export')
          .send({})
          .expect(400);
      });

      it('should reject invalid format', () => {
        return request(app.getHttpServer())
          .post('/api/v1/export')
          .send({
            snapshotId: '1',
            format: 'INVALID_FORMAT',
          })
          .expect(400);
      });
    });
  });
});
