import { describe, it, expect, beforeEach, vi } from 'vitest';
import { testClient } from 'hono/testing';
import {
  IntegrationTestDatabase,
  setupIntegrationDatabaseHooksWithEntities
} from '@d8d/shared-test-util';
import { systemConfigRoutesMt } from '../../src/routes/system-config.routes.mt';
import { SystemConfigMt } from '../../src/entities/system-config.entity.mt';
import { SystemConfigServiceMt } from '../../src/services/system-config.service.mt';
import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
import { FileMt } from '@d8d/core-module-mt/file-module-mt';
import { TestDataFactory } from '../utils/integration-test-db';
import { AuthService } from '@d8d/core-module-mt/auth-module-mt';
import { UserServiceMt } from '@d8d/core-module-mt/user-module-mt';
import { redisUtil } from '@d8d/shared-utils';

// 设置集成测试钩子
setupIntegrationDatabaseHooksWithEntities([SystemConfigMt, UserEntityMt, RoleMt, FileMt])

describe('系统配置路由API集成测试 (使用hono/testing)', () => {
  let client: ReturnType<typeof testClient<typeof systemConfigRoutesMt>>;
  let authService: AuthService;
  let userService: UserServiceMt;
  let testToken: string;
  let testUser: any;

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

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

    // 初始化服务
    userService = new UserServiceMt(dataSource);
    authService = new AuthService(userService);

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

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

  describe('CRUD Operations', () => {
    it('应该成功创建系统配置', async () => {
      const configData = {
        configKey: 'app.login.enabled',
        configValue: 'true',
        description: '控制小程序登录功能是否开启'
      };

      const response = await client.index.$post({
        json: configData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(201);
      const result = await response.json();
      if ('configKey' in result) {
        expect(result.configKey).toBe(configData.configKey);
        expect(result.configValue).toBe(configData.configValue);
      }
    });

    it('应该根据ID获取系统配置', async () => {
      // 先创建配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const config = await systemConfigService.create({
        configKey: 'app.payment.enabled',
        configValue: 'true',
        description: '控制支付功能是否开启',
        tenantId: testUser.tenantId
      } as SystemConfigMt);

      const response = await client[':id'].$get({
        param: { id: config.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(200);
      const result = await response.json();
      if ('id' in result) {
        expect(result.id).toBe(config.id);
        expect(result.configKey).toBe(config.configKey);
      }
    });

    it('应该更新系统配置', async () => {
      // 先创建配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const config = await systemConfigService.create({
        configKey: 'app.notification.enabled',
        configValue: 'true',
        description: '控制通知功能是否开启',
        tenantId: testUser.tenantId
      } as SystemConfigMt);

      const updateData = {
        configValue: 'false',
        description: '通知功能已关闭'
      };

      const response = await client[':id'].$put({
        param: { id: config.id },
        json: updateData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(200);
      const result = await response.json();
      if ('configValue' in result) {
        expect(result.configValue).toBe(updateData.configValue);
        expect(result.description).toBe(updateData.description);
      }
    });

    it('应该删除系统配置', async () => {
      // 先创建配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const config = await systemConfigService.create({
        configKey: 'app.analytics.enabled',
        configValue: 'true',
        description: '控制分析功能是否开启',
        tenantId: testUser.tenantId
      } as SystemConfigMt);

      const response = await client[':id'].$delete({
        param: { id: config.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(204);

      // 验证配置已被删除
      const deletedConfig = await systemConfigService.getById(config.id);
      expect(deletedConfig).toBeNull();
    });

    it('应该列出系统配置列表', async () => {
      // 创建多个配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      await systemConfigService.create({
        configKey: 'app.feature1.enabled',
        configValue: 'true',
        tenantId: testUser.tenantId
      } as SystemConfigMt);

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

      const response = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(200);
      const result = await response.json();
      if ('data' in result) {
        expect(result.data).toHaveLength(2);
      }
    });
  });

  describe('Multi-tenant Isolation', () => {
    let tenant1User: any;
    let tenant2User: any;
    let tenant1Token: string;
    let tenant2Token: string;

    beforeEach(async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      // 创建租户1的用户
      tenant1User = await TestDataFactory.createTestUser(dataSource, {
        username: 'tenant1_user_systemconfig',
        password: 'TestPassword123!',
        email: 'tenant1_systemconfig@example.com',
        tenantId: 1
      });

      // 创建租户2的用户
      tenant2User = await TestDataFactory.createTestUser(dataSource, {
        username: 'tenant2_user_systemconfig',
        password: 'TestPassword123!',
        email: 'tenant2_systemconfig@example.com',
        tenantId: 2
      });

      // 生成租户用户的token
      tenant1Token = authService.generateToken(tenant1User);
      tenant2Token = authService.generateToken(tenant2User);
    });

    it('应该按租户隔离配置', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);

      // 为租户1创建配置
      await systemConfigService.create({
        configKey: 'app.shared.config',
        configValue: 'tenant1-value',
        tenantId: 1
      } as SystemConfigMt);

      // 为租户2创建配置
      await systemConfigService.create({
        configKey: 'app.shared.config',
        configValue: 'tenant2-value',
        tenantId: 2
      } as SystemConfigMt);

      // 查询租户1的配置
      const response1 = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${tenant1Token}`
        }
      });

      expect(response1.status).toBe(200);
      const result1 = await response1.json();
      if ('data' in result1) {
        expect(result1.data).toHaveLength(1);
        expect(result1.data[0].configValue).toBe('tenant1-value');
      }

      // 查询租户2的配置
      const response2 = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${tenant2Token}`
        }
      });

      expect(response2.status).toBe(200);
      const result2 = await response2.json();
      if ('data' in result2) {
        expect(result2.data).toHaveLength(1);
        expect(result2.data[0].configValue).toBe('tenant2-value');
      }
    });
  });

  describe('Data Validation', () => {
    it('应该验证必填字段', async () => {
      const invalidData = {
        configKey: '', // 空字符串
        configValue: 'true'
      };

      const response = await client.index.$post({
        json: invalidData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(400);
    });

    it('应该验证字段长度', async () => {
      const invalidData = {
        configKey: 'a'.repeat(256), // 超过255字符
        configValue: 'true'
      };

      const response = await client.index.$post({
        json: invalidData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(400);
    });
  });

  describe('自定义路由缓存刷新验证', () => {
    beforeEach(async () => {
      // 清除测试缓存
      await redisUtil.deleteSystemConfig(testUser.tenantId, 'app.login.enabled');
      await redisUtil.deleteSystemConfig(testUser.tenantId, 'app.payment.enabled');
    });

    it('应该通过自定义创建路由刷新缓存', async () => {
      const configData = {
        configKey: 'app.login.enabled',
        configValue: 'true',
        description: '控制小程序登录功能是否开启'
      };

      // 验证缓存初始为空
      const initialCache = await redisUtil.getSystemConfig(testUser.tenantId, configData.configKey);
      expect(initialCache).toBeNull();

      // 通过自定义路由创建配置
      const response = await client.index.$post({
        json: configData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(201);
      const result = await response.json() as any;
      expect(result.configKey).toBe(configData.configKey);
      expect(result.configValue).toBe(configData.configValue);

      // 验证缓存已被刷新（为空，因为setConfig会删除缓存）
      const afterCreateCache = await redisUtil.getSystemConfig(testUser.tenantId, configData.configKey);
      expect(afterCreateCache).toBeNull();
    });

    it('应该通过自定义更新路由刷新缓存', async () => {
      // 先创建配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const config = await systemConfigService.create({
        configKey: 'app.payment.enabled',
        configValue: 'true',
        description: '控制支付功能是否开启',
        tenantId: testUser.tenantId
      } as any);

      // 设置缓存
      await redisUtil.setSystemConfig(testUser.tenantId, config.configKey, 'cached-value', 3600);
      const initialCache = await redisUtil.getSystemConfig(testUser.tenantId, config.configKey);
      expect(initialCache).toBe('cached-value');

      // 通过自定义路由更新配置
      const updateData = {
        configValue: 'false',
        description: '支付功能已关闭'
      };

      const response = await client[':id'].$put({
        param: { id: config.id },
        json: updateData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(200);
      const result = await response.json() as any;
      expect(result.configValue).toBe(updateData.configValue);

      // 验证缓存已被刷新
      const afterUpdateCache = await redisUtil.getSystemConfig(testUser.tenantId, config.configKey);
      expect(afterUpdateCache).toBeNull();
    });

    it('应该通过自定义删除路由刷新缓存', async () => {
      // 先创建配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const config = await systemConfigService.create({
        configKey: 'app.analytics.enabled',
        configValue: 'true',
        description: '控制分析功能是否开启',
        tenantId: testUser.tenantId
      } as any);

      // 设置缓存
      await redisUtil.setSystemConfig(testUser.tenantId, config.configKey, 'cached-value', 3600);
      const initialCache = await redisUtil.getSystemConfig(testUser.tenantId, config.configKey);
      expect(initialCache).toBe('cached-value');

      // 通过自定义路由删除配置
      const response = await client[':id'].$delete({
        param: { id: config.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(204);

      // 验证缓存已被刷新
      const afterDeleteCache = await redisUtil.getSystemConfig(testUser.tenantId, config.configKey);
      expect(afterDeleteCache).toBeNull();
    });
  });

  describe('自定义路由多租户隔离验证', () => {
    let tenant1User: any;
    let tenant2User: any;
    let tenant1Token: string;
    let tenant2Token: string;

    beforeEach(async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      // 创建租户1的用户
      tenant1User = await TestDataFactory.createTestUser(dataSource, {
        username: 'tenant1_customroutes',
        password: 'TestPassword123!',
        email: 'tenant1_customroutes@example.com',
        tenantId: 1
      });

      // 创建租户2的用户
      tenant2User = await TestDataFactory.createTestUser(dataSource, {
        username: 'tenant2_customroutes',
        password: 'TestPassword123!',
        email: 'tenant2_customroutes@example.com',
        tenantId: 2
      });

      // 生成租户用户的token
      tenant1Token = authService.generateToken(tenant1User);
      tenant2Token = authService.generateToken(tenant2User);

      // 清除测试缓存
      await redisUtil.deleteSystemConfig(1, 'app.shared.config');
      await redisUtil.deleteSystemConfig(2, 'app.shared.config');
    });

    it('应该确保多租户缓存隔离', async () => {
      const configData = {
        configKey: 'app.shared.config',
        configValue: 'tenant1-value',
        description: '共享配置'
      };

      // 租户1创建配置
      const response1 = await client.index.$post({
        json: configData
      }, {
        headers: {
          'Authorization': `Bearer ${tenant1Token}`
        }
      });

      expect(response1.status).toBe(201);

      // 租户2创建配置
      const response2 = await client.index.$post({
        json: { ...configData, configValue: 'tenant2-value' }
      }, {
        headers: {
          'Authorization': `Bearer ${tenant2Token}`
        }
      });

      expect(response2.status).toBe(201);

      // 验证租户1的缓存操作不影响租户2
      const tenant1Cache = await redisUtil.getSystemConfig(1, configData.configKey);
      const tenant2Cache = await redisUtil.getSystemConfig(2, configData.configKey);

      // 两个租户的缓存都应该是空的，因为setConfig会删除缓存
      expect(tenant1Cache).toBeNull();
      expect(tenant2Cache).toBeNull();
    });

    it('应该验证租户ID正确提取', async () => {
      const configData = {
        configKey: 'app.tenant.specific',
        configValue: 'tenant-specific-value',
        description: '租户特定配置'
      };

      // 租户1创建配置
      const response = await client.index.$post({
        json: configData
      }, {
        headers: {
          'Authorization': `Bearer ${tenant1Token}`
        }
      });

      expect(response.status).toBe(201);
      const result = await response.json() as any;

      // 验证配置属于正确的租户
      expect(result.tenantId).toBe(1);

      // 验证租户2无法访问租户1的配置
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const systemConfigService = new SystemConfigServiceMt(dataSource);
      const tenant2Configs = await systemConfigService.getAllConfigs(2);
      const tenant2HasConfig = tenant2Configs.some(config => config.configKey === configData.configKey);
      expect(tenant2HasConfig).toBe(false);
    });
  });
});