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

describe('Pluggy Module (e2e)', () => {
  let app: INestApplication;
  const API_KEY = 'JOqyUcP45H875xmuI2gT3H9dDK42I2Wt';

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

    app = moduleFixture.createNestApplication();

    // Adicionar ValidationPipe para validação de DTOs
    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: false, // Permitir propriedades adicionais para DTOs dinâmicos
        transform: true,
      }),
    );

    await app.init();
  });

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

  describe('POST /pluggy', () => {
    it('deve processar requisição para API Pluggy', () => {
      const pluggyRequest = {
        endpoint: '/items',
        method: 'GET',
        itemId: 'test_item_123',
      };

      return request(app.getHttpServer())
        .post('/pluggy')
        .set('x-api-key', API_KEY)
        .send(pluggyRequest)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
        });
    });

    it('deve retornar erro 400 para dados inválidos', () => {
      const invalidRequest = {
        // endpoint ausente
        method: 'GET',
      };

      return request(app.getHttpServer())
        .post('/pluggy')
        .set('x-api-key', API_KEY)
        .send(invalidRequest)
        .expect(400);
    });

    it('deve retornar erro 401 sem API key', () => {
      const pluggyRequest = {
        endpoint: '/items',
        method: 'GET',
      };

      return request(app.getHttpServer())
        .post('/pluggy')
        .send(pluggyRequest)
        .expect(401);
    });

    it('deve processar requisição POST para criar item', () => {
      const createItemRequest = {
        endpoint: '/items',
        method: 'POST',
        body: {
          parameter: 'test_parameter',
          provider: 'test_provider',
        },
      };

      return request(app.getHttpServer())
        .post('/pluggy')
        .set('x-api-key', API_KEY)
        .send(createItemRequest)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
        });
    });
  });

  describe('POST /pluggy/connect_token', () => {
    it('deve obter connect token para item específico', () => {
      const connectTokenRequest = {
        itemId: 'test_item_123',
      };

      return request(app.getHttpServer())
        .post('/pluggy/connect_token')
        .set('x-api-key', API_KEY)
        .send(connectTokenRequest)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
        });
    });

    it('deve retornar erro 400 para itemId ausente', () => {
      const invalidRequest = {
        // itemId ausente
      };

      return request(app.getHttpServer())
        .post('/pluggy/connect_token')
        .set('x-api-key', API_KEY)
        .send(invalidRequest)
        .expect(400);
    });

    it('deve retornar erro 401 sem API key', () => {
      const connectTokenRequest = {
        itemId: 'test_item_123',
      };

      return request(app.getHttpServer())
        .post('/pluggy/connect_token')
        .send(connectTokenRequest)
        .expect(401);
    });
  });

  describe('POST /pluggy-webhook', () => {
    it('deve processar webhook do Pluggy', () => {
      const webhookData = {
        event: 'ITEM_UPDATED',
        itemId: 'test_item_123',
        timestamp: new Date().toISOString(),
        data: {
          status: 'UPDATED',
          message: 'Item atualizado com sucesso',
        },
      };

      return request(app.getHttpServer())
        .post('/pluggy-webhook')
        .send(webhookData)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.received).toBe(true);
        });
    });

    it('deve processar webhook de erro', () => {
      const errorWebhookData = {
        event: 'ITEM_ERROR',
        itemId: 'test_item_123',
        timestamp: new Date().toISOString(),
        error: {
          code: 'INVALID_CREDENTIALS',
          message: 'Credenciais inválidas',
        },
      };

      return request(app.getHttpServer())
        .post('/pluggy-webhook')
        .send(errorWebhookData)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.received).toBe(true);
        });
    });

    it('deve processar webhook de transação', () => {
      const transactionWebhookData = {
        event: 'transactions/created',
        itemId: 'test_item_123',
        timestamp: new Date().toISOString(),
        data: {
          transactionId: 'txn_123',
          amount: 100.5,
          description: 'Compra no supermercado',
          date: new Date().toISOString(),
        },
      };

      return request(app.getHttpServer())
        .post('/pluggy-webhook')
        .send(transactionWebhookData)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.received).toBe(true);
        });
    });

    it('deve processar webhook de conta atualizada', () => {
      const accountWebhookData = {
        event: 'ACCOUNT_UPDATED',
        itemId: 'test_item_123',
        timestamp: new Date().toISOString(),
        data: {
          accountId: 'acc_123',
          balance: 1500.75,
          type: 'CHECKING',
        },
      };

      return request(app.getHttpServer())
        .post('/pluggy-webhook')
        .send(accountWebhookData)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.received).toBe(true);
        });
    });

    it('deve retornar erro 400 para webhook malformado', () => {
      const malformedWebhookData = {
        // dados incompletos
        event: 'INVALID_EVENT',
      };

      return request(app.getHttpServer())
        .post('/pluggy-webhook')
        .send(malformedWebhookData)
        .expect(400);
    });
  });
});
