package vip.xiaonuo.biz.modular.wx;

import cn.hutool.core.date.DateField;
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.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.apache.commons.lang3.StringUtils;
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.bizactivate.entity.BizActivate;
import vip.xiaonuo.biz.modular.bizactivate.service.BizActivateService;
import vip.xiaonuo.biz.modular.bizactivatedetail.entity.BizActivateDetail;
import vip.xiaonuo.biz.modular.bizactivatedetail.service.BizActivateDetailService;
import vip.xiaonuo.biz.modular.couponconfig.entity.CouponConfig;
import vip.xiaonuo.biz.modular.couponconfig.service.CouponConfigService;
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.rechargeplanconfig.entity.BizRechargePlanConfig;
import vip.xiaonuo.biz.modular.rechargeplanconfig.service.BizRechargePlanConfigService;
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.List;
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;
    @Resource
    private BizRechargePlanConfigService bizRechargePlanConfigService;
    @Resource
    private BizActivateService bizActivateService;
    @Resource
    private BizActivateDetailService bizActivateDetailService;
    @Resource
    private CouponConfigService couponConfigService;

    /**
     * 微信支付回调通知
     *
     * @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 (StringUtils.equals(bizRechargeRecord.getIsPay(),"1")) {
                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());
            BizRechargePlanConfig planConfig = null;
            //计算新金额
            if (ObjectUtil.isNotEmpty(bizRechargeRecord.getRechargePlanId())) {
                planConfig = bizRechargePlanConfigService.getById(bizRechargeRecord.getRechargePlanId());
                if(StringUtils.equals(planConfig.getIsAccount(),"1")){
                    //有充值计划,立即到账
                    bizUser.setAccountBalance(bizUser.getAccountBalance().add(bizRechargeRecord.getPlanAccountBalance()));

                    getActivate(bizUser,bizRechargeRecord);
                }else{
                    //插入一条待激活的记录
                    BizActivate bizActivate = new BizActivate();
                    bizActivate.setUserId(bizUser.getId());
                    bizActivate.setAccountBalance(planConfig.getAccountBalance());
                    bizActivate.setStatus("1");
                    bizActivate.setHelpCount(0);
                    bizActivate.setPlanConfigId(planConfig.getId());
                    bizActivateService.save(bizActivate);


                    getActivate(bizUser,bizRechargeRecord);
                }
            } else {
                bizUser.setAccountBalance(bizUser.getAccountBalance().add(realPayAmount));
                getActivate(bizUser,bizRechargeRecord);
            }
            bizUserMapper.updateById(bizUser);
            //更新充值记录
            log.info("=========== 更新充值记录 ========");
            bizRechargeRecord.setNewAccountBalance(bizUser.getAccountBalance());
            bizRechargeRecord.setPayTime(DateUtil.parse(transaction.getSuccessTime()));
            bizRechargeRecord.setIsPay("1");
            bizRechargeRecord.setWxOrderNo(transaction.getTransactionId());
            bizRechargeRecord.setWxPayAmount(realPayAmount);
            bizRechargeRecordService.updateById(bizRechargeRecord);
            // 记录充值用户账户资金变动记录
            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(bizUser.getAccountBalance());
            bizUserFundChangeRecord.setNewVoucherBalance(bizUser.getVoucherBalance());
            bizUserFundChangeRecordService.save(bizUserFundChangeRecord);
            //生成蛋糕券
            /*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.setStartTime(date);
                    bizCouponRecord.setEndTime(DateUtil.offset(date, DateField.YEAR,1));
                    bizCouponRecord.setRechargePlanId(bizRechargeRecord.getRechargePlanId());
                    bizCouponRecord.setRechargeRecordId(bizRechargeRecord.getId());
                    bizCouponRecordService.save(bizCouponRecord);
                }
            }*/
            if (ObjectUtil.isNotEmpty(bizRechargeRecord.getRechargePlanId())){
                //查询充值方案蛋糕券
                List<CouponConfig> couponList = couponConfigService.list(new QueryWrapper<CouponConfig>().lambda().
                        eq(CouponConfig::getRechargePlanId, bizRechargeRecord.getRechargePlanId()));
                for(CouponConfig couponConfig : couponList){
                    log.info("=========== 生成优惠券 ========");
                    DateTime date = DateUtil.date();
                    for (int i = 0; i < couponConfig.getCouponNum(); i++) {
                        BizCouponRecord bizCouponRecord = new BizCouponRecord();
                        bizCouponRecord.setCouponNo(CommonCouponGeneratorUtil.generateCouponCode());
                        bizCouponRecord.setTime(date);
                        bizCouponRecord.setStartTime(date);
                        bizCouponRecord.setEndTime(DateUtil.offset(date, DateField.YEAR,1));
                        bizCouponRecord.setRechargePlanId(bizRechargeRecord.getRechargePlanId());
                        bizCouponRecord.setRechargeRecordId(bizRechargeRecord.getId());
                        bizCouponRecord.setCouponId(couponConfig.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);
            }

            //手动提交事务
            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);
    }

    //记录激活记录
    public void getActivate(BizUser bizUser,BizRechargeRecord bizRechargeRecord){
        if (ObjectUtil.isNotEmpty(bizUser.getReferralUser())) {
            //查询推荐人最早的一条待激活的记录，帮助激活人数+1
            BizUser user = bizUserMapper.selectById(bizUser.getReferralUser());
            BizActivate activate = bizActivateService.getOne(new QueryWrapper<BizActivate>().lambda().eq(BizActivate::getUserId, user.getId())
                    .eq(BizActivate::getStatus,"1")
                    .orderByAsc(BizActivate::getCreateTime)
                    .last("limit 1"));
            if(ObjectUtil.isNotNull(activate)){
                //查询待激活记录的充值方案信息
                BizRechargePlanConfig config = bizRechargePlanConfigService.getById(activate.getPlanConfigId());
                //本次充值金额大于待激活记录充值金额,可帮助激活一次
                if(bizRechargeRecord.getRechargeAmount().compareTo(config.getRechargeAmount()) >= 0){
                    //根据充值人和激活记录id查询是否帮助激活过，一个人只能激活一次
                    List<BizActivateDetail> list = bizActivateDetailService.list(new QueryWrapper<BizActivateDetail>().lambda().
                            eq(BizActivateDetail::getHelpUserId, bizUser.getId()));
                    if(ObjectUtil.isEmpty(list)){
                        //记录激活明细
                        BizActivateDetail bizActivateDetail = new BizActivateDetail();
                        bizActivateDetail.setActivateId(activate.getId());
                        bizActivateDetail.setHelpUserId(bizUser.getId());
                        bizActivateDetailService.save(bizActivateDetail);
                        //判断是否到达激活人数
                        if(activate.getHelpCount()+1 == config.getHelpCount()){

                            // 记录用户账户资金变动记录
                            log.info("=========== 记录用户账户资金变动记录 ========");
                            BizUserFundChangeRecord bizUserFundChangeRecord = new BizUserFundChangeRecord();
                            bizUserFundChangeRecord.setChangeType(FundChangeTypeEnum.RECHARGE.getValue());
                            bizUserFundChangeRecord.setUserId(user.getId());
                            bizUserFundChangeRecord.setOldAccountBalance(user.getAccountBalance());
                            bizUserFundChangeRecord.setOldVoucherBalance(user.getVoucherBalance());

                            //帮助激活人数等于配置的帮助激活人数，账户糕点可激活
                            user.setAccountBalance(user.getAccountBalance().add(activate.getAccountBalance()));

                            bizUserFundChangeRecord.setNewAccountBalance(user.getAccountBalance());
                            bizUserFundChangeRecord.setNewVoucherBalance(user.getVoucherBalance());
                            bizUserFundChangeRecordService.save(bizUserFundChangeRecord);

                            //修改推荐人账户余额
                            bizUserMapper.updateById(user);

                            activate.setStatus("2");
                        }
                        activate.setHelpCount(activate.getHelpCount()+1);
                        bizActivateService.updateById(activate);
                    }
                }
            }
        }
    }
}
