package com.gxwebsoft.shop.controller;

import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.RequestUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.open.service.OfficeMpServiceImpl;
import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.service.*;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RSANotificationConfig;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 会员特权购买记录表控制器
 *
 * @author 科技小王子
 * @since 2023-06-20 18:07:50
 */
@Api(tags = "微信支付结果通知")
@RestController
@RequestMapping("/api/shop/wx-pay/notify/10559")
public class WxPayNotifyNbgController extends BaseController {
    @Resource
    private OrderService orderService;
    @Resource
    private OrderInfoService orderInfoService;
    @Resource
    private OrderGoodsService orderGoodsService;
    @Resource
    private GoodsService goodsService;
    @Resource
    private UsersService usersService;
    @Resource
    private CartService cartService;
    @Resource
    private MerchantService merchantService;
    @Resource
    private MerchantChargePackageService merchantChargePackageService;
    @Resource
    private UserBalanceInMerchantService userBalanceInMerchantService;
    @Resource
    private MerchantGoodsPackageService merchantGoodsPackageService;
    @Resource
    private UserGoodsInMerchantService userGoodsInMerchantService;
    @Resource
    private CouponService couponService;
    @Resource
    private UserCouponService userCouponService;
    @Resource
    private ConfigProperties config;

    @Resource
    private OfficeMpServiceImpl officeMpService;

    @Resource
    private RedisUtil redisUtil;

    @ApiModelProperty("微信支付通知")
    @PostMapping()
    public String notify(@RequestHeader Map<String, String> header, @RequestBody String body) throws WxErrorException {
        String key = "Payment:1:10559";
        final String uploadPath = config.getUploadPath();
        final com.gxwebsoft.common.system.entity.Payment payment = redisUtil.get(key, Payment.class);
        String privateKeyPath = uploadPath.concat("/file").concat(payment.getApiclientKey());
        String apiclientCert = uploadPath.concat("/file").concat(payment.getApiclientCert());

        com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
                .serialNumber(header.get("wechatpay-serial"))
                .nonce(header.get("wechatpay-nonce"))
                .signature(header.get("wechatpay-signature"))
                .timestamp(header.get("wechatpay-timestamp"))
                .body(body)
                .build();

        // 如果已经初始化了 RSAAutoCertificateConfig，可直接使用
        // 没有的话，则构造一个
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(payment.getMchId())
                .privateKeyFromPath(privateKeyPath)
                .merchantSerialNumber(payment.getMerchantSerialNumber())
                .apiV3Key(payment.getApiKey())
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        return doPay(transaction);
    }

