import { DataSource } from 'typeorm';
import WxPay from 'wechatpay-node-v3';
import { Buffer } from 'buffer';
import { PaymentMtEntity } from '../entities/payment.mt.entity.js';
import { PaymentStatus, RefundRequest, RefundResponse } from '../entities/payment.types.js';
import { PaymentCreateResponse } from '../entities/payment.types.js';
import { GenericCrudService } from '@d8d/shared-crud';
import { SystemConfigServiceMt } from '@d8d/core-module-mt/system-config-module-mt';
import { OrderMt } from '@d8d/orders-module-mt';

/**
 * 微信支付服务 - 多租户版本
 * 使用微信支付v3 SDK，支持小程序支付，支持租户数据隔离
 */
export class PaymentMtService extends GenericCrudService<PaymentMtEntity> {
  private wxPay: WxPay;
  private readonly systemConfigService: SystemConfigServiceMt;

  constructor(
    dataSource: DataSource
  ) {
    super(dataSource, PaymentMtEntity, {
      tenantOptions: { enabled: true, tenantIdField: 'tenantId' }
    });

    this.systemConfigService = new SystemConfigServiceMt(dataSource);

    // 微信支付SDK将在需要时动态初始化
    this.wxPay = null as any;
  }

  /**
   * 初始化微信支付SDK实例
   */
  private async initializeWxPay(tenantId: number): Promise<void> {
    const config = await this.getPaymentConfig(tenantId);

    // 初始化微信支付SDK
    this.wxPay = new WxPay({
      appid: config.appId,
      mchid: config.merchantId,
      publicKey: Buffer.from(config.publicKey),
      privateKey: Buffer.from(config.privateKey),
      key: config.v3Key,
      serial_no: config.certSerialNo
    });
  }

  /**
   * 获取支付配置（优先从系统配置获取，回退到环境变量）
   */
  private async getPaymentConfig(tenantId: number): Promise<{
    merchantId: string;
    appId: string;
    v3Key: string;
    notifyUrl: string;
    certSerialNo: string;
    publicKey: string;
    privateKey: string;
  }> {
    // 配置键定义
    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'
    ];

    // 优先从系统配置获取
    const configs = await this.systemConfigService.getConfigsByKeys(configKeys, tenantId);

    // 获取配置值，如果系统配置中没有则回退到环境变量
    const merchantId = configs['wx.payment.merchant.id'] || process.env.WECHAT_MERCHANT_ID || '';
    const appId = configs['wx.mini.app.id'] || process.env.WX_MINI_APP_ID || '';
    const v3Key = configs['wx.payment.v3.key'] || process.env.WECHAT_V3_KEY || '';
    const notifyUrl = configs['wx.payment.notify.url'] || process.env.WECHAT_PAY_NOTIFY_URL || '';
    const certSerialNo = configs['wx.payment.cert.serial.no'] || process.env.WECHAT_MERCHANT_CERT_SERIAL_NO || '';
    let publicKey = configs['wx.payment.public.key'] || process.env.WECHAT_PUBLIC_KEY || '';
    let privateKey = configs['wx.payment.private.key'] || process.env.WECHAT_PRIVATE_KEY || '';

    // 处理证书字符串，将 \n 转换为实际换行符
    publicKey = publicKey.replace(/\\n/g, '\n');
    privateKey = privateKey.replace(/\\n/g, '\n');

    // 验证配置完整性
    if (!merchantId || !appId || !v3Key || !certSerialNo || !publicKey || !privateKey) {
      throw new Error('微信支付配置不完整，请检查系统配置或环境变量');
    }

    return {
      merchantId,
      appId,
      v3Key,
      notifyUrl,
      certSerialNo,
      publicKey,
      privateKey
    };
  }

  /**
   * 创建微信支付订单
   * @param externalOrderId 外部订单ID
   * @param userId 用户ID
   * @param totalAmount 支付金额（分）
   * @param description 支付描述
   * @param openid 用户OpenID
   * @param tenantId 租户ID
   */
  async createPayment(
    externalOrderId: number,
    userId: number,
    totalAmount: number,
    description: string,
    openid: string,
    tenantId: number
  ): Promise<PaymentCreateResponse> {
    // 检查是否已存在相同外部订单ID的支付记录
    const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);
    const existingPayment = await paymentRepository.findOne({
      where: { externalOrderId, tenantId }
    });

    if (existingPayment) {
      if (existingPayment.paymentStatus !== PaymentStatus.PENDING) {
        throw new Error('该订单已存在支付记录且状态不正确');
      }
      // 如果存在待支付的记录，可以更新或重新创建，这里选择重新创建
      await paymentRepository.remove(existingPayment);
    }

    if (!openid) {
      throw new Error('用户OpenID不能为空');
    }

    try {
      // 重新初始化微信支付SDK
      await this.initializeWxPay(tenantId);

      // 获取支付配置
      const config = await this.getPaymentConfig(tenantId);

      // console.debug('微信支付配置:', config);

      // 创建商户订单号
      const outTradeNo = `PAYMENT_${externalOrderId}_${Date.now()}`;

      // 使用微信支付SDK创建JSAPI支付
      const result = await this.wxPay.transactions_jsapi({
        appid: config.appId,
        mchid: config.merchantId,
        description,
        out_trade_no: outTradeNo,
        notify_url: config.notifyUrl,
        amount: {
          total: totalAmount,
        },
        payer: {
          openid
        }
      });

      console.debug('微信支付SDK返回结果:', result);

      // 从 package 字段中提取 prepay_id
      const prepayId = result.package ? result.package.replace('prepay_id=', '') : undefined;

      // 创建支付记录
      const payment = new PaymentMtEntity();
      payment.externalOrderId = externalOrderId;
      payment.userId = userId;
      payment.totalAmount = totalAmount;
      payment.description = description;
      payment.paymentStatus = PaymentStatus.PROCESSING;
      payment.outTradeNo = outTradeNo;
      payment.openid = openid;
      payment.tenantId = tenantId;

      await paymentRepository.save(payment);

      // 直接返回微信支付SDK生成的参数
      return {
        paymentId: prepayId,
        timeStamp: result.timeStamp,
        nonceStr: result.nonceStr,
        package: result.package,
        signType: result.signType,
        paySign: result.paySign,
        totalAmount: totalAmount // 添加金额字段用于前端验证
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      throw new Error(`微信支付创建失败: ${errorMessage}`);
    }
  }

  /**
   * 处理支付回调
   */
  async handlePaymentCallback(
    callbackData: any,
    headers: any,
    rawBody: string // 添加原始请求体参数
  ): Promise<void> {
    console.debug('收到支付回调请求:', {
      headers,
      callbackData,
      rawBody
    });

    // 重新初始化微信支付SDK（先初始化以进行签名验证和解密）
    console.debug(`开始初始化微信支付SDK`);
    await this.initializeWxPay(1); // 先使用默认租户ID进行初始化
    console.debug(`微信支付SDK初始化完成`);

    // 验证回调签名
    console.debug(`开始验证回调签名`);
    const isValid = await this.wxPay.verifySign({
      timestamp: headers['wechatpay-timestamp'],
      nonce: headers['wechatpay-nonce'],
      body: rawBody, // 优先使用原始请求体
      serial: headers['wechatpay-serial'],
      signature: headers['wechatpay-signature']
    });

    console.debug(`回调签名验证结果:`, isValid);

    if (!isValid) {
      console.debug(`回调签名验证失败，headers:`, headers);
      throw new Error('回调签名验证失败');
    }

    console.debug(`回调签名验证成功`);

    // 解密回调数据
    console.debug(`开始解密回调数据`);
    const decryptedData = this.wxPay.decipher_gcm(
      callbackData.resource.ciphertext,
      callbackData.resource.associated_data || '',
      callbackData.resource.nonce
    );

    console.debug(`解密回调数据:`, decryptedData);
    console.debug(`解密回调数据类型:`, typeof decryptedData);

    // 处理解密后的数据，可能是字符串或对象
    let parsedData;
    if (typeof decryptedData === 'string') {
      parsedData = JSON.parse(decryptedData);
    } else {
      parsedData = decryptedData;
    }

    console.debug(`解析后的回调数据:`, parsedData);

    // 从解密后的数据中获取商户订单号
    const outTradeNo = parsedData.out_trade_no;
    if (!outTradeNo) {
      console.debug('解密后的回调数据中缺少商户订单号，回调数据:', parsedData);
      throw new Error('回调数据中缺少商户订单号');
    }

    console.debug(`开始处理支付回调，商户订单号: ${outTradeNo}`);

    // 从数据库中查找支付记录以获取租户ID
    const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);
    const payment = await paymentRepository.findOne({
      where: { outTradeNo }
    });

    if (!payment) {
      console.debug(`支付记录不存在，商户订单号: ${outTradeNo}`);
      throw new Error('支付记录不存在');
    }

    console.debug(`[租户${payment.tenantId}] 找到支付记录，外部订单ID: ${payment.externalOrderId}, 当前支付状态: ${payment.paymentStatus}`);

    // 重新使用正确的租户ID初始化微信支付SDK
    console.debug(`[租户${payment.tenantId}] 重新初始化微信支付SDK`);
    await this.initializeWxPay(payment.tenantId);
    console.debug(`[租户${payment.tenantId}] 微信支付SDK重新初始化完成`);

    // 根据回调结果更新支付状态
    const originalPaymentStatus = payment.paymentStatus;
    if (parsedData.trade_state === 'SUCCESS') {
      payment.paymentStatus = PaymentStatus.PAID;
      payment.wechatTransactionId = parsedData.transaction_id;
      console.debug(`[租户${payment.tenantId}] 支付成功，微信交易流水号: ${parsedData.transaction_id}`);
    } else if (parsedData.trade_state === 'FAIL') {
      payment.paymentStatus = PaymentStatus.FAILED;
      console.debug(`[租户${payment.tenantId}] 支付失败`);
    } else if (parsedData.trade_state === 'REFUND') {
      payment.paymentStatus = PaymentStatus.REFUNDED;
      console.debug(`[租户${payment.tenantId}] 支付退款`);
    }

    console.debug(`[租户${payment.tenantId}] 支付状态从 ${originalPaymentStatus} 更新为 ${payment.paymentStatus}`);

    console.debug(`[租户${payment.tenantId}] 开始保存支付记录`);
    await paymentRepository.save(payment);
    console.debug(`[租户${payment.tenantId}] 支付记录保存成功`);

    // 根据支付状态更新订单状态
    console.debug(`[租户${payment.tenantId}] 开始更新订单状态，外部订单ID: ${payment.externalOrderId}, 支付状态: ${payment.paymentStatus}`);

    try {
      if (payment.paymentStatus === PaymentStatus.PAID) {
        // 支付成功，更新订单状态为已支付 (2)
        await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 2);
        console.debug(`[租户${payment.tenantId}] 订单状态更新为已支付，订单ID: ${payment.externalOrderId}`);
      } else if (payment.paymentStatus === PaymentStatus.FAILED) {
        // 支付失败，更新订单状态为支付失败 (4)
        await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 4);
        console.debug(`[租户${payment.tenantId}] 订单状态更新为支付失败，订单ID: ${payment.externalOrderId}`);
      } else if (payment.paymentStatus === PaymentStatus.REFUNDED) {
        // 退款，更新订单状态为已退款 (3)
        await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 3);
        console.debug(`[租户${payment.tenantId}] 订单状态更新为已退款，订单ID: ${payment.externalOrderId}`);
      }
    } catch (error) {
      console.debug(`[租户${payment.tenantId}] 订单状态更新失败，订单ID: ${payment.externalOrderId}, 错误:`, error);
      // 这里不抛出错误，因为支付记录已经保存，订单状态更新失败不影响支付回调的成功响应
    }
  }

  /**
   * 查询支付状态
   */
  async getPaymentStatus(externalOrderId: number, tenantId: number): Promise<PaymentStatus> {
    const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);
    const payment = await paymentRepository.findOne({
      where: { externalOrderId, tenantId }
    });

    if (!payment) {
      throw new Error('支付记录不存在');
    }

    return payment.paymentStatus;
  }

  /**
   * 生成随机字符串
   */
  private generateNonceStr(length: number = 32): string {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let result = '';
    for (let i = 0; i < length; i++) {
      result += chars.charAt(Math.floor(Math.random() * chars.length));
    }
    return result;
  }

  /**
   * 生成回调签名（用于测试）
   */
  async generateCallbackSignature(
    timestamp: string,
    nonce: string,
    callbackData: any,
    tenantId: number
  ): Promise<string> {
    // 初始化微信支付SDK
    await this.initializeWxPay(tenantId);

    return this.wxPay.getSignature(
      'POST',
      nonce,
      timestamp,
      '/v3/pay/transactions/jsapi',
      callbackData
    );
  }

  /**
   * 获取微信支付平台证书（用于测试）
   */
  async getPlatformCertificates(tenantId: number): Promise<any> {
    try {
      // 重新初始化微信支付SDK
      await this.initializeWxPay(tenantId);

      console.debug('开始获取微信支付平台证书...');
      const config = await this.getPaymentConfig(tenantId);
      const certificates = await this.wxPay.get_certificates(config.v3Key);
      console.debug('获取平台证书成功:', certificates);
      return certificates;
    } catch (error) {
      console.debug('获取平台证书失败:', error);
      throw error;
    }
  }

  /**
   * 更新订单支付状态
   * @param tenantId 租户ID
   * @param externalOrderId 外部订单ID
   * @param payState 支付状态 (0未支付、1支付中、2支付成功、3已退款、4支付失败、5订单关闭)
   */
  async updateOrderPaymentStatus(tenantId: number, externalOrderId: number, payState: number): Promise<void> {
    console.debug(`[租户${tenantId}] 开始更新订单支付状态，订单ID: ${externalOrderId}, 状态: ${payState}`);

    try {
      // 直接使用数据源更新订单支付状态
      const orderRepository = this.dataSource.getRepository(OrderMt);

      const updateResult = await orderRepository.update(
        { id: externalOrderId, tenantId },
        {
          payState,
          updatedAt: new Date()
        }
      );

      if (updateResult.affected === 0) {
        console.debug(`[租户${tenantId}] 订单不存在或更新失败，订单ID: ${externalOrderId}`);
        throw new Error(`订单ID ${externalOrderId} 不存在或更新失败`);
      }

      console.debug(`[租户${tenantId}] 订单支付状态更新成功，订单ID: ${externalOrderId}, 状态: ${payState}`);
    } catch (error) {
      console.debug(`[租户${tenantId}] 订单支付状态更新失败，订单ID: ${externalOrderId}, 错误:`, error);
      throw error;
    }
  }

  /**
   * 执行微信支付退款
   * @param tenantId 租户ID
   * @param orderNo 订单号
   * @param refundAmount 退款金额（分）
   * @param refundReason 退款原因
   */
  async refund(
    tenantId: number,
    orderNo: string,
    refundAmount: number,
    refundReason?: string
  ): Promise<RefundResponse> {
    console.debug(`[租户${tenantId}] 开始处理退款，订单号: ${orderNo}, 退款金额: ${refundAmount}`);

    try {
      // 初始化微信支付SDK
      await this.initializeWxPay(tenantId);

      // 根据订单号查找支付记录
      const paymentRepository = this.dataSource.getRepository(PaymentMtEntity);

      // 首先通过订单号查找对应的订单ID
      const orderRepository = this.dataSource.getRepository(OrderMt);
      const order = await orderRepository.findOne({
        where: { orderNo, tenantId }
      });

      if (!order) {
        throw new Error(`订单不存在，订单号: ${orderNo}`);
      }

      // 通过订单ID查找支付记录
      const payment = await paymentRepository.findOne({
        where: { externalOrderId: order.id, tenantId }
      });

      if (!payment) {
        throw new Error(`支付记录不存在，订单号: ${orderNo}`);
      }

      // 验证支付状态
      if (payment.paymentStatus !== PaymentStatus.PAID) {
        throw new Error(`订单支付状态不正确，当前状态: ${payment.paymentStatus}`);
      }

      // 验证退款金额并转换为整数（分）
      const refundAmountInCents = Math.round(refundAmount * 100);
      if (refundAmountInCents <= 0 || refundAmountInCents > payment.totalAmount) {
        throw new Error(`退款金额无效，退款金额: ${refundAmount}, 支付金额: ${payment.totalAmount}`);
      }

      // 生成退款订单号
      const outRefundNo = `REFUND_${orderNo}_${Date.now()}`;

      // 验证outTradeNo存在
      if (!payment.outTradeNo) {
        throw new Error('支付记录缺少商户订单号');
      }

      // 调用微信支付退款API
      const result = await this.wxPay.refunds({
        out_trade_no: payment.outTradeNo,
        out_refund_no: outRefundNo,
        amount: {
          refund: refundAmountInCents,
          total: payment.totalAmount,
          currency: 'CNY'
        },
        reason: refundReason || '用户取消订单'
      });

      console.debug(`[租户${tenantId}] 微信支付退款API返回结果:`, result);

      // 更新支付记录的退款状态
      payment.refundStatus = PaymentStatus.REFUNDED;
      payment.refundTransactionId = outRefundNo; // 使用退款订单号作为临时退款流水号
      payment.refundAmount = refundAmountInCents;
      payment.refundTime = new Date();

      await paymentRepository.save(payment);

      console.debug(`[租户${tenantId}] 退款处理完成，退款订单号: ${outRefundNo}`);

      return {
        refundId: outRefundNo,
        outRefundNo: outRefundNo,
        refundStatus: 'SUCCESS',
        refundAmount: refundAmount,
        refundTime: new Date().toISOString()
      };
    } catch (error) {
      console.debug(`[租户${tenantId}] 退款处理失败，订单号: ${orderNo}, 错误:`, error);
      throw new Error(`退款处理失败: ${error instanceof Error ? error.message : '未知错误'}`);
    }
  }

  /**
   * 处理退款回调
   */
  async handleRefundCallback(
    callbackData: any,
    headers: any,
    rawBody: string
  ): Promise<void> {
    console.debug('收到退款回调请求:', {
      headers,
      callbackData,
      rawBody
    });

    // 重新初始化微信支付SDK（先初始化以进行签名验证和解密）
    await this.initializeWxPay(1); // 先使用默认租户ID进行初始化

    // 验证回调签名
    const isValid = await this.wxPay.verifySign({
      timestamp: headers['wechatpay-timestamp'],
      nonce: headers['wechatpay-nonce'],
      body: rawBody,
      serial: headers['wechatpay-serial'],
      signature: headers['wechatpay-signature']
    });

    if (!isValid) {
      console.debug('退款回调签名验证失败，headers:', headers);
      throw new Error('退款回调签名验证失败');
    }

    console.debug('退款回调签名验证成功');

    // 解密回调数据
    const decryptedData = this.wxPay.decipher_gcm(
      callbackData.resource.ciphertext,
      callbackData.resource.associated_data || '',
      callbackData.resource.nonce
    );

    console.debug('解密退款回调数据:', decryptedData);

    // 处理解密后的数据
    let parsedData;
    if (typeof decryptedData === 'string') {
      parsedData = JSON.parse(decryptedData);
    } else {
      parsedData = decryptedData;
    }

    console.debug('解析后的退款回调数据:', parsedData);

    // 从解密后的数据中获取退款订单号
    const outRefundNo = parsedData.out_refund_no;
    if (!outRefundNo) {
      console.debug('解密后的退款回调数据中缺少退款订单号，回调数据:', parsedData);
      throw new Error('退款回调数据中缺少退款订单号');
    }

    console.debug(`开始处理退款回调，退款订单号: ${outRefundNo}`);

    // 这里可以根据退款回调更新相关业务状态
    // 例如：更新退款记录状态、通知用户等
    console.debug(`退款回调处理完成，退款订单号: ${outRefundNo}, 退款状态: ${parsedData.refund_status}`);
  }
}