package vip.xiaonuo.biz.modular.wx;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.xiaonuo.biz.api.BizUserApi;
import vip.xiaonuo.biz.core.enums.FundChangeTypeEnum;
import vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord;
import vip.xiaonuo.biz.modular.couponrecord.service.BizCouponRecordService;
import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
import vip.xiaonuo.biz.modular.rebaterecord.service.BizRebateRecordService;
import vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord;
import vip.xiaonuo.biz.modular.rechargerecord.service.BizRechargeRecordService;
import vip.xiaonuo.biz.modular.user.entity.BizUser;
import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper;
import vip.xiaonuo.biz.modular.user.service.BizUserService;
import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
import vip.xiaonuo.biz.modular.userfundchangerecord.service.BizUserFundChangeRecordService;
import vip.xiaonuo.common.util.CommonCouponGeneratorUtil;
import vip.xiaonuo.common.wx.HttpServletUtils;
import vip.xiaonuo.sys.api.SysUserApi;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author wulei
 * @date 2024/11/1
 * @Version 1.0
 * @Description 微信支付回调
 */
@RestController
@Slf4j
public class WxPayNotifyController {

    @Resource
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;
    @Resource
    private BizRechargeRecordService bizRechargeRecordService;
    @Resource
    private BizUserMapper bizUserMapper;
    @Resource
    private BizCouponRecordService bizCouponRecordService;
    @Resource
    private BizRebateRecordService bizRebateRecordService;
    @Resource
    private BizUserFundChangeRecordService bizUserFundChangeRecordService;
    @Resource
    private PlatformTransactionManager transactionManager;

