import { describe, it, expect, beforeEach, vi } from 'vitest';
import { testClient } from 'hono/testing';
import {
  IntegrationTestDatabase,
  setupIntegrationDatabaseHooks,
  TestDataFactory
} from '~/utils/server/integration-test-db';
import { paymentRoutesExport } from '@d8d/server/api';
import { AuthService } from '@d8d/server/modules/auth/auth.service';
import { UserService } from '@d8d/server/modules/users/user.service';
import { OrderStatus, PaymentStatus } from '@d8d/server/share/order.types';
import { config } from 'dotenv';
import { resolve } from 'path';
// 导入微信支付SDK用于模拟
import WxPay from 'wechatpay-node-v3';

// 在测试环境中加载环境变量
config({ path: resolve(process.cwd(), '.env') });

vi.mock('wechatpay-node-v3')


// 设置集成测试钩子
setupIntegrationDatabaseHooks()

describe('支付API集成测试', () => {
  let client: ReturnType<typeof testClient<typeof paymentRoutesExport>>['api']['v1'];
  let testToken: string;
  let testUser: any;
  let testRoute: any;
  let testOrder: any;

  beforeEach(async () => {
    // 创建测试客户端
    client = testClient(paymentRoutesExport).api.v1;

    // 创建测试用户并生成token
    const dataSource = await IntegrationTestDatabase.getDataSource();

    const userService = new UserService(dataSource);
    const authService = new AuthService(userService);

    // 创建测试用户，确保有openid字段
    testUser = await TestDataFactory.createTestUser(dataSource, {
      openid: 'oJy1-16IIG18XZLl7G32k1hHMUFg'
    });

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

    // 创建测试路线
    testRoute = await TestDataFactory.createTestRoute(dataSource);

    // 创建测试订单
    testOrder = await TestDataFactory.createTestOrder(dataSource, {
      userId: testUser.id,
      routeId: testRoute.id,
      passengerCount: 2,
      totalAmount: 200.00,
      status: OrderStatus.PENDING_PAYMENT,
      paymentStatus: PaymentStatus.PENDING
    });

    // 设置微信支付SDK的全局mock
    const mockWxPay = {
      transactions_jsapi: vi.fn().mockResolvedValue({
        package: 'prepay_id=wx_test_prepay_id_123456',
        timeStamp: Math.floor(Date.now() / 1000).toString(),
        nonceStr: 'test_nonce_string',
        signType: 'RSA',
        paySign: 'test_pay_sign'
      }),
      verifySign: vi.fn().mockResolvedValue(true),
      decipher_gcm: vi.fn().mockReturnValue(JSON.stringify({
        out_trade_no: `ORDER_${testOrder.id}_${Date.now()}`,
        trade_state: 'SUCCESS',
        transaction_id: 'test_transaction_id',
        amount: {
          total: 20000
        }
      })),
      getSignature: vi.fn().mockReturnValue('mock_signature')
    };

    // 模拟PaymentService的wxPay实例
    vi.mocked(WxPay).mockImplementation(() => mockWxPay as any);

  });

  describe('POST /payment - 创建支付', () => {
    it('应该成功创建支付订单', async () => {
      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000, // 200元，单位分
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const result = await response.json();

        console.debug('支付创建返回结果:', result);

        expect(result).toHaveProperty('paymentId');
        expect(result).toHaveProperty('timeStamp');
        expect(result).toHaveProperty('nonceStr');
        expect(result).toHaveProperty('package');
        expect(result).toHaveProperty('signType');
        expect(result).toHaveProperty('paySign');
        expect(result).toHaveProperty('totalAmount'); // 验证新增的金额字段
        expect(result.paymentId).toBeDefined();
        expect(result.paymentId).not.toBe('undefined');
        expect(result.totalAmount).toBe(20000); // 验证金额正确返回
      }
    });

    it('应该拒绝未认证的请求', async () => {
      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000,
          description: '测试支付订单'
        }
      });

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

    it('应该验证订单存在性', async () => {
      const response = await client.payment.$post({
        json: {
          orderId: 99999, // 不存在的订单ID
          totalAmount: 20000,
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(response.status).toBe(500);
      if (response.status === 500) {
        const result = await response.json();
        expect(result.message).toContain('订单不存在');
      }
    });

    it('应该验证支付金额匹配', async () => {
      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 30000, // 金额不匹配
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(response.status).toBe(500);
      if (response.status === 500) {
        const result = await response.json();
        expect(result.message).toContain('支付金额与订单金额不匹配');
      }
    });

    it('应该验证订单支付状态', async () => {
      // 更新订单状态为已支付
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const orderRepository = dataSource.getRepository('Order');
      await orderRepository.update(testOrder.id, {
        paymentStatus: PaymentStatus.PAID
      });

      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000,
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(response.status).toBe(500);
      if (response.status === 500) {
        const result = await response.json();
        expect(result.message).toContain('订单支付状态不正确');
      }
    });

    it('应该拒绝没有openid的用户支付', async () => {
      // 创建没有openid的测试用户
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const userService = new UserService(dataSource);
      const authService = new AuthService(userService);

      const userWithoutOpenid = await TestDataFactory.createTestUser(dataSource, {
        openid: null
      });

      const tokenWithoutOpenid = authService.generateToken(userWithoutOpenid);

      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000,
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${tokenWithoutOpenid}`
          }
        });

      expect(response.status).toBe(400);
      if (response.status === 400) {
        const result = await response.json();
        expect(result.message).toContain('用户未绑定微信小程序');
      }
    });
  });

  describe('POST /payment/callback - 支付回调', () => {
    it('应该成功处理支付成功回调', async () => {
      const timestamp = Math.floor(Date.now() / 1000).toString();
      const nonce = Math.random().toString(36).substring(2, 15);

      const callbackData = {
        id: 'EV-201802251122332345',
        create_time: '2018-06-08T10:34:56+08:00',
        event_type: 'TRANSACTION.SUCCESS',
        resource_type: 'encrypt-resource',
        resource: {
          algorithm: 'AEAD_AES_256_GCM',
          ciphertext: 'encrypted_data',
          nonce: 'random_nonce',
          associated_data: 'associated_data'
        },
        summary: 'payment_success'
      };

      const response = await client.payment.callback.$post({
        json: callbackData
      }, {
        headers: {
          'wechatpay-timestamp': timestamp,
          'wechatpay-nonce': nonce,
          'wechatpay-signature': 'mock_signature_for_test',
          'wechatpay-serial': process.env.WECHAT_PLATFORM_CERT_SERIAL_NO || ''
        }
      });

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const result = await response.text();
        expect(result).toBe('SUCCESS');
      }
    });

    it('应该处理支付失败回调', async () => {
      const timestamp = Math.floor(Date.now() / 1000).toString();
      const nonce = Math.random().toString(36).substring(2, 15);

      const callbackData = {
        id: 'EV-201802251122332346',
        create_time: '2018-06-08T10:34:56+08:00',
        event_type: 'TRANSACTION.FAIL',
        resource_type: 'encrypt-resource',
        resource: {
          algorithm: 'AEAD_AES_256_GCM',
          ciphertext: 'encrypted_data',
          nonce: 'random_nonce',
          associated_data: 'associated_data'
        },
        summary: 'payment_failed'
      };

      const response = await client.payment.callback.$post({
        json: callbackData
      }, {
        headers: {
          'wechatpay-timestamp': timestamp,
          'wechatpay-nonce': nonce,
          'wechatpay-signature': 'mock_signature_for_test',
          'wechatpay-serial': process.env.WECHAT_PLATFORM_CERT_SERIAL_NO || ''
        }
      });

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const result = await response.text();
        expect(result).toBe('SUCCESS');
      }
    });

    it('应该处理无效的回调数据', async () => {
      const response = await client.payment.callback.$post({
        json: { invalid: 'data' } as any
      }, {
        headers: {
          'wechatpay-timestamp': '1622456896',
          'wechatpay-nonce': 'random_nonce_string',
          'wechatpay-signature': 'signature_data',
          'wechatpay-serial': process.env.WECHAT_PLATFORM_CERT_SERIAL_NO || ''
        }
      });

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

  describe('支付状态流转测试', () => {
    it('应该正确更新订单支付状态', async () => {
      // 创建支付
      const createResponse = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000,
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(createResponse.status).toBe(200);

      // 验证订单状态已更新为处理中
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const orderRepository = dataSource.getRepository('Order');
      const updatedOrder = await orderRepository.findOne({
        where: { id: testOrder.id }
      });

      expect(updatedOrder?.paymentStatus).toBe(PaymentStatus.PROCESSING);
    });
  });

  describe('微信支付JSAPI参数生成测试', () => {
    it('应该生成正确的支付参数格式', async () => {
      const response = await client.payment.$post({
        json: {
          orderId: testOrder.id,
          totalAmount: 20000,
          description: '测试支付订单'
        },
      },
        {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const result = await response.json();

        // 验证返回参数格式
        expect(result.timeStamp).toMatch(/^\d+$/); // 时间戳应该是数字字符串
        expect(result.nonceStr).toBeTruthy(); // 随机字符串应该存在
        expect(result.package).toContain('prepay_id=');
        expect(result.signType).toBe('RSA');
        expect(result.paySign).toBeTruthy(); // 签名应该存在
        expect(result.totalAmount).toBe(20000); // 验证金额字段正确返回
      }
    });
  });
});