import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import {
  IntegrationTestDatabase,
  setupIntegrationDatabaseHooksWithEntities
} from '@d8d/shared-test-util';
import { PaymentMtService } from '../../src/services/payment.mt.service';
import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
import { SystemConfigMt } from '@d8d/core-module-mt/system-config-module-mt';
import { UserEntityMt, RoleMt } from '@d8d/core-module-mt/user-module-mt';
import { FileMt } from '@d8d/core-module-mt/file-module-mt';

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

/**
 * 支付模块系统配置集成测试
 * 验证PaymentMtService与SystemConfigServiceMt的集成
 */
describe('支付模块系统配置集成测试', () => {
  let paymentMtService: PaymentMtService;
  let systemConfigService: SystemConfigServiceMt;
  const testTenantId = 1;

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

    paymentMtService = new PaymentMtService(dataSource);
    systemConfigService = new SystemConfigServiceMt(dataSource);

    // 清理测试配置
    await cleanupTestConfigs(testTenantId);
  });

  afterEach(async () => {
    // 清理测试配置
    await cleanupTestConfigs(testTenantId);
  });

  async function cleanupTestConfigs(tenantId: number) {
    if (!systemConfigService) return;

    const configKeys = [
      'wx.payment.merchant.id',
      'wx.mini.app.id',
      'wx.payment.v3.key',
      'wx.payment.notify.url',
      'wx.payment.cert.serial.no',
      'wx.payment.public.key',
      'wx.payment.private.key'
    ];

    for (const key of configKeys) {
      try {
        await systemConfigService.deleteConfig(key, tenantId);
      } catch (error) {
        // 忽略删除失败的情况
      }
    }
  }

  async function setupCompletePaymentConfig(tenantId: number, tenantPrefix: string) {
    await systemConfigService.setConfig('wx.payment.merchant.id', `${tenantPrefix}-merchant-id`, tenantId, `${tenantPrefix}商户ID`);
    await systemConfigService.setConfig('wx.mini.app.id', `${tenantPrefix}-app-id`, tenantId, `${tenantPrefix}小程序AppID`);
    await systemConfigService.setConfig('wx.payment.v3.key', `${tenantPrefix}-v3-key`, tenantId, `${tenantPrefix}V3密钥`);
    await systemConfigService.setConfig('wx.payment.notify.url', `${tenantPrefix}-notify-url`, tenantId, `${tenantPrefix}回调URL`);
    await systemConfigService.setConfig('wx.payment.cert.serial.no', `${tenantPrefix}-cert-serial`, tenantId, `${tenantPrefix}证书序列号`);
    await systemConfigService.setConfig('wx.payment.public.key', `${tenantPrefix}-public-key`, tenantId, `${tenantPrefix}公钥`);
    await systemConfigService.setConfig('wx.payment.private.key', `${tenantPrefix}-private-key`, tenantId, `${tenantPrefix}私钥`);
  }

  describe('系统配置读取功能', () => {
    it('应该从系统配置获取支付配置', async () => {
      // 设置测试支付配置
      await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID');
      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');
      await systemConfigService.setConfig('wx.payment.v3.key', 'test-v3-key', testTenantId, '测试V3密钥');
      await systemConfigService.setConfig('wx.payment.notify.url', 'https://test.com/notify', testTenantId, '测试回调URL');
      await systemConfigService.setConfig('wx.payment.cert.serial.no', 'test-serial-no', testTenantId, '测试证书序列号');
      await systemConfigService.setConfig('wx.payment.public.key', 'test-public-key', testTenantId, '测试公钥');
      await systemConfigService.setConfig('wx.payment.private.key', 'test-private-key', testTenantId, '测试私钥');

      // 验证配置读取
      const config = await paymentMtService['getPaymentConfig'](testTenantId);

      expect(config.merchantId).toBe('test-merchant-id');
      expect(config.appId).toBe('test-app-id');
      expect(config.v3Key).toBe('test-v3-key');
      expect(config.notifyUrl).toBe('https://test.com/notify');
      expect(config.certSerialNo).toBe('test-serial-no');
      expect(config.publicKey).toBe('test-public-key');
      expect(config.privateKey).toBe('test-private-key');
    });

    it('应该支持批量获取支付配置', async () => {
      // 设置测试配置
      await systemConfigService.setConfig('wx.payment.merchant.id', 'test-merchant-id', testTenantId, '测试商户ID');
      await systemConfigService.setConfig('wx.mini.app.id', 'test-app-id', testTenantId, '测试小程序AppID');

      // 批量获取配置
      const configs = await systemConfigService.getConfigsByKeys(
        ['wx.payment.merchant.id', 'wx.mini.app.id'],
        testTenantId
      );

      expect(configs['wx.payment.merchant.id']).toBe('test-merchant-id');
      expect(configs['wx.mini.app.id']).toBe('test-app-id');
    });
  });

  describe('租户配置隔离', () => {
    const tenant1Id = 1;
    const tenant2Id = 2;

    it('应该支持不同租户的独立支付配置', async () => {
      // 为租户1设置完整的支付配置
      await setupCompletePaymentConfig(tenant1Id, 'tenant1');

      // 为租户2设置不同的完整支付配置
      await setupCompletePaymentConfig(tenant2Id, 'tenant2');

      // 验证租户1的配置
      const tenant1Config = await paymentMtService['getPaymentConfig'](tenant1Id);

      // 验证租户2的配置
      const tenant2Config = await paymentMtService['getPaymentConfig'](tenant2Id);

      expect(tenant1Config.merchantId).toBe('tenant1-merchant-id');
      expect(tenant1Config.appId).toBe('tenant1-app-id');
      expect(tenant2Config.merchantId).toBe('tenant2-merchant-id');
      expect(tenant2Config.appId).toBe('tenant2-app-id');

      // 验证配置隔离
      expect(tenant1Config.merchantId).not.toBe(tenant2Config.merchantId);
      expect(tenant1Config.appId).not.toBe(tenant2Config.appId);
    });
  });

  describe('配置回退机制', () => {
    it('应该在系统配置不存在时回退到环境变量', async () => {
      // 不设置系统配置，依赖环境变量
      // 注意：这里假设环境变量已设置，实际测试时需要确保环境变量存在

      try {
        const config = await paymentMtService['getPaymentConfig'](testTenantId);
        // 如果环境变量存在，应该能获取到配置
        expect(config).toBeDefined();
      } catch (error) {
        // 如果环境变量不存在，应该抛出配置不完整的错误
        expect(error).toBeInstanceOf(Error);
        expect((error as Error).message).toContain('微信支付配置不完整');
      }
    });

    it('应该优先使用系统配置', async () => {
      // 设置完整的系统配置
      await setupCompletePaymentConfig(testTenantId, 'system');

      // 获取配置，应该优先使用系统配置
      const config = await paymentMtService['getPaymentConfig'](testTenantId);

      // 验证所有配置都来自系统配置
      expect(config.merchantId).toBe('system-merchant-id');
      expect(config.appId).toBe('system-app-id');
      expect(config.v3Key).toBe('system-v3-key');
    });
  });

  describe('PaymentMtService集成', () => {
    it('应该正确注入SystemConfigServiceMt依赖', () => {
      // 验证服务实例化
      expect(paymentMtService).toBeDefined();
      expect(paymentMtService).toBeInstanceOf(PaymentMtService);
    });

    it('应该支持动态配置初始化', async () => {
      // 验证initializeWxPay方法存在
      const initializeMethod = paymentMtService['initializeWxPay'];
      expect(typeof initializeMethod).toBe('function');

      // 验证getPaymentConfig方法存在
      const getConfigMethod = paymentMtService['getPaymentConfig'];
      expect(typeof getConfigMethod).toBe('function');
    });

    it('应该支持租户ID参数', async () => {
      // 验证createPayment方法支持tenantId参数
      const method = paymentMtService.createPayment;
      expect(typeof method).toBe('function');

      // 验证方法签名包含tenantId参数
      expect(method.length).toBeGreaterThanOrEqual(6);
    });
  });

  describe('配置验证', () => {
    it('应该验证配置完整性', async () => {
      // 不设置任何配置，应该抛出配置不完整的错误
      await expect(paymentMtService['getPaymentConfig'](testTenantId))
        .rejects
        .toThrow('微信支付配置不完整');
    });

    it('应该处理证书字符串格式', async () => {
      // 设置完整的支付配置，包含包含转义字符的证书
      await setupCompletePaymentConfig(testTenantId, 'cert-test');

      // 覆盖证书配置为包含转义字符的格式
      await systemConfigService.setConfig('wx.payment.public.key', 'test\\npublic\\nkey', testTenantId, '测试公钥');
      await systemConfigService.setConfig('wx.payment.private.key', 'test\\nprivate\\nkey', testTenantId, '测试私钥');

      // 获取配置并验证格式处理
      const config = await paymentMtService['getPaymentConfig'](testTenantId);

      // 验证转义字符被正确处理
      expect(config.publicKey).toBe('test\npublic\nkey');
      expect(config.privateKey).toBe('test\nprivate\nkey');
    });
  });
});