import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import * as path from 'path';

// WeChat Pay V3 SDK types
interface WxPayConfig {
  appId: string;
  mchId: string;
  apiKey: string;
  certPath: string;
  keyPath: string;
  notifyUrl: string;
}

export interface UnifiedOrderResult {
  prepay_id: string;
  nonceStr: string;
  timeStamp: string;
  package: string;
  paySign: string;
  signType: string;
}

@Injectable()
export class PaymentService {
  private readonly logger = new Logger(PaymentService.name);
  private config: WxPayConfig;
  private wxPay: any;

  constructor(private prisma: PrismaService) {
    this.config = {
      appId: process.env.WX_APPID || '',
      mchId: process.env.WX_MCHID || process.env.WX_PAY_MCH_ID || '1108945993',
      apiKey: process.env.WX_API_KEY || process.env.WX_PAY_API_KEY || '8Kj9mP2nQ5rT7vW1xY3zA4bC6dE8fG0h',
      certPath: process.env.WX_CERT_PATH || path.resolve(__dirname, '../../../cert/key/apiclient_cert.pem'),
      keyPath: process.env.WX_KEY_PATH || path.resolve(__dirname, '../../../cert/key/apiclient_key.pem'),
      notifyUrl: process.env.WX_NOTIFY_URL || 'https://yuzhiran.com/api/v1/payment/wxpay/notify',
    };

    if (process.env.WX_PAY_MOCK === 'true') {
      this.logger.warn('WX_PAY_MOCK=true，强制使用模拟支付模式');
      this.wxPay = null;
      return;
    }

    try {
      const fs = require('fs');
      const { WechatPay } = require('wechat-pay-nodejs');
      this.wxPay = new WechatPay({
        appid: this.config.appId,
        mchid: this.config.mchId,
        key: this.config.apiKey,
        cert_private_content: fs.readFileSync(this.config.keyPath),
        cert_public_content: fs.readFileSync(this.config.certPath),
      });
      this.logger.log(`微信支付初始化成功 (商户号: ${this.config.mchId})`);
    } catch (err: any) {
      this.logger.warn(`微信支付 SDK 初始化失败: ${err.message}，将使用模拟模式`);
      this.wxPay = null;
    }
  }

  async createUnifiedOrder(params: {
    description: string;
    outTradeNo: string;
    amount: number;
    openid?: string;
    tradeType?: 'JSAPI' | 'NATIVE' | 'MWEB';
  }): Promise<UnifiedOrderResult & { codeUrl?: string }> {
    const { description, outTradeNo, amount, openid, tradeType = 'JSAPI' } = params;

    if (!this.wxPay) {
      return { ...this.mockPayResult(outTradeNo, amount), codeUrl: 'mock://pay' };
    }

    try {
      const baseParams = {
        description,
        out_trade_no: outTradeNo,
        amount: { total: Math.round(amount * 100) },
        notify_url: this.config.notifyUrl,
      };

      let result: any;
      if (tradeType === 'NATIVE') {
        result = await this.wxPay.prepayNative({
          ...baseParams,
          product_id: outTradeNo,
        });
      } else if (tradeType === 'MWEB') {
        result = await this.wxPay.prepayMweb({
          ...baseParams,
          scene_info: { payer_client_ip: '127.0.0.1' },
        });
      } else {
        result = await this.wxPay.prepayJsapi({
          ...baseParams,
          payer: { openid: openid || 'oVtFy6Wv8L0lKJ9xG2rH3nM5pQ7sT1uZ' },
        });
      }

      if (result.success && result.data) {
        const response: any = {
          prepay_id: result.data.package?.replace('prepay_id=', '') || result.data.prepay_id || '',
          nonceStr: result.data.nonceStr || result.data.nonce_str,
          timeStamp: result.data.timeStamp || String(Math.floor(Date.now() / 1000)),
          paySign: result.data.paySign || result.data.sign,
          signType: 'RSA',
        };
        if (result.data.code_url) response.codeUrl = result.data.code_url;
        if (result.data.mweb_url) response.mwebUrl = result.data.mweb_url;
        return response;
      }
      throw new Error(result.errMsg || '下单失败');
    } catch (err: any) {
      this.logger.error(`微信支付统一下单失败: ${err.message}`);
      return { ...this.mockPayResult(outTradeNo, amount), codeUrl: 'mock://pay' };
    }
  }

