/**
 * ContentTypeMiddleware 单元测试
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-07
 */

import { Test, TestingModule } from '@nestjs/testing';
import { Request, Response, NextFunction } from 'express';
import { ContentTypeMiddleware } from './content_type.middleware';

describe('ContentTypeMiddleware', () => {
  let middleware: ContentTypeMiddleware;
  let mockRequest: Partial<Request>;
  let mockResponse: Partial<Response>;
  let mockNext: NextFunction;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [ContentTypeMiddleware],
    }).compile();

    middleware = module.get<ContentTypeMiddleware>(ContentTypeMiddleware);

    mockResponse = {
      status: jest.fn().mockReturnThis(),
      json: jest.fn().mockReturnThis(),
    };

    mockNext = jest.fn();
  });

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

  describe('use', () => {
    it('should call next() for GET requests', () => {
      // Arrange
      mockRequest = {
        method: 'GET',
        url: '/api/test',
      };

      // Act
      middleware.use(mockRequest as Request, mockResponse as Response, mockNext);

      // Assert
      expect(mockNext).toHaveBeenCalled();
      expect(mockResponse.status).not.toHaveBeenCalled();
    });

    it('should call next() for excluded paths', () => {
      // Arrange
      mockRequest = {
        method: 'POST',
        url: '/api-docs/swagger',
        get: jest.fn(),
      };

      // Act
      middleware.use(mockRequest as Request, mockResponse as Response, mockNext);

      // Assert
      expect(mockNext).toHaveBeenCalled();
      expect(mockResponse.status).not.toHaveBeenCalled();
    });

    it('should return 415 when Content-Type is missing', () => {
      // Arrange
      mockRequest = {
        method: 'POST',
        url: '/api/test',
        get: jest.fn().mockReturnValue(undefined),
        ip: '127.0.0.1',
      };

      // Act
      middleware.use(mockRequest as Request, mockResponse as Response, mockNext);

      // Assert
      expect(mockResponse.status).toHaveBeenCalledWith(415);
      expect(mockNext).not.toHaveBeenCalled();
    });

    it('should call next() for supported Content-Type', () => {
      // Arrange
      mockRequest = {
        method: 'POST',
        url: '/api/test',
        get: jest.fn().mockImplementation((header) => {
          if (header === 'Content-Type') return 'application/json';
          return undefined;
        }),
      };

      // Act
      middleware.use(mockRequest as Request, mockResponse as Response, mockNext);

      // Assert
      expect(mockNext).toHaveBeenCalled();
      expect(mockResponse.status).not.toHaveBeenCalled();
    });
  });

  describe('getSupportedTypes', () => {
    it('should return supported types array', () => {
      const types = middleware.getSupportedTypes();
      expect(Array.isArray(types)).toBe(true);
      expect(types.length).toBeGreaterThan(0);
    });
  });

  describe('addSupportedType', () => {
    it('should add new supported type', () => {
      middleware.addSupportedType('application/xml');
      const types = middleware.getSupportedTypes();
      expect(types).toContain('application/xml');
    });
  });
});