import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import * as request from 'supertest';
import { LaravelApiController } from '../src/laravel-api/laravel-api.controller';
import { LaravelApiService } from '../src/laravel-api/laravel-api.service';
import { JwtAuthGuard } from '../src/auth/guards/jwt-auth.guard';
import { UserJwtGuard } from '../src/auth/guards/user-jwt.guard';
import { ClientJwtGuard } from '../src/auth/guards/client-jwt.guard';
import { ApiKeyGuard } from '../src/common/guards/api-key/api-key.guard';
import { ConfigModule } from '@nestjs/config';

// Setup MSW
import './setup-e2e';

// Mock simples do service
const mockLaravelApiService = {
  validateTokenWithLaravel: jest
    .fn()
    .mockResolvedValue({ data: { id: 'test' } }),
  getUserFromLaravel: jest.fn().mockResolvedValue({ data: { id: 'test' } }),
  getClientFromLaravel: jest.fn().mockResolvedValue({ data: { id: 'test' } }),
  proxyRequest: jest
    .fn()
    .mockResolvedValue({ data: { test: true }, status: 200 }),
};

// Mock simples dos guards - sempre permitir acesso
const mockGuard = {
  canActivate: jest.fn().mockImplementation((context) => {
    const request = context.switchToHttp().getRequest();
    request.user = {
      id: 'user-123',
      type: 'user',
      expiresAt: new Date(),
      issuedAt: new Date(),
      payload: { sub: 'user-123' },
    };
    return true;
  }),
};

describe('Laravel API Module Simple (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          ignoreEnvFile: true,
          load: [
            () => ({
              LARAVEL_API_URL: 'http://localhost:8000',
              JWT_SECRET: 'test-secret-key',
              API_KEY: 'test-api-key',
            }),
          ],
        }),
      ],
      controllers: [LaravelApiController],
      providers: [
        { provide: LaravelApiService, useValue: mockLaravelApiService },
        { provide: JwtAuthGuard, useValue: mockGuard },
        { provide: UserJwtGuard, useValue: mockGuard },
        { provide: ClientJwtGuard, useValue: mockGuard },
        { provide: ApiKeyGuard, useValue: mockGuard },
      ],
    })
      .overrideGuard(JwtAuthGuard)
      .useValue(mockGuard)
      .overrideGuard(UserJwtGuard)
      .useValue(mockGuard)
      .overrideGuard(ClientJwtGuard)
      .useValue(mockGuard)
      .overrideGuard(ApiKeyGuard)
      .useValue(mockGuard)
      .compile();

    app = moduleFixture.createNestApplication();

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

    await app.init();
  });

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

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

  describe('GET /laravel-api/health', () => {
    it('deve retornar status de saúde da integração', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/health')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty('message');
          expect(res.body).toHaveProperty('user');
          expect(res.body).toHaveProperty('tokenAvailable');
        });
    });
  });

  describe('POST /laravel-api/validate-token', () => {
    it('deve validar token com Laravel API', () => {
      return request(app.getHttpServer())
        .post('/laravel-api/validate-token')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty('valid', true);
          expect(res.body).toHaveProperty('message');
        });
    });
  });

  describe('GET /laravel-api/user/profile', () => {
    it('deve obter perfil do usuário', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/user/profile')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_user_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty('source', 'Laravel API');
          expect(res.body).toHaveProperty('tokenData');
          expect(res.body).toHaveProperty('laravelData');
        });
    });
  });

  describe('GET /laravel-api/client/profile', () => {
    it('deve obter perfil do client', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/client/profile')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_client_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty('source', 'Laravel API');
          expect(res.body).toHaveProperty('tokenData');
          expect(res.body).toHaveProperty('laravelData');
        });
    });
  });

  describe('POST /laravel-api/proxy/test', () => {
    it('deve fazer proxy de requisição', () => {
      return request(app.getHttpServer())
        .post('/laravel-api/proxy/test')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_token')
        .send({ method: 'GET', data: { test: true } })
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty(
            'source',
            'Laravel API via BFF Proxy',
          );
          expect(res.body).toHaveProperty('endpoint', '/test');
          expect(res.body).toHaveProperty('method', 'GET');
          expect(res.body).toHaveProperty('response');
        });
    });
  });

  describe('GET /laravel-api/debug/token', () => {
    it('deve retornar debug do token', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/debug/token')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty(
            'message',
            'Debug completo do token JWT',
          );
          expect(res.body).toHaveProperty('data');
        });
    });
  });

  describe('GET /laravel-api/test/user-endpoint', () => {
    it('deve testar endpoint de usuário', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/test/user-endpoint')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_user_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty(
            'message',
            'Teste de endpoint de usuário da API Laravel',
          );
          expect(res.body).toHaveProperty('response');
          expect(res.body).toHaveProperty('status');
        });
    });
  });

  describe('GET /laravel-api/test/client-endpoint', () => {
    it('deve testar endpoint de client', () => {
      return request(app.getHttpServer())
        .get('/laravel-api/test/client-endpoint')
        .set('x-api-key', 'test-api-key')
        .set('Authorization', 'Bearer valid_client_token')
        .expect(200)
        .expect((res) => {
          expect(res.body).toHaveProperty(
            'message',
            'Teste de endpoint de client da API Laravel',
          );
          expect(res.body).toHaveProperty('response');
          expect(res.body).toHaveProperty('status');
        });
    });
  });
});
