import { describe, it, expect, beforeEach, vi } from 'vitest';
import { testClient } from 'hono/testing';
import {
  IntegrationTestDatabase,
  setupIntegrationDatabaseHooksWithEntities
} from '@d8d/shared-test-util';
import { systemConfigRoutes } from '../../src/routes/system-config.routes';
import { SystemConfig } from '../../src/entities/system-config.entity';
import { SystemConfigService } from '../../src/services/system-config.service';
import { UserEntity, Role } from '@d8d/core-module/user-module';
import { File } from '@d8d/core-module/file-module';
import { TestDataFactory } from '../utils/integration-test-db';
import { AuthService } from '@d8d/core-module/auth-module';
import { UserService } from '@d8d/core-module/user-module';
import { redisUtil } from '@d8d/shared-utils';

// 设置集成测试钩子
setupIntegrationDatabaseHooksWithEntities([SystemConfig, UserEntity, Role, File])

describe('系统配置Redis缓存集成测试', () => {
  let client: ReturnType<typeof testClient<typeof systemConfigRoutes>>;
  let authService: AuthService;
  let userService: UserService;
  let systemConfigService: SystemConfigService;
  let testToken: string;
  let testUser: any;

  beforeEach(async () => {
    // 创建测试客户端
    client = testClient(systemConfigRoutes);

    // 获取数据源
    const dataSource = await IntegrationTestDatabase.getDataSource();
    if (!dataSource) throw new Error('Database not initialized');

    // 初始化服务
    userService = new UserService(dataSource);
    authService = new AuthService(userService);
    systemConfigService = new SystemConfigService(dataSource);

    // 创建测试用户并生成token
    testUser = await TestDataFactory.createTestUser(dataSource, {
      username: 'testuser_rediscache',
      password: 'TestPassword123!',
      email: 'testuser_rediscache@example.com'
    });

    // 生成测试用户的token
    testToken = authService.generateToken(testUser);

    // 清除测试前的缓存
  });

  describe('缓存命中测试', () => {
    it('应该从缓存中获取配置值', async () => {
      // 先创建配置
      const config = await systemConfigService.create({
        configKey: 'app.cache.test',
        configValue: 'cached-value',
        description: '缓存测试配置',
      } as SystemConfig);

      // 第一次查询 - 应该从数据库获取并写入缓存
      const firstResult = await systemConfigService.getConfigByKey('app.cache.test');
      expect(firstResult).toBe('cached-value');

      // 验证缓存已写入
      const cachedValue = await redisUtil.getSystemConfig('app.cache.test');
      expect(cachedValue).toBe('cached-value');

      // 第二次查询 - 应该从缓存获取
      const secondResult = await systemConfigService.getConfigByKey('app.cache.test');
      expect(secondResult).toBe('cached-value');
    });

    it('应该批量从缓存中获取配置值', async () => {
      // 创建多个配置
      await systemConfigService.create({
        configKey: 'app.feature1.enabled',
        configValue: 'true',
      } as SystemConfig);

      await systemConfigService.create({
        configKey: 'app.feature2.enabled',
        configValue: 'false',
      } as SystemConfig);

      // 第一次批量查询 - 应该从数据库获取并写入缓存
      const firstResult = await systemConfigService.getConfigsByKeys(
        ['app.feature1.enabled', 'app.feature2.enabled']
      );
      expect(firstResult['app.feature1.enabled']).toBe('true');
      expect(firstResult['app.feature2.enabled']).toBe('false');

      // 验证缓存已写入
      const cachedValues = await redisUtil.getSystemConfigs(['app.feature1.enabled', 'app.feature2.enabled']);
      expect(cachedValues['app.feature1.enabled']).toBe('true');
      expect(cachedValues['app.feature2.enabled']).toBe('false');

      // 第二次批量查询 - 应该从缓存获取
      const secondResult = await systemConfigService.getConfigsByKeys(
        ['app.feature1.enabled', 'app.feature2.enabled']
      );
      expect(secondResult['app.feature1.enabled']).toBe('true');
      expect(secondResult['app.feature2.enabled']).toBe('false');
    });
  });

  describe('缓存失效测试', () => {
    it('应该在配置更新时清除缓存', async () => {
      // 清除可能存在的缓存
      await redisUtil.deleteSystemConfig('app.update.test');

      // 创建配置
      const config = await systemConfigService.create({
        configKey: 'app.update.test',
        configValue: 'initial-value',
      } as SystemConfig);

      // 查询一次以填充缓存
      await systemConfigService.getConfigByKey('app.update.test');

      // 验证缓存已写入
      const cachedValue = await redisUtil.getSystemConfig('app.update.test');
      console.debug('缓存值:', cachedValue, '期望值: initial-value');
      expect(cachedValue).toBe('initial-value');

      // 更新配置
      await systemConfigService.update(config.id, { configValue: 'updated-value' });

      // 等待一小段时间确保缓存操作完成
      await new Promise(resolve => setTimeout(resolve, 50));

      // 验证缓存已清除
      const clearedCache = await redisUtil.getSystemConfig('app.update.test');
      expect(clearedCache).toBeNull();

      // 再次查询应该从数据库获取新值
      const result = await systemConfigService.getConfigByKey('app.update.test');
      expect(result).toBe('updated-value');
    });

    it('应该在配置删除时清除缓存', async () => {
      // 创建配置
      const config = await systemConfigService.create({
        configKey: 'app.delete.test',
        configValue: 'to-be-deleted',
      } as SystemConfig);

      // 查询一次以填充缓存
      await systemConfigService.getConfigByKey('app.delete.test');

      // 验证缓存已写入
      const cachedValue = await redisUtil.getSystemConfig('app.delete.test');
      expect(cachedValue).toBe('to-be-deleted');

      // 删除配置
      await systemConfigService.delete(config.id);

      // 验证缓存已清除
      const clearedCache = await redisUtil.getSystemConfig('app.delete.test');
      expect(clearedCache).toBeNull();
    });
  });

  describe('缓存穿透保护测试', () => {
    it('应该防止缓存穿透攻击', async () => {
      const nonExistentKey = 'app.nonexistent.config';

      // 第一次查询不存在的配置
      const firstResult = await systemConfigService.getConfigByKey('app.nonexistent.config');
      expect(firstResult).toBeNull();

      // 验证空值缓存已设置
      const cachedValue = await redisUtil.getSystemConfig('app.nonexistent.config');
      expect(redisUtil.isNullValue(cachedValue)).toBe(true);

      // 第二次查询应该从空值缓存返回null
      const secondResult = await systemConfigService.getConfigByKey('app.nonexistent.config');
      expect(secondResult).toBeNull();
    });

    it('应该在批量查询中防止缓存穿透', async () => {
      const existentKey = 'app.existent.config';
      const nonExistentKey = 'app.nonexistent.config';

      // 创建一个存在的配置
      await systemConfigService.create({
        configKey: existentKey,
        configValue: 'existent-value',
      } as SystemConfig);

      // 批量查询包含存在和不存在的配置
      const result = await systemConfigService.getConfigsByKeys(
        [existentKey, nonExistentKey]
      );

      expect(result[existentKey]).toBe('existent-value');
      expect(result[nonExistentKey]).toBeUndefined();

      // 验证空值缓存已设置
      const cachedValues = await redisUtil.getSystemConfigs([existentKey, nonExistentKey]);
      expect(cachedValues[existentKey]).toBe('existent-value');
      expect(redisUtil.isNullValue(cachedValues[nonExistentKey])).toBe(true);
    });
  });

  // 多租户缓存隔离测试已移除，因为core-module是非多租户版本

  describe('缓存预热测试', () => {
    it('应该成功预热缓存', async () => {
      // 创建一些常用配置
      await systemConfigService.create({
        configKey: 'app.login.enabled',
        configValue: 'true',
      } as SystemConfig);

      await systemConfigService.create({
        configKey: 'app.payment.enabled',
        configValue: 'false',
      } as SystemConfig);

      // 预热缓存
      await systemConfigService.warmUpCache();

      // 验证缓存已预热
      const cachedValues = await redisUtil.getSystemConfigs([
        'app.login.enabled',
        'app.payment.enabled',
        'app.notification.enabled'
      ]);

      expect(cachedValues['app.login.enabled']).toBe('true');
      expect(cachedValues['app.payment.enabled']).toBe('false');
      expect(redisUtil.isNullValue(cachedValues['app.notification.enabled'])).toBe(true);
    });
  });
});