/**
 * 自动清理服务单元测试
 * 
 * 功能描述：
 * - 测试自动清理服务的所有功能
 * - 验证定时清理和手动清理操作
 * - 确保配置更新和统计信息正确
 * - 提供完整的测试覆盖率
 * 
 * 测试范围：
 * - 清理调度器的启动和停止
 * - 各种清理操作的执行
 * - 配置更新和统计信息管理
 * - 异常情况处理
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { Test, TestingModule } from '@nestjs/testing';
import { CleanupService } from './cleanup.service';

describe('CleanupService', () => {
  let service: CleanupService;
  let mockLocationBroadcastCore: any;

  beforeEach(async () => {
    // 创建位置广播核心服务的Mock
    mockLocationBroadcastCore = {
      cleanupExpiredData: jest.fn(),
      cleanupUserData: jest.fn(),
      cleanupEmptySession: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        CleanupService,
        {
          provide: 'ILocationBroadcastCore',
          useValue: mockLocationBroadcastCore,
        },
      ],
    }).compile();

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

  afterEach(() => {
    jest.clearAllMocks();
    // 确保清理定时器被停止
    service.stopCleanupScheduler();
  });

  describe('模块生命周期', () => {
    it('应该在模块初始化时启动清理调度器', () => {
      const startSpy = jest.spyOn(service, 'startCleanupScheduler');
      
      service.onModuleInit();
      
      expect(startSpy).toHaveBeenCalled();
    });

    it('应该在模块销毁时停止清理调度器', () => {
      const stopSpy = jest.spyOn(service, 'stopCleanupScheduler');
      
      service.onModuleDestroy();
      
      expect(stopSpy).toHaveBeenCalled();
    });

    it('应该在禁用时不启动清理调度器', () => {
      service.updateConfig({ enabled: false });
      const startSpy = jest.spyOn(service, 'startCleanupScheduler');
      
      service.onModuleInit();
      
      expect(startSpy).not.toHaveBeenCalled();
    });
  });

  describe('清理调度器管理', () => {
    it('应该成功启动清理调度器', () => {
      service.startCleanupScheduler();
      
      // 验证调度器已启动（通过检查内部状态）
      expect(service['cleanupTimer']).not.toBeNull();
    });

    it('应该成功停止清理调度器', () => {
      service.startCleanupScheduler();
      service.stopCleanupScheduler();
      
      expect(service['cleanupTimer']).toBeNull();
    });

    it('应该防止重复启动调度器', () => {
      service.startCleanupScheduler();
      const firstTimer = service['cleanupTimer'];
      
      service.startCleanupScheduler();
      
      expect(service['cleanupTimer']).toBe(firstTimer);
    });

    it('应该安全处理停止未启动的调度器', () => {
      expect(() => service.stopCleanupScheduler()).not.toThrow();
    });
  });

  describe('手动清理操作', () => {
    it('应该成功执行手动清理', async () => {
      const results = await service.manualCleanup();
      
      expect(results).toBeInstanceOf(Array);
      expect(results.length).toBeGreaterThan(0);
      expect(results.every(r => typeof r.operation === 'string')).toBe(true);
      expect(results.every(r => typeof r.count === 'number')).toBe(true);
      expect(results.every(r => typeof r.duration === 'number')).toBe(true);
      expect(results.every(r => typeof r.success === 'boolean')).toBe(true);
    });

    it('应该更新统计信息', async () => {
      const statsBefore = service.getStats();
      
      await service.manualCleanup();
      
      const statsAfter = service.getStats();
      expect(statsAfter.totalCleanups).toBe(statsBefore.totalCleanups + 1);
      expect(statsAfter.lastCleanupTime).toBeGreaterThan(statsBefore.lastCleanupTime);
    });

    it('应该处理清理过程中的异常', async () => {
      // 模拟清理过程中的异常
      const originalCleanupExpiredSessions = service['cleanupExpiredSessions'];
      service['cleanupExpiredSessions'] = jest.fn().mockRejectedValue(new Error('清理失败'));
      
      const results = await service.manualCleanup();
      
      expect(results).toBeInstanceOf(Array);
      expect(results.some(r => !r.success)).toBe(true);
      
      // 恢复原方法
      service['cleanupExpiredSessions'] = originalCleanupExpiredSessions;
    });
  });

  describe('配置管理', () => {
    it('应该返回当前配置', () => {
      const config = service.getConfig();
      
      expect(config).toHaveProperty('sessionExpiry');
      expect(config).toHaveProperty('positionExpiry');
      expect(config).toHaveProperty('userOfflineTimeout');
      expect(config).toHaveProperty('cleanupInterval');
      expect(config).toHaveProperty('batchSize');
      expect(config).toHaveProperty('enabled');
    });

    it('应该成功更新配置', () => {
      const newConfig = {
        cleanupInterval: 10000,
        batchSize: 50,
        enabled: false,
      };
      
      service.updateConfig(newConfig);
      
      const config = service.getConfig();
      expect(config.cleanupInterval).toBe(newConfig.cleanupInterval);
      expect(config.batchSize).toBe(newConfig.batchSize);
      expect(config.enabled).toBe(newConfig.enabled);
    });

    it('应该在间隔时间改变时重启调度器', () => {
      const stopSpy = jest.spyOn(service, 'stopCleanupScheduler');
      const startSpy = jest.spyOn(service, 'startCleanupScheduler');
      
      service.startCleanupScheduler();
      service.updateConfig({ cleanupInterval: 20000 });
      
      expect(stopSpy).toHaveBeenCalled();
      expect(startSpy).toHaveBeenCalledTimes(2); // 初始启动 + 重启
    });

    it('应该在启用状态改变时控制调度器', () => {
      service.startCleanupScheduler();
      const stopSpy = jest.spyOn(service, 'stopCleanupScheduler');
      
      service.updateConfig({ enabled: false });
      
      expect(stopSpy).toHaveBeenCalled();
    });
  });

  describe('统计信息管理', () => {
    it('应该返回初始统计信息', () => {
      const stats = service.getStats();
      
      expect(stats.totalCleanups).toBe(0);
      expect(stats.cleanedSessions).toBe(0);
      expect(stats.cleanedPositions).toBe(0);
      expect(stats.cleanedUsers).toBe(0);
      expect(stats.errorCount).toBe(0);
    });

    it('应该成功重置统计信息', () => {
      // 先执行一次清理以产生统计数据
      service['stats'].totalCleanups = 5;
      service['stats'].cleanedSessions = 10;
      
      service.resetStats();
      
      const stats = service.getStats();
      expect(stats.totalCleanups).toBe(0);
      expect(stats.cleanedSessions).toBe(0);
    });

    it('应该正确计算平均清理时间', async () => {
      // 重置清理时间数组
      service['cleanupTimes'] = [100, 200, 300];
      
      // 手动触发统计更新
      service['updateStats']([], 0);
      
      const stats = service.getStats();
      expect(stats.avgCleanupTime).toBeGreaterThan(0);
    });
  });

  describe('清理时间管理', () => {
    it('应该返回下次清理时间', () => {
      service.updateConfig({ enabled: true });
      service.startCleanupScheduler();
      service['stats'].lastCleanupTime = Date.now();
      
      const nextTime = service.getNextCleanupTime();
      
      expect(nextTime).toBeGreaterThan(Date.now());
      
      service.stopCleanupScheduler();
    });

    it('应该在禁用时返回0', () => {
      service.updateConfig({ enabled: false });
      
      const nextTime = service.getNextCleanupTime();
      
      expect(nextTime).toBe(0);
    });

    it('应该正确判断是否需要立即清理', () => {
      service.updateConfig({ enabled: true, cleanupInterval: 1000 });
      
      // 设置上次清理时间为很久以前
      service['stats'].lastCleanupTime = Date.now() - 2000;
      
      expect(service.shouldCleanupNow()).toBe(true);
    });

    it('应该在最近清理过时返回false', () => {
      service.updateConfig({ enabled: true, cleanupInterval: 10000 });
      
      // 设置上次清理时间为刚刚
      service['stats'].lastCleanupTime = Date.now();
      
      expect(service.shouldCleanupNow()).toBe(false);
    });
  });

  describe('健康状态检查', () => {
    it('应该返回健康状态', () => {
      service.updateConfig({ enabled: true });
      service['stats'].lastCleanupTime = Date.now();
      
      const health = service.getHealthStatus();
      
      expect(health).toHaveProperty('status');
      expect(health).toHaveProperty('details');
      expect(['healthy', 'degraded', 'unhealthy']).toContain(health.status);
    });

    it('应该在禁用时返回降级状态', () => {
      service.updateConfig({ enabled: false });
      
      const health = service.getHealthStatus();
      
      expect(health.status).toBe('degraded');
    });

    it('应该在长时间未清理时返回不健康状态', () => {
      service.updateConfig({ enabled: true, cleanupInterval: 1000 });
      service['stats'].lastCleanupTime = Date.now() - 10000; // 10秒前
      
      const health = service.getHealthStatus();
      
      expect(health.status).toBe('unhealthy');
    });

    it('应该在错误率过高时返回降级状态', () => {
      service.updateConfig({ enabled: true });
      service['stats'].lastCleanupTime = Date.now();
      service['stats'].totalCleanups = 10;
      service['stats'].errorCount = 2; // 20%错误率
      
      const health = service.getHealthStatus();
      
      expect(health.status).toBe('degraded');
    });
  });

  describe('私有方法测试', () => {
    it('应该成功执行清理过期会话', async () => {
      const result = await service['cleanupExpiredSessions']();
      
      expect(result).toHaveProperty('operation', 'cleanup_expired_sessions');
      expect(result).toHaveProperty('count');
      expect(result).toHaveProperty('duration');
      expect(result).toHaveProperty('success');
      expect(typeof result.count).toBe('number');
      expect(typeof result.duration).toBe('number');
      expect(typeof result.success).toBe('boolean');
    });

    it('应该成功执行清理过期位置数据', async () => {
      const result = await service['cleanupExpiredPositions']();
      
      expect(result).toHaveProperty('operation', 'cleanup_expired_positions');
      expect(result.success).toBe(true);
    });

    it('应该成功执行清理离线用户', async () => {
      const result = await service['cleanupOfflineUsers']();
      
      expect(result).toHaveProperty('operation', 'cleanup_offline_users');
      expect(result.success).toBe(true);
    });

    it('应该成功执行清理缓存数据', async () => {
      const result = await service['cleanupCacheData']();
      
      expect(result).toHaveProperty('operation', 'cleanup_cache_data');
      expect(result.success).toBe(true);
    });

    it('应该正确更新统计信息', () => {
      const results = [
        { operation: 'cleanup_expired_sessions', count: 5, duration: 100, success: true },
        { operation: 'cleanup_expired_positions', count: 10, duration: 200, success: true },
        { operation: 'cleanup_offline_users', count: 3, duration: 50, success: false, error: '测试错误' },
      ];
      
      const statsBefore = service.getStats();
      service['updateStats'](results, 350);
      const statsAfter = service.getStats();
      
      expect(statsAfter.totalCleanups).toBe(statsBefore.totalCleanups + 1);
      expect(statsAfter.cleanedSessions).toBe(statsBefore.cleanedSessions + 5);
      expect(statsAfter.cleanedPositions).toBe(statsBefore.cleanedPositions + 10);
      expect(statsAfter.cleanedUsers).toBe(statsBefore.cleanedUsers + 3);
      expect(statsAfter.errorCount).toBe(statsBefore.errorCount + 1);
      expect(statsAfter.lastError).toBe('测试错误');
    });
  });

  describe('边界条件测试', () => {
    it('应该处理空的清理结果', () => {
      expect(() => service['updateStats']([], 0)).not.toThrow();
    });

    it('应该处理极大的清理时间记录', () => {
      // 添加大量清理时间记录
      for (let i = 0; i < 150; i++) {
        service['cleanupTimes'].push(100 + i);
      }
      
      service['updateStats']([
        { operation: 'test', count: 1, duration: 200, success: true }
      ], 200);
      
      // 应该只保留最近的记录
      expect(service['cleanupTimes'].length).toBeLessThanOrEqual(100);
    });

    it('应该处理配置中的无效值', () => {
      expect(() => service.updateConfig({
        cleanupInterval: -1000,
        batchSize: 0,
      })).not.toThrow();
    });
  });

  describe('性能测试', () => {
    it('应该在合理时间内完成清理操作', async () => {
      const startTime = Date.now();
      
      await service.manualCleanup();
      
      const duration = Date.now() - startTime;
      expect(duration).toBeLessThan(1000); // 应该在1秒内完成
    });

    it('应该正确处理并发清理请求', async () => {
      const promises = [
        service.manualCleanup(),
        service.manualCleanup(),
        service.manualCleanup(),
      ];
      
      const results = await Promise.all(promises);
      
      expect(results).toHaveLength(3);
      results.forEach(result => {
        expect(result).toBeInstanceOf(Array);
      });
    });
  });
});