import { Request, Response } from 'express';

import { prisma } from '../../../config/database.config';
import { HealthController } from '../health.controller';

jest.mock('../../../config/database.config');

describe('HealthController', () => {
  let healthController: HealthController;
  let mockReq: Partial<Request>;
  let mockRes: Partial<Response>;
  let mockJson: jest.Mock;
  let mockStatus: jest.Mock;

  beforeEach(() => {
    healthController = new HealthController();
    mockJson = jest.fn();
    mockStatus = jest.fn().mockReturnValue({ json: mockJson });
    mockReq = {};
    mockRes = {
      json: mockJson,
      status: mockStatus,
    };
  });

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

  describe('health', () => {
    it('should return healthy status', async () => {
      // EN: Act
      // VI: Thực hiện
      await healthController.health(mockReq as Request, mockRes as Response);

      // EN: Assert
      // VI: Kiểm tra
      expect(mockJson).toHaveBeenCalledWith({
        success: true,
        data: {
          status: 'ok',
          timestamp: expect.any(String),
        },
        timestamp: expect.any(String),
      });

      // EN: Verify timestamp is valid ISO string
      // VI: Xác minh timestamp là ISO string hợp lệ
      const response = mockJson.mock.calls[0][0];
      expect(new Date(response.timestamp).toISOString()).toBe(response.timestamp);
      expect(new Date(response.data.timestamp).toISOString()).toBe(response.data.timestamp);
    });
  });

  describe('ready', () => {
    it('should return ready status when database is connected', async () => {
      // EN: Arrange
      // VI: Chuẩn bị
      (prisma.$queryRaw as jest.Mock).mockResolvedValue([{ '1': 1 }]);

      // EN: Act
      // VI: Thực hiện
      await healthController.ready(mockReq as Request, mockRes as Response);

      // EN: Assert
      // VI: Kiểm tra
      expect(prisma.$queryRaw).toHaveBeenCalledWith(expect.anything());
      expect(mockJson).toHaveBeenCalledWith({
        success: true,
        data: { status: 'ready' },
        timestamp: expect.any(String),
      });
    });

    it('should return 503 when database connection fails', async () => {
      // EN: Arrange
      // VI: Chuẩn bị
      const dbError = new Error('Database connection failed');
      (prisma.$queryRaw as jest.Mock).mockRejectedValue(dbError);

      // EN: Act
      // VI: Thực hiện
      await healthController.ready(mockReq as Request, mockRes as Response);

      // EN: Assert
      // VI: Kiểm tra
      expect(mockStatus).toHaveBeenCalledWith(503);
      expect(mockJson).toHaveBeenCalledWith({
        success: false,
        error: {
          code: 'HEALTH_001',
          message: 'Service not ready',
        },
        timestamp: expect.any(String),
      });
    });
  });

  describe('live', () => {
    it('should return live status', async () => {
      // EN: Act
      // VI: Thực hiện
      await healthController.live(mockReq as Request, mockRes as Response);

      // EN: Assert
      // VI: Kiểm tra
      expect(mockJson).toHaveBeenCalledWith({
        success: true,
        data: { status: 'live' },
        timestamp: expect.any(String),
      });
    });
  });
});