const request = require('supertest');
const createApp = require('../app.js');

describe('Express App', () => {
  let app;

  beforeAll(() => {
    app = createApp();
  });

  describe('Health Check', () => {
    it('should return health status with services info', async () => {
      const response = await request(app).get('/health');

      // May return 200 (healthy) or 503 (degraded) depending on DB/Redis availability
      expect([200, 503]).toContain(response.status);
      expect(response.body.data).toHaveProperty('status');
      expect(response.body.data).toHaveProperty('timestamp');
      expect(response.body.data).toHaveProperty('uptime');
      expect(response.body.data).toHaveProperty('services');
      expect(response.body.data.services).toHaveProperty('database');
      expect(response.body.data.services).toHaveProperty('redis');
    });

    it('should return liveness status', async () => {
      const response = await request(app).get('/health/live');

      expect(response.status).toBe(200);
      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('status', 'alive');
      expect(response.body.data).toHaveProperty('timestamp');
    });

    it('should return readiness status', async () => {
      const response = await request(app).get('/health/ready');

      // May return 200 (ready) or 503 (not ready) depending on DB/Redis availability
      expect([200, 503]).toContain(response.status);
      expect(response.body.data).toHaveProperty('status');
      expect(response.body.data).toHaveProperty('timestamp');
    });
  });

  describe('Metrics', () => {
    it('should return metrics data', async () => {
      const response = await request(app).get('/health/metrics');

      expect(response.status).toBe(200);
      expect(response.body.success).toBe(true);
      expect(response.body.data).toHaveProperty('uptime');
      expect(response.body.data).toHaveProperty('requests');
      expect(response.body.data).toHaveProperty('responseTime');
      expect(response.body.data).toHaveProperty('memory');
      expect(response.body.data.requests).toHaveProperty('total');
      expect(response.body.data.requests).toHaveProperty('success');
      expect(response.body.data.requests).toHaveProperty('error');
      expect(response.body.data.requests).toHaveProperty('errorRate');
    });
  });

  describe('404 Handler', () => {
    it('should return 404 for non-existent routes', async () => {
      const response = await request(app).get('/non-existent-route');

      expect(response.status).toBe(404);
      expect(response.body.success).toBe(false);
      expect(response.body.error).toHaveProperty('code', 'NOT_FOUND');
      expect(response.body.error.message).toContain('not found');
    });
  });

  describe('Security Headers', () => {
    it('should include security headers from helmet', async () => {
      const response = await request(app).get('/health');

      expect(response.headers).toHaveProperty('x-content-type-options');
      expect(response.headers).toHaveProperty('x-frame-options');
    });
  });

  describe('CORS', () => {
    it('should handle CORS preflight requests', async () => {
      const response = await request(app)
        .options('/health')
        .set('Origin', 'http://localhost:3000')
        .set('Access-Control-Request-Method', 'GET');

      // CORS middleware returns 200 or 204 depending on configuration
      expect([200, 204]).toContain(response.status);
      expect(response.headers).toHaveProperty('access-control-allow-origin');
    });
  });
});