    public String doPay(Transaction transaction) throws WxErrorException {

        System.out.println("支付通知 >>>>> ");
        System.out.println("transaction = " + transaction);

        // TODO 1.查询订单信息
        final Order order = orderService.getByOutTradeNo(transaction.getOutTradeNo());
        if (order.getPayStatus().equals(0)) {
//            orderService.settle(order);

            // TODO 2.更新订单支付状态
            order.setPayStatus(1);
            order.setTransactionId(transaction.getTransactionId());
            order.setPayPrice(new BigDecimal(NumberUtil.decimalFormat("0.00", transaction.getAmount().getTotal() * 0.01)));
            order.setPayTime(DateUtil.date());
            order.setExpirationTime(DateUtil.offset(DateUtil.date(), DateField.YEAR, 10));
            orderService.updateById(order);

            if (order.getCouponId() != null && order.getCouponId() > 0) {
                UserCoupon userCoupon = userCouponService.getById(order.getCouponId());
                userCoupon.setOrderId(order.getOrderId());
                userCoupon.setUsed(1);
                userCoupon.setUsedTime(LocalDateTime.now());
                userCouponService.updateById(userCoupon);
            }

            // TODO 3.更新订单商品的支付状态
            if (order.getType().equals(0)) {
                final boolean update = orderGoodsService.update(new LambdaUpdateWrapper<OrderGoods>().eq(OrderGoods::getOrderId, order.getOrderId()).set(OrderGoods::getPayStatus, 1));
                System.out.println("update1 = " + update);
                // TODO 3.1 更新商品销量、库存数量
                final List<OrderGoods> orderGoods = orderGoodsService.listByOrderId(order.getOrderId());
                final Set<Integer> goodsIds = orderGoods.stream().map(OrderGoods::getGoodsId).collect(Collectors.toSet());
                final Map<Integer, List<OrderGoods>> collectGoods = orderGoods.stream().collect(Collectors.groupingBy(OrderGoods::getGoodsId));
                final List<Goods> goods = goodsService.list(new LambdaQueryWrapper<Goods>().in(Goods::getGoodsId, goodsIds));
                String goodsNameList = goods.get(0).getGoodsName().length() > 12 ? goods.get(0).getGoodsName().substring(0, 12) : goods.get(0).getGoodsName();
                if (goods.size() > 1) goodsNameList += "等" + goods.size() + "件商品";
                for (Goods g : goods) {
                    final List<OrderGoods> goods1 = collectGoods.get(g.getGoodsId());
                    final OrderGoods goods2 = goods1.get(0);
                    g.setSales(g.getSales() + goods2.getTotalNum());
                    if (g.getStock().compareTo(0) >= 0) {
                        g.setStock(g.getStock() - goods2.getTotalNum());
                    }
                }
                final boolean batchById = goodsService.updateBatchById(goods);
                System.out.println("batchById = " + batchById);
            } else if (order.getType().equals(1)) {
                final boolean update = orderInfoService.update(
                        new LambdaUpdateWrapper<OrderInfo>()
                                .eq(OrderInfo::getOrderId, order.getOrderId())
                                .set(OrderInfo::getPayStatus, 1)
                );
                System.out.println("update2 = " + update);
                final List<OrderGoods> orderGoods = orderGoodsService.listByOrderId(order.getOrderId());
                final Set<Integer> goodsIds = orderGoods.stream().map(OrderGoods::getGoodsId).collect(Collectors.toSet());
                final Map<Integer, List<OrderGoods>> collectGoods = orderGoods.stream().collect(Collectors.groupingBy(OrderGoods::getGoodsId));
                final List<Goods> goods = goodsService.list(new LambdaQueryWrapper<Goods>().in(Goods::getGoodsId, goodsIds));
                String goodsNameList = goods.get(0).getGoodsName().length() > 12 ? goods.get(0).getGoodsName().substring(0, 12) : goods.get(0).getGoodsName();
                if (goods.size() > 1) goodsNameList += "等" + goods.size() + "件商品";
                for (Goods g : goods) {
                    final List<OrderGoods> goods1 = collectGoods.get(g.getGoodsId());
                    final OrderGoods goods2 = goods1.get(0);
                    g.setSales(g.getSales() + goods2.getTotalNum());
                }
                goodsService.updateBatchById(goods);

                Merchant merchant = merchantService.getById(order.getMerchantId());
                RequestUtil requestUtil = new RequestUtil();
                User merchantUser = requestUtil.getByUserId(merchant.getUserId());
                if (merchantUser != null && merchantUser.getOfficeOpenid() != null && !merchantUser.getOfficeOpenid().isEmpty()) {
                    String address = (order.getAddress() == null || order.getAddress().isEmpty()) ? "自提" : order.getAddress();
                    officeMpService.expressSendMessage(merchantUser.getOfficeOpenid(), order.getOrderNo(), goodsNameList, address);
                }
            } else if (order.getType().equals(3)) {
                // 门店充值
                final List<OrderGoods> orderGoods = orderGoodsService.listByOrderId(order.getOrderId());
                MerchantChargePackage merchantChargePackage = merchantChargePackageService.getById(orderGoods.get(0).getGoodsId());
                UserBalanceInMerchant userBalanceInMerchant = userBalanceInMerchantService.getBalance(order.getMerchantId(), order.getUserId());
                BigDecimal balance = merchantChargePackage.getAmount().add(merchantChargePackage.getSendAmount());
                if (userBalanceInMerchant == null) {
                    userBalanceInMerchant = new UserBalanceInMerchant();
                    userBalanceInMerchant.setUserId(order.getUserId());
                    userBalanceInMerchant.setMerchantId(order.getMerchantId());
                    userBalanceInMerchant.setBalance(balance);
                    userBalanceInMerchantService.save(userBalanceInMerchant);
                } else {
                    userBalanceInMerchant.setBalance(userBalanceInMerchant.getBalance().add(balance));
                    userBalanceInMerchantService.updateById(userBalanceInMerchant);
                }
            } else if (order.getType().equals(4)) {
                // 门店商品套餐
                final List<OrderGoods> orderGoods = orderGoodsService.listByOrderId(order.getOrderId());
                MerchantGoodsPackage merchantGoodsPackage = merchantGoodsPackageService.getById(orderGoods.get(0).getGoodsId());
                UserGoodsInMerchant userGoodsInMerchant = userGoodsInMerchantService.infoInMerchant(merchantGoodsPackage.getId(), order.getUserId());
                if (userGoodsInMerchant == null) {
                    userGoodsInMerchant = new UserGoodsInMerchant();
                    userGoodsInMerchant.setUserId(order.getUserId());
                    userGoodsInMerchant.setPackageId(merchantGoodsPackage.getId());
                    userGoodsInMerchant.setRemainNum(merchantGoodsPackage.getGetNum());
                    userGoodsInMerchantService.save(userGoodsInMerchant);
                } else {
                    userGoodsInMerchant.setRemainNum(userGoodsInMerchant.getRemainNum() + merchantGoodsPackage.getGetNum());
                    userGoodsInMerchantService.updateById(userGoodsInMerchant);
                }
            }
            // TODO 4. 清除购物车
            final boolean remove = cartService.remove(new LambdaQueryWrapper<Cart>().eq(Cart::getUserId, order.getUserId()).eq(Cart::getIsNew, true));
            System.out.println("remove = " + remove);

            // TODO 5.累计会员积分

        }
        return "订单已支付";
    }
}