    /**
     * 微信支付回调通知
     *
     * @param request
     * @return
     * @throws Exception
     */
    @PostMapping("/biz/wx/notify")
    public synchronized String payNotify(HttpServletRequest request) {
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
        log.info("------收到支付通知------");
        log.info("request ========: {}", request);
        // 请求头Wechatpay-Signature
        String signature = request.getHeader("Wechatpay-Signature");
        // 请求头Wechatpay-nonce
        String nonce = request.getHeader("Wechatpay-Nonce");
        // 请求头Wechatpay-Timestamp
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        // 微信支付证书序列号
        String serial = request.getHeader("Wechatpay-Serial");
        // 签名方式
        String signType = request.getHeader("Wechatpay-Signature-Type");
        Map<String, String> returnMap = new HashMap<>(2);
        try {
            RequestParam requestParam = new RequestParam.Builder()
                    .serialNumber(serial)
                    .nonce(nonce)
                    .signature(signature)
                    .timestamp(timestamp)
                    .signType(signType)
                    .body(HttpServletUtils.getRequestBody(request))
                    .build();

            returnMap.put("code", "FAIL");
            returnMap.put("message", "失败");
            // 初始化 NotificationParser
            NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            log.info("验签参数：{}", requestParam);
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            log.info("验签成功！-支付回调结果：{}", transaction.toString());
            //实际支付金额
            BigDecimal realPayAmount = new BigDecimal(transaction.getAmount().getPayerTotal()).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
            //查询充值记录数据
            BizRechargeRecord bizRechargeRecord = bizRechargeRecordService.getOne(new LambdaQueryWrapper<BizRechargeRecord>().eq(BizRechargeRecord::getOrderNo, transaction.getOutTradeNo()));
            if (ObjectUtil.isNull(bizRechargeRecord)) {
                log.info("未查询到系统订单编号所关联的充值记录：{}========", transaction.getOutTradeNo());
                return JSONObject.toJSONString(returnMap);
            }
            //如果已经成功无需再次更新
            if (bizRechargeRecord.getIsPay()) {
                returnMap.put("code", "SUCCESS");
                returnMap.put("message", "成功");
                return JSONObject.toJSONString(returnMap);
            }
            // 查询用户信息
            BizUser bizUser = bizUserMapper.selectById(bizRechargeRecord.getUserId());
            if (ObjectUtil.isNull(bizUser)) {
                log.info("未查询到用户信息：{}========", bizRechargeRecord.getUserId());
                return JSONObject.toJSONString(returnMap);
            }
            log.info("=========== 更新用户：{}，账户余额 ========", bizUser.getName());
            bizRechargeRecord.setOldAccountBalance(bizUser.getAccountBalance());
            bizRechargeRecord.setOldVoucherBalance(bizUser.getVoucherBalance());
            //计算新金额
            if (ObjectUtil.isNotEmpty(bizRechargeRecord.getRechargePlanId())) {
                //有充值计划
                bizUser.setAccountBalance(bizUser.getAccountBalance().add(bizRechargeRecord.getPlanAccountBalance()));
            } else {
                bizUser.setAccountBalance(bizUser.getAccountBalance().add(realPayAmount));
            }
            bizUserMapper.updateById(bizUser);
            //更新充值记录
            log.info("=========== 更新充值记录 ========");
            bizRechargeRecord.setNewAccountBalance(bizUser.getAccountBalance());
            bizRechargeRecord.setPayTime(DateUtil.parse(transaction.getSuccessTime()));
            bizRechargeRecord.setIsPay(Boolean.TRUE);
            bizRechargeRecord.setWxOrderNo(transaction.getTransactionId());
            bizRechargeRecord.setWxPayAmount(realPayAmount);
            bizRechargeRecordService.updateById(bizRechargeRecord);
            //生成蛋糕券
            if (bizRechargeRecord.getCouponNum() != null && bizRechargeRecord.getCouponNum() > 0) {
                log.info("=========== 生成优惠券 ========");
                DateTime date = DateUtil.date();
                for (int i = 0; i < bizRechargeRecord.getCouponNum(); i++) {
                    BizCouponRecord bizCouponRecord = new BizCouponRecord();
                    bizCouponRecord.setCouponNo(CommonCouponGeneratorUtil.generateCouponCode());
                    bizCouponRecord.setTime(date);
                    bizCouponRecord.setRechargePlanId(bizRechargeRecord.getRechargePlanId());
                    bizCouponRecord.setRechargeRecordId(bizRechargeRecord.getId());
                    bizCouponRecordService.save(bizCouponRecord);
                }
            }
            // 生成推荐人返点
            if (ObjectUtil.isNotEmpty(bizUser.getReferralUser())) {
                log.info("=========== 生成推荐人返点记录 ========");
                BizRebateRecord bizRebateRecord = new BizRebateRecord();
                bizRebateRecord.setRechargeRecordId(bizRechargeRecord.getId());
                bizRebateRecord.setRebateAmount(bizRechargeRecord.getRebateAmount());
                bizRebateRecord.setRechargeUserId(bizRechargeRecord.getUserId());
                bizRebateRecord.setRecommendUserId(bizUser.getReferralUser());
                bizRebateRecordService.save(bizRebateRecord);
            }
            // 记录用户账户资金变动记录
            log.info("=========== 记录用户账户资金变动记录 ========");
            BizUserFundChangeRecord bizUserFundChangeRecord = new BizUserFundChangeRecord();
            bizUserFundChangeRecord.setChangeType(FundChangeTypeEnum.RECHARGE.getValue());
            bizUserFundChangeRecord.setUserId(bizRechargeRecord.getUserId());
            bizUserFundChangeRecord.setOldAccountBalance(bizRechargeRecord.getOldAccountBalance());
            bizUserFundChangeRecord.setOldVoucherBalance(bizRechargeRecord.getOldVoucherBalance());
            bizUserFundChangeRecord.setNewAccountBalance(bizRechargeRecord.getNewAccountBalance());
            bizUserFundChangeRecord.setNewVoucherBalance(bizRechargeRecord.getNewVoucherBalance());
            bizUserFundChangeRecordService.save(bizUserFundChangeRecord);
            //手动提交事务
            transactionManager.commit(transactionStatus);
            log.info("微信订单回调成功------------------");
        } catch (Exception e) {
            e.printStackTrace();
            transactionManager.rollback(transactionStatus);
            log.error("wx pay error , 支付回调异常:{}", e.getMessage());
            returnMap.put("code", "FAIL");
            returnMap.put("message", "失败");
            return JSONObject.toJSONString(returnMap);
        }
        returnMap.put("code", "SUCCESS");
        returnMap.put("message", "成功");
        return JSONObject.toJSONString(returnMap);
    }
}
