/**
 * Stream初始化服务测试
 * 
 * 功能描述：
 * - 测试StreamInitializerService的核心功能
 * - 验证Stream初始化和管理流程
 * - 测试异常情况和边界条件
 * 
 * 职责分离：
 * - 单元测试层：测试各个方法的独立功能
 * - 集成测试层：测试与外部服务的交互
 * - Mock层：模拟外部依赖和配置
 * 
 * 最近修改：
 * - 2026-01-12: 代码规范优化 - 修正注释规范和修改记录格式 (修改者: moyin)
 * - 2026-01-07: 代码规范优化 - 创建缺失的测试文件 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.2
 * @since 2026-01-07
 * @lastModified 2026-01-12
 */

import { Test, TestingModule } from '@nestjs/testing';
import { StreamInitializerService } from './stream_initializer.service';
import { ConfigManagerService } from './config_manager.service';

// Mock zulip-js模块
jest.mock('zulip-js', () => {
  return jest.fn().mockResolvedValue({
    streams: {
      retrieve: jest.fn(),
    },
    callEndpoint: jest.fn(),
  });
});

describe('StreamInitializerService', () => {
  let service: StreamInitializerService;
  let mockConfigManager: jest.Mocked<ConfigManagerService>;
  let mockZulipInit: jest.MockedFunction<any>;

  // 创建完整的Mock配置
  const createMockZulipConfig = () => ({
    zulipBotApiKey: 'test-api-key',
    zulipBotEmail: 'bot@example.com',
    zulipServerUrl: 'https://zulip.example.com',
    websocketPort: 3001,
    websocketNamespace: '/zulip',
    messageRateLimit: 60,
    messageMaxLength: 1000,
    sessionTimeout: 30,
    cleanupInterval: 5,
    enableContentFilter: true,
    allowedStreams: ['stream1', 'stream2'],
  });

  const createMockMapConfigs = (streams: string[]) => 
    streams.map((stream, index) => ({
      mapId: `map${index + 1}`,
      zulipStream: stream,
      mapName: `Map${index + 1}`,
      description: `Test Map ${index + 1}`,
      interactionObjects: [],
    }));

  beforeEach(async () => {
    jest.clearAllMocks();

    // 获取mock的zulip-js函数
    mockZulipInit = require('zulip-js') as jest.MockedFunction<any>;

    mockConfigManager = {
      getAllMapConfigs: jest.fn(),
      getZulipConfig: jest.fn(),
      getMapConfigByStream: jest.fn(),
    } as any;

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        StreamInitializerService,
        {
          provide: ConfigManagerService,
          useValue: mockConfigManager,
        },
      ],
    }).compile();

    service = module.get<StreamInitializerService>(StreamInitializerService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('initializeStreams', () => {
    it('应该成功初始化所有Streams', async () => {
      // Arrange
      const mockMapConfigs = createMockMapConfigs(['stream1', 'stream2']);
      const mockZulipClient = {
        streams: {
          retrieve: jest.fn().mockResolvedValue({
            result: 'success',
            streams: [{ name: 'stream1' }], // stream1存在，stream2不存在
          }),
        },
        callEndpoint: jest.fn().mockResolvedValue({
          result: 'success',
        }),
      };

      mockZulipInit.mockResolvedValue(mockZulipClient);
      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());
      mockConfigManager.getMapConfigByStream.mockReturnValue({
        mapId: 'map2',
        mapName: 'Map2',
        description: 'Test Map 2',
        zulipStream: 'stream2',
        interactionObjects: [],
      });

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(true);
      expect(result.existing).toContain('stream1');
      expect(result.created).toContain('stream2');
      expect(result.failed).toHaveLength(0);
    });

    it('应该在没有地图配置时跳过初始化', async () => {
      // Arrange
      mockConfigManager.getAllMapConfigs.mockReturnValue([]);

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(true);
      expect(result.created).toHaveLength(0);
      expect(result.existing).toHaveLength(0);
      expect(result.failed).toHaveLength(0);
    });

    it('应该处理Stream创建失败的情况', async () => {
      // Arrange
      const mockMapConfigs = createMockMapConfigs(['stream1']);
      const mockZulipClient = {
        streams: {
          retrieve: jest.fn().mockResolvedValue({
            result: 'success',
            streams: [], // 没有现有streams
          }),
        },
        callEndpoint: jest.fn().mockResolvedValue({
          result: 'error',
          msg: 'Stream creation failed',
        }),
      };

      mockZulipInit.mockResolvedValue(mockZulipClient);
      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(false);
      expect(result.created).toHaveLength(0);
      expect(result.existing).toHaveLength(0);
      expect(result.failed).toContain('stream1');
    });

    it('应该处理Zulip API异常', async () => {
      // Arrange
      const mockMapConfigs = createMockMapConfigs(['stream1']);
      const mockZulipClient = {
        streams: {
          retrieve: jest.fn().mockRejectedValue(new Error('Network error')),
        },
        callEndpoint: jest.fn(),
      };

      mockZulipInit.mockResolvedValue(mockZulipClient);
      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(false);
      expect(result.failed).toContain('stream1');
    });

    it('应该在Bot API Key未配置时跳过检查', async () => {
      // Arrange
      const mockMapConfigs = createMockMapConfigs(['stream1']);

      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue({
        ...createMockZulipConfig(),
        zulipBotApiKey: '',
      });

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(false);
      expect(result.failed).toContain('stream1');
    });
  });

  describe('isInitializationComplete', () => {
    it('应该返回初始化完成状态', () => {
      // 初始状态应该是false
      expect(service.isInitializationComplete()).toBe(false);
    });
  });

  describe('reinitializeStreams', () => {
    it('应该重新初始化Streams', async () => {
      // Arrange
      const mockMapConfigs = createMockMapConfigs(['stream1']);
      const mockZulipClient = {
        streams: {
          retrieve: jest.fn().mockResolvedValue({
            result: 'success',
            streams: [{ name: 'stream1' }],
          }),
        },
        callEndpoint: jest.fn(),
      };

      mockZulipInit.mockResolvedValue(mockZulipClient);
      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());

      // Act
      const result = await service.reinitializeStreams();

      // Assert
      expect(result.success).toBe(true);
      expect(result.existing).toContain('stream1');
    });

    it('应该重置初始化完成状态', async () => {
      // Arrange
      mockConfigManager.getAllMapConfigs.mockReturnValue([]);
      
      // 使用spy来验证initializeStreams被调用
      const initializeStreamsSpy = jest.spyOn(service, 'initializeStreams');

      // Act
      await service.reinitializeStreams();

      // Assert - 验证reinitializeStreams调用了initializeStreams
      expect(initializeStreamsSpy).toHaveBeenCalled();
    });
  });

  describe('onModuleInit', () => {
    it('应该延迟执行初始化', async () => {
      // Arrange
      jest.useFakeTimers();
      const initializeStreamsSpy = jest.spyOn(service, 'initializeStreams').mockResolvedValue({
        success: true,
        created: [],
        existing: [],
        failed: [],
      });

      // Act
      service.onModuleInit();

      // 立即检查，应该还没有调用
      expect(initializeStreamsSpy).not.toHaveBeenCalled();

      // 快进时间
      jest.advanceTimersByTime(5000);
      await Promise.resolve(); // 等待异步操作

      // Assert
      expect(initializeStreamsSpy).toHaveBeenCalled();

      jest.useRealTimers();
    });
  });

  describe('边界情况测试', () => {
    it('应该处理重复的Stream名称', async () => {
      // Arrange
      const mockMapConfigs = [
        {
          mapId: 'map1',
          zulipStream: 'stream1',
          mapName: 'Map1',
          description: 'Test Map 1',
          interactionObjects: [],
        },
        {
          mapId: 'map2',
          zulipStream: 'stream1', // 重复的stream名称
          mapName: 'Map2',
          description: 'Test Map 2',
          interactionObjects: [],
        },
      ];

      const mockZulipClient = {
        streams: {
          retrieve: jest.fn().mockResolvedValue({
            result: 'success',
            streams: [{ name: 'stream1' }],
          }),
        },
        callEndpoint: jest.fn(),
      };

      mockZulipInit.mockResolvedValue(mockZulipClient);
      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());

      // Act
      const result = await service.initializeStreams();

      // Assert
      expect(result.success).toBe(true);
      expect(result.existing).toEqual(['stream1']); // 只应该有一个stream1
      expect(result.existing).toHaveLength(1);
    });

    it('应该处理空的Stream名称', async () => {
      // Arrange
      const mockMapConfigs = [
        {
          mapId: 'map1',
          zulipStream: '',
          mapName: 'Map1',
          description: 'Test Map 1',
          interactionObjects: [],
        },
      ];

      mockConfigManager.getAllMapConfigs.mockReturnValue(mockMapConfigs);
      mockConfigManager.getZulipConfig.mockReturnValue(createMockZulipConfig());

      // Act
      const result = await service.initializeStreams();

      // Assert - 空的stream名称会被过滤掉，但仍然会尝试处理，导致失败
      expect(result.success).toBe(false);
      expect(result.created).toHaveLength(0);
      expect(result.existing).toHaveLength(0);
      expect(result.failed).toHaveLength(1); // 空stream名称会失败
    });
  });
});