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

import { Test, TestingModule } from '@nestjs/testing';
import { ExecutionContext, CallHandler } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { of } from 'rxjs';
import { TimeoutInterceptor } from './timeout.interceptor';
import { TimeoutConfig } from './timeout.decorator';

describe('TimeoutInterceptor', () => {
  let interceptor: TimeoutInterceptor;
  let reflector: jest.Mocked<Reflector>;

  beforeEach(async () => {
    const mockReflector = {
      get: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        TimeoutInterceptor,
        { provide: Reflector, useValue: mockReflector },
      ],
    }).compile();

    interceptor = module.get<TimeoutInterceptor>(TimeoutInterceptor);
    reflector = module.get(Reflector);
  });

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

  describe('intercept', () => {
    it('should pass through when no timeout config is found', (done) => {
      // Arrange
      reflector.get.mockReturnValue(null);
      const testData = { result: 'success' };
      const mockCallHandler: CallHandler = {
        handle: jest.fn().mockReturnValue(of(testData)),
      };
      const mockContext = createMockContext();

      // Act
      const result$ = interceptor.intercept(mockContext, mockCallHandler);

      // Assert
      result$.subscribe({
        next: (data) => {
          expect(data).toEqual(testData);
          done();
        },
      });
    });

    it('should apply timeout when config is found', (done) => {
      // Arrange
      const config: TimeoutConfig = { timeout: 1000 };
      reflector.get.mockReturnValueOnce(config).mockReturnValueOnce(null);
      const testData = { result: 'success' };
      const mockCallHandler: CallHandler = {
        handle: jest.fn().mockReturnValue(of(testData)),
      };
      const mockContext = createMockContext();

      // Act
      const result$ = interceptor.intercept(mockContext, mockCallHandler);

      // Assert
      result$.subscribe({
        next: (data) => {
          expect(data).toEqual(testData);
          done();
        },
      });
    });
  });

  function createMockContext(): ExecutionContext {
    const mockRequest = {
      method: 'GET',
      url: '/api/test',
      get: jest.fn(),
      ip: '127.0.0.1',
    };

    return {
      switchToHttp: jest.fn().mockReturnValue({
        getRequest: jest.fn().mockReturnValue(mockRequest),
      }),
      getHandler: jest.fn(),
      getClass: jest.fn(),
    } as any;
  }
});