  async handleNotify(body: any, signature: string): Promise<{ code: string; message: string }> {
    if (!this.wxPay) {
      // 模拟模式：尝试更新订单状态
      try {
        const data = typeof body === 'string' ? JSON.parse(body) : body;
        const outTradeNo = data.out_trade_no || (data.resource && data.resource.out_trade_no);
        if (outTradeNo) {
          await this.updateOrderAndMembership(outTradeNo, data.amount?.total || 0);
        }
      } catch (err) {
        this.logger.warn(`模拟模式处理通知失败: ${err.message}`);
      }
      return { code: 'SUCCESS', message: '模拟模式-通知处理成功' };
    }

    try {
      const verified = this.wxPay.verifySignature(body, signature);
      if (!verified) {
        return { code: 'FAIL', message: '签名验证失败' };
      }

      const data = typeof body === 'string' ? JSON.parse(body) : body;
      const { event_type, resource } = data;

      if (event_type === 'TRANSACTION.SUCCESS') {
        const ciphertext = resource.ciphertext;
        const associatedData = resource.associated_data;
        const nonce = resource.nonce;

        const decrypted = this.wxPay.decryptGCM(ciphertext, associatedData, nonce);
        const payResult = typeof decrypted === 'string' ? JSON.parse(decrypted) : decrypted;

        this.logger.log(`支付成功: ${payResult.out_trade_no}, 金额: ${payResult.amount.total}`);

        // 更新订单状态和会员订阅
        await this.updateOrderAndMembership(payResult.out_trade_no, payResult.amount.total, payResult.transaction_id);

        return { code: 'SUCCESS', message: '支付成功' };
      }

      return { code: 'SUCCESS', message: '已接收' };
    } catch (err: any) {
      this.logger.error(`支付通知处理失败: ${err.message}`);
      return { code: 'FAIL', message: err.message };
    }
  }

  private async updateOrderAndMembership(outTradeNo: string, paidAmountTotal: number, transactionId?: string) {
    const order = await this.prisma.order.findUnique({
      where: { orderNo: outTradeNo },
      include: { user: true },
    });

    if (!order) {
      this.logger.warn(`订单不存在: ${outTradeNo}`);
      return;
    }

    if (order.status === 'PAID') {
      this.logger.log(`订单已支付，跳过重复处理: ${outTradeNo}`);
      return;
    }

    // 验证金额（微信支付单位：分，订单单位：元）
    const paidAmount = paidAmountTotal / 100;
    if (Math.abs(paidAmount - order.amount) > 0.01) {
      this.logger.warn(`支付金额不一致: 订单${order.amount}元，支付${paidAmount}元`);
    }

    // 更新订单状态为已支付
    await this.prisma.order.update({
      where: { id: order.id },
      data: { status: 'PAID', paidAt: new Date(), transactionId: transactionId || order.transactionId },
    });

    // 处理会员订阅（仅限MONTHLY/YEARLY计划）
    if (order.planType === 'MONTHLY' || order.planType === 'YEARLY') {
      const durationDays = order.planType === 'MONTHLY' ? 30 : 365;
      const now = new Date();
      let subscriptionEndDate: Date;

      // 查询现有活跃订阅
      const existingSub = await this.prisma.subscription.findFirst({
        where: {
          userId: order.userId,
          status: 'ACTIVE',
          endDate: { gt: now },
        },
      });

      if (existingSub) {
        // 延长现有订阅
        subscriptionEndDate = new Date(existingSub.endDate.getTime() + durationDays * 24 * 60 * 60 * 1000);
        await this.prisma.subscription.update({
          where: { id: existingSub.id },
          data: { endDate: subscriptionEndDate },
        });
      } else {
        // 创建新订阅
        subscriptionEndDate = new Date(now);
        subscriptionEndDate.setDate(subscriptionEndDate.getDate() + durationDays);
        await this.prisma.subscription.create({
          data: {
            userId: order.userId,
            plan: order.planType as any,
            startDate: now,
            endDate: subscriptionEndDate,
            status: 'ACTIVE',
          },
        });
      }

      // 更新用户会员状态
      await this.prisma.user.update({
        where: { id: order.userId },
        data: {
          memberPlan: order.planType as any,
          memberExpire: subscriptionEndDate,
        },
      });

      this.logger.log(`会员订阅更新成功: 用户${order.userId}, 类型${order.planType}, 到期${subscriptionEndDate}`);
    }
  }

  /**
   * 完成模拟支付（mock 模式）：自动更新订单状态 + 升级会员订阅
   */
  async completeMockPayment(orderNo: string): Promise<void> {
    if (this.wxPay) {
      this.logger.warn(`非模拟模式，跳过模拟支付完成: ${orderNo}`);
      return;
    }
    const order = await this.prisma.order.findUnique({ where: { orderNo } });
    if (!order) {
      this.logger.warn(`订单不存在: ${orderNo}`);
      return;
    }
    if (order.status === 'PAID') {
      this.logger.log(`订单已支付，跳过重复处理: ${orderNo}`);
      return;
    }
    await this.updateOrderAndMembership(orderNo, Math.round(order.amount * 100));
    this.logger.log(`模拟支付完成: ${orderNo}`);
  }

  async refund(outTradeNo: string, amount: number, reason?: string) {
    if (!this.wxPay) {
      this.logger.log(`模拟退款: ${outTradeNo}`);
      // 模拟退款成功后更新订单状态
      try {
        await this.prisma.order.update({
          where: { orderNo: outTradeNo },
          data: { status: 'REFUNDED' },
        });
      } catch(err) {
        this.logger.warn(`模拟退款更新订单失败: ${err.message}`);
      }
      return { code: 'SUCCESS', message: '模拟退款成功' };
    }

    try {
      const result = await this.wxPay.refunds({
        out_trade_no: outTradeNo,
        out_refund_no: `REFUND_${outTradeNo}_${Date.now()}`,
        amount: {
          refund: Math.round(amount * 100),
          total: Math.round(amount * 100),
          currency: 'CNY',
        },
        reason: reason || '用户申请退款',
      });

      // 退款成功后更新订单状态
      if (result.success) {
        await this.prisma.order.update({
          where: { orderNo: outTradeNo },
          data: { status: 'REFUNDED' },
        }).catch(err => this.logger.warn(`退款更新订单失败: ${err.message}`));
      }

      return result;
    } catch (err: any) {
      this.logger.error(`退款失败: ${err.message}`);
      throw err;
    }
  }

  async queryOrder(outTradeNo: string) {
    // 先查本地订单状态
    const localOrder = await this.prisma.order.findUnique({
      where: { orderNo: outTradeNo },
      include: { user: { select: { id: true, nickname: true, memberPlan: true, memberExpire: true } } },
    });

    if (!this.wxPay) {
      return {
        trade_state: localOrder?.status === 'PAID' ? 'SUCCESS' : 'NOTPAY',
        out_trade_no: outTradeNo,
        localStatus: localOrder?.status,
        amount: localOrder?.amount,
        planType: localOrder?.planType,
      };
    }

    const wxResult = await this.wxPay.queryByOutTradeNo(outTradeNo);
    return {
      ...wxResult,
      localStatus: localOrder?.status,
      localAmount: localOrder?.amount,
      user: localOrder?.user,
    };
  }

  private mockPayResult(outTradeNo: string, amount: number): UnifiedOrderResult {
    const nonceStr = this.generateNonceStr();
    const timeStamp = String(Math.floor(Date.now() / 1000));
    const prepayId = `wx${Date.now()}${Math.random().toString(36).slice(2, 10)}`;

    return {
      prepay_id: prepayId,
      nonceStr,
      timeStamp,
      package: `prepay_id=${prepayId}`,
      paySign: 'MOCK_SIGN_FOR_DEVELOPMENT',
      signType: 'RSA',
    };
  }

  private generateNonceStr(): string {
    return Math.random().toString(36).substring(2, 18) + Math.random().toString(36).substring(2, 18);
  }
}
