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

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

  // Tokens de teste
  const validUserToken = jwt.sign(
    {
      sub: 'user_123',
      iss: 'planfi-bff',
      jti: 'jwt_id_123',
      prv: 'user',
      exp: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hora
      iat: Math.floor(Date.now() / 1000),
      nbf: Math.floor(Date.now() / 1000),
      uuid: 'user-uuid-123',
      email: 'user@test.com',
      name: 'Usuário Teste',
    },
    'test-secret-key',
  );

  const validClientToken = jwt.sign(
    {
      sub: 'client_456',
      iss: 'planfi-bff',
      jti: 'jwt_id_456',
      prv: 'client',
      exp: Math.floor(Date.now() / 1000) + 60 * 60, // 1 hora
      iat: Math.floor(Date.now() / 1000),
      nbf: Math.floor(Date.now() / 1000),
      uuid: 'client-uuid-456',
      email: 'client@test.com',
      name: 'Client Teste',
    },
    'test-secret-key',
  );

  const expiredToken = jwt.sign(
    {
      sub: 'user_123',
      iss: 'planfi-bff',
      jti: 'jwt_id_123',
      prv: 'user',
      exp: Math.floor(Date.now() / 1000) - 60 * 60, // Expirado há 1 hora
      iat: Math.floor(Date.now() / 1000) - 2 * 60 * 60,
      nbf: Math.floor(Date.now() / 1000) - 2 * 60 * 60,
    },
    'test-secret-key',
  );

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

    app = moduleFixture.createNestApplication();
    await app.init();
  });

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

  describe('GET /auth/health', () => {
    it('deve retornar status de saúde sem autenticação', () => {
      return request(app.getHttpServer())
        .get('/auth/health')
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.status).toBe('OK');
          expect(res.body.message).toContain('BFF PlanFi está funcionando');
          expect(res.body.timestamp).toBeDefined();
        });
    });
  });

  describe('GET /auth/profile', () => {
    it('deve acessar perfil com token de usuário válido', () => {
      return request(app.getHttpServer())
        .get('/auth/profile')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Perfil acessado com sucesso');
          expect(res.body.user).toBeDefined();
          expect(res.body.user.id).toBe('user_123');
          expect(res.body.user.type).toBe('user');
        });
    });

    it('deve acessar perfil com token de client válido', () => {
      return request(app.getHttpServer())
        .get('/auth/profile')
        .set('Authorization', `Bearer ${validClientToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Perfil acessado com sucesso');
          expect(res.body.user).toBeDefined();
          expect(res.body.user.id).toBe('client_456');
          expect(res.body.user.type).toBe('client');
        });
    });

    it('deve retornar erro 401 sem token', () => {
      return request(app.getHttpServer()).get('/auth/profile').expect(401);
    });

    it('deve retornar erro 401 com token expirado', () => {
      return request(app.getHttpServer())
        .get('/auth/profile')
        .set('Authorization', `Bearer ${expiredToken}`)
        .expect(401);
    });

    it('deve retornar erro 401 com token inválido', () => {
      return request(app.getHttpServer())
        .get('/auth/profile')
        .set('Authorization', 'Bearer token_invalido')
        .expect(401);
    });
  });

  describe('GET /auth/user/dashboard', () => {
    it('deve acessar dashboard de usuário com token de usuário válido', () => {
      return request(app.getHttpServer())
        .get('/auth/user/dashboard')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Dashboard do usuário');
          expect(res.body.userId).toBe('user_123');
          expect(res.body.userType).toBe('user');
          expect(res.body.payload).toBeDefined();
        });
    });

    it('deve retornar erro 403 com token de client', () => {
      return request(app.getHttpServer())
        .get('/auth/user/dashboard')
        .set('Authorization', `Bearer ${validClientToken}`)
        .expect(403);
    });

    it('deve retornar erro 401 sem token', () => {
      return request(app.getHttpServer())
        .get('/auth/user/dashboard')
        .expect(401);
    });
  });

  describe('GET /auth/client/dashboard', () => {
    it('deve acessar dashboard de client com token de client válido', () => {
      return request(app.getHttpServer())
        .get('/auth/client/dashboard')
        .set('Authorization', `Bearer ${validClientToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Dashboard do client');
          expect(res.body.clientId).toBe('client_456');
          expect(res.body.userType).toBe('client');
          expect(res.body.payload).toBeDefined();
        });
    });

    it('deve retornar erro 403 com token de usuário', () => {
      return request(app.getHttpServer())
        .get('/auth/client/dashboard')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(403);
    });

    it('deve retornar erro 401 sem token', () => {
      return request(app.getHttpServer())
        .get('/auth/client/dashboard')
        .expect(401);
    });
  });

  describe('GET /auth/client/test', () => {
    it('deve acessar endpoint de teste de client com token válido', () => {
      return request(app.getHttpServer())
        .get('/auth/client/test')
        .set('Authorization', `Bearer ${validClientToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.text).toBe('OK');
        });
    });

    it('deve retornar erro 403 com token de usuário', () => {
      return request(app.getHttpServer())
        .get('/auth/client/test')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(403);
    });
  });

  describe('POST /auth/validate-token', () => {
    it('deve validar token fornecido no body', () => {
      return request(app.getHttpServer())
        .post('/auth/validate-token')
        .send({ token: validUserToken })
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toContain('Use o header Authorization');
          expect(res.body.example).toContain('Authorization: Bearer');
        });
    });

    it('deve retornar erro quando token não é fornecido', () => {
      return request(app.getHttpServer())
        .post('/auth/validate-token')
        .send({})
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.valid).toBe(false);
          expect(res.body.error).toBe('Token não fornecido');
        });
    });
  });

  describe('GET /auth/me', () => {
    it('deve retornar informações do usuário autenticado', () => {
      return request(app.getHttpServer())
        .get('/auth/me')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.id).toBe('user_123');
          expect(res.body.type).toBe('user');
          expect(res.body.expiresAt).toBeDefined();
          expect(res.body.issuedAt).toBeDefined();
          expect(res.body.payload).toBeDefined();
        });
    });

    it('deve retornar erro 401 sem token', () => {
      return request(app.getHttpServer()).get('/auth/me').expect(401);
    });
  });

  describe('GET /auth/token/debug', () => {
    it('deve retornar debug completo do token', () => {
      return request(app.getHttpServer())
        .get('/auth/token/debug')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Debug completo do token JWT');
          expect(res.body.authentication).toBeDefined();
          expect(res.body.rawToken).toBeDefined();
          expect(res.body.tokenData).toBeDefined();
          expect(res.body.jwtPayload).toBeDefined();
          expect(res.body.extractedFields).toBeDefined();
          expect(res.body.laravelCompatible).toBe(true);
          expect(res.body.instructions).toBeDefined();
        });
    });
  });

  describe('GET /auth/laravel/compatibility', () => {
    it('deve retornar dados de compatibilidade com Laravel', () => {
      return request(app.getHttpServer())
        .get('/auth/laravel/compatibility')
        .set('Authorization', `Bearer ${validUserToken}`)
        .expect(200)
        .expect((res) => {
          expect(res.body).toBeDefined();
          expect(res.body.message).toBe('Dados de compatibilidade com Laravel');
          expect(res.body.bffData).toBeDefined();
          expect(res.body.laravelFields).toBeDefined();
          expect(res.body.compatibility).toBeDefined();
          expect(res.body.bffData.userId).toBe('user_123');
          expect(res.body.bffData.userType).toBe('user');
        });
    });
  });
});
