package com.yida.data.school.transaction.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.common.ResultBean;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.apply.*;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.LockPrefixConstant;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.EduPayWxConfig;
import com.yida.data.common.core.enums.PayWay;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.common.core.utils.WxPayUtil;
import com.yida.data.common.service.CommonService;
import com.yida.data.rabbit.util.RabbitUtil;
import com.yida.data.school.dto.transaction.EduApplyProductOrderDTO;
import com.yida.data.school.transaction.mapper.EduApplyProductOrderMapper;
import com.yida.data.school.transaction.mapper.EduApplyProductOrderStudentMapper;
import com.yida.data.school.transaction.mapper.EduApplyProductRefundMapper;
import com.yida.data.school.transaction.mapper.EduProductMapper;
import com.yida.data.school.transaction.service.EduProductOrderService;
import com.yida.data.school.transaction.util.GuuidUtil;
import com.yida.data.school.vo.transcation.EduProductOrderVO;
import com.yida.data.school.vo.transcation.PayInfoVO;
import com.yida.data.school.vo.transcation.RefundOrderVO;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.user.feign.RemoteStudentService;
import com.yida.data.user.vo.ParentInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
@RefreshScope
public class EduProductOrderServiceImpl extends ServiceImpl<EduApplyProductOrderMapper, EduApplyProductOrder> implements
    EduProductOrderService {

    private static final String WX_CALL = "product/in/productOrder/wxCall";
    private static final ExecutorService ORDER_SUCCESS_POOL = new ThreadPoolExecutor(10, 20, 1,
        TimeUnit.MINUTES, new LinkedBlockingQueue<>());
    @Resource
    private EduProductMapper eduProductMapper;
    @Resource
    private EduApplyProductOrderStudentMapper eduApplyProductOrderStudentMapper;
    @Resource
    private EduApplyProductRefundMapper eduApplyProductRefundMapper;
    @Resource
    private EduApplyProductOrderMapper eduApplyProductOrderMapper;
    @Resource
    private RemoteStudentService remoteStudentService;
    @Resource
    private RedisService redisService;
    @Resource
    private RabbitUtil rabbitUtil;
    @Resource
    private CommonService commonService;
    @Resource
    private RemoteDeptService remoteDeptService;
    @Value("${febs.apiUrl}")
    private String apiUrl;

    /**
     * 生成订单未支付
     */

    @Override
    @Transactional
    public PayInfoVO createOrder(Long productId, Long[] studentIds, Integer payType, CurrentUser currentUser,
        String ip) {
        boolean flag = false;

        log.info("params:[{}],[{}],[{}]", productId, studentIds, payType);
        EduApplyProductOrder order = new EduApplyProductOrder();
        PayInfoVO vo = new PayInfoVO();
        // 获取商品信息
        EduProduct product = (EduProduct) redisService.hget(CachePrefixConstant.PRODUCT, productId.toString());
        if (product == null) {
            product = eduProductMapper.getInfo(productId);
            redisService.hset(CachePrefixConstant.PRODUCT, productId.toString(), product);
        }
        log.info("product:[{}]", product);
        // 进行库存操作
        // 获取修改库存锁
        redisService.lock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + productId);
        // 获取库存
        Integer stock = (Integer) redisService.get(CachePrefixConstant.PRODUCT_STOCK + productId);
        if (stock == null) {
            stock = product.getStock();
            redisService.set(CachePrefixConstant.PRODUCT_STOCK + productId, stock, 600L);
        }
        if (stock >= studentIds.length) {
            // 修改库存缓存
            redisService.decr(CachePrefixConstant.PRODUCT_STOCK + productId, Long.valueOf(studentIds.length));
            flag = true;
        }
        redisService.unlock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + product.getProductId());
        if (!flag) {
            throw new FebsException("库存不足");
        }
        try {
            // 查询学生班级信息
            List<EduApplyProductOrderStudent> orderStudentList = new ArrayList<>();
            Double realPrice = 0D;
            for (Long studentId : studentIds) {
                EduApplyProductOrderStudent orderStudent = new EduApplyProductOrderStudent();
                BeanUtils.copyProperties(remoteStudentService.getClassInfoByStudent(studentId, currentUser.getMobile()).getData(),
                    orderStudent);
                orderStudentList.add(orderStudent);
                // 订单未超时 不允许再次下单
                EduApplyProductOrder studentOrder =
                    (EduApplyProductOrder) redisService
                        .get(CachePrefixConstant.STUDENT_ORDER + studentId.toString() + "." + product.getProductId().toString());
                // 未支付订单 学生与下单人的关系
                EduApplyProductOrderStudent existOrderStudent = null;
                // 可能数据不同步，查询数据库
                if (studentOrder == null) {
                    existOrderStudent = baseMapper.selectNotPayOrderStudent(studentId, product.getProductId());
                } else {
                    existOrderStudent = eduApplyProductOrderStudentMapper
                        .selectOne(Wrappers.<EduApplyProductOrderStudent>lambdaQuery()
                            .eq(EduApplyProductOrderStudent::getStudentId, studentId)
                            .eq(EduApplyProductOrderStudent::getOrderId, studentOrder.getOrderId()));
                }
                if (existOrderStudent != null) {
                    throw new FebsException(String.format("%s已经为%s下单,等待支付中", existOrderStudent.getStudentParentType(),
                        existOrderStudent.getStudentName()));
                }
                // 计算每个学生的价格
                String studentFamily = orderStudent.getStudentFamilyType();
                String productFamily = product.getDiscountFamilyType();
                realPrice += product.getPrice();
                if (StrUtil.isNotBlank(productFamily) && StrUtil.isNotBlank(studentFamily)) {
                    // 学生为商品符合的特殊家庭 适用减免后的价格
                    String[] familyTypes = studentFamily.split(",");
                    for (String familyType : familyTypes) {
                        if (productFamily.contains(familyType)) {
                            realPrice -= product.getPrice();
                            realPrice += product.getDiscountPrice();
                            break;
                        }
                    }
                }
            }
            // 订单号
            order.setOrderCode(String.valueOf(GuuidUtil.getUUID()));
            // 流水号
            order.setTransactionNumber(generateSerialNumber(orderStudentList.get(0).getSchoolId(),
                product.getProductCode()));
            // 下单人信息
            order.setPhone(currentUser.getMobile());
            order.setCreateId(currentUser.getUserId());
            order.setProductId(productId);
            order.setProductName(product.getProductName());
            order.setProductPrice(product.getPrice());
            order.setProductTotalPrice(product.getPrice() * studentIds.length);
            order.setPraccticalMoney(realPrice);
            order.setProductNum(studentIds.length);
            order.setOrderStatus("0");
            order.setPayStatus("0");
            String payWay = null;
            switch (payType) {
                case 0:
                case 1:
                    payWay = PayWay.WEI_XIN.getValue();
                    break;
            }
            order.setPayWay(payWay);
            save(order);
            // 保存订单与学生对应关系
            for (EduApplyProductOrderStudent orderStudent : orderStudentList) {
                orderStudent.setOrderId(order.getOrderId());
                eduApplyProductOrderStudentMapper.insert(orderStudent);
            }
            log.info("支付：{},{},{}", order.getPraccticalMoney(), order.getProductTotalPrice(), studentIds.length);
            // 发起支付
            String res = null;
            ParentInfoVO parent = remoteStudentService.getParentWithStudent(currentUser.getMobile(),
                null, currentUser.getDeptId()).getData();
            EduPayWxConfig config = commonService.getPayWxConfigBySchool(product.getSchoolId());
            if (order.getPraccticalMoney() > 0D) {
                try {
                    switch (payType) {
                        case 0:
                            res = WxPayUtil.placeOrderJs(config, order, parent.getWxPublicOpenId(), ip,
                                apiUrl + WX_CALL);
                            break;
                        case 1:
                            res = WxPayUtil.placeOrderH5(config, order, ip, apiUrl + WX_CALL);
                            break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("make order fail", e);
                    throw new FebsException("下单失败");
                }
            }
            // 添加订单的信息缓存
            redisService.set(CachePrefixConstant.ORDER + order.getOrderCode(), order, 900L);
            redisService.set(CachePrefixConstant.ORDER_FLAG + order.getOrderCode(), res, 900L);
            // 添加学生的订单缓存
            for (EduApplyProductOrderStudent orderStudent : orderStudentList) {
                redisService.set(
                    CachePrefixConstant.STUDENT_ORDER + orderStudent.getStudentId().toString() + "." + product.getProductId()
                        .toString(),
                    order, 900L);
            }
            if (order.getPraccticalMoney() == 0D) {
                paySuccessUpdate(order.getOrderCode(), LocalDateTime.now());
            } else {
                // 支付方式不同   返回信息也不同
                switch (payType) {
                    case 0:
                        vo = getWxJsSign(order.getOrderCode(), res);
                }
            }
            vo.setOrderCode(order.getOrderCode());
            // 修改商品实际库存
            eduProductMapper.updateProductStock(productId, Long.valueOf(studentIds.length));
        } catch (Exception e) {
            log.error("make order fail", e);
            if (flag) {
                // 进行了减库存操作  还原库存
                redisService.lock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + product.getProductId());
                product = (EduProduct) redisService.hget(CachePrefixConstant.PRODUCT,
                    productId.toString());
                product.setStock(product.getStock() + studentIds.length);
                redisService.hset(CachePrefixConstant.PRODUCT, productId.toString(), product);
                redisService.unlock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + product.getProductId());
            }
            throw new FebsException(FebsUtil.containChinese(e.getMessage()) ? e.getMessage() : "下单失败");
        }
        return vo;
    }

    @Override
    @Transactional
    public ResultBean updateProductOder(EduApplyProductOrder eduApplyProductOrder) {
        //修改订单已支付，并且新增付款关联表
        return ResultBean.buildSuccess("支付成功状态");
    }

    /**
     * 后台订单列表查询
     */
    @Override
    public IPage<EduApplyProductOrder> selectPageListProductOrderService(Page page,
        EduApplyProductOrderDTO eduApplyProductOrder) {
        List<Long> schoolIds = new ArrayList<>();

        if (Objects.isNull(eduApplyProductOrder.getSchoolId())) {
            List<Dept> deptList =
                remoteDeptService.getSchoolByArea(eduApplyProductOrder.getAreaId(), null).getData();
            if (CollUtil.isNotEmpty(deptList)) {
                schoolIds = deptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
            } else {
                schoolIds.add(-1L);
            }
        } else {
            schoolIds.add(eduApplyProductOrder.getSchoolId());
        }

        IPage<EduApplyProductOrder> listOrder = baseMapper.listPageEduProductOrder(page, eduApplyProductOrder, schoolIds);
        if (CollUtil.isNotEmpty(listOrder.getRecords())) {
            for (EduApplyProductOrder order : listOrder.getRecords()) {
                order.setOrderStudentList(
                    eduApplyProductOrderStudentMapper.selectList(Wrappers.lambdaQuery(new EduApplyProductOrderStudent())
                        .eq(EduApplyProductOrderStudent::getOrderId, order.getOrderId())));
            }
        }
        return listOrder;
    }


    /**
     * 生成订单号
     */
    private String generateSerialNumber(Long schoolId, String productCode) {
        StringBuilder stringBuilder = new StringBuilder("Z");
        stringBuilder.append(StrUtil.fill(schoolId.toString(), '0', 9, true));
        stringBuilder.append(StrUtil.fill(productCode, '0', 10, true));
        stringBuilder.append(DateUtil.format(new Date(), "yyyyMMdd"));
        stringBuilder.append(RandomUtil.randomNumbers(8));
        return stringBuilder.toString();
    }

    @Override
    public void refund(EduApplyProductRefund refund, CurrentUser currentUser) {
        EduApplyProductOrder order = baseMapper.getOrderByCode(refund.getOrderCode());
        Asserts.isTrue("2".equals(order.getOrderStatus()) && "1".equals(order.getPayStatus()), "该笔订单无法进行退款");
        // 保存退款信息
        // 退款编号
        refund.setRefundCode(refund.getOrderCode().replace("Z", "R"));
        eduApplyProductRefundMapper.insert(refund);
        //修改订单状态
        order.setOrderStatus("3");
        updateById(order);
        EduPayWxConfig config = commonService.getPayWxConfigBySchool(order.getSchoolId());
        switch (order.getPayWay()) {
            case "1":
                try {
                    WxPayUtil.refund(config, refund.getOrderCode(),
                        refund.getRefundReason(),
                        refund.getRefundCode(),
                        Double.valueOf(order.getPraccticalMoney() * 100).longValue(),
                        Double.valueOf(order.getPraccticalMoney() * 100).longValue(),
                        apiUrl + WX_CALL);
                } catch (Exception e) {
                    log.info("退款失败,msg:[{}],stack:[{}]", e.getMessage(), e.getStackTrace());
                    throw new FebsException("退款失败");
                }
        }
    }

    @Override
    public void wxCall(Map<String, Object> res) {
        //log.info("微信通知,data:[{}]", res);
        //String eventType = res.get("event_type").toString();
        //Map<String, Object> resource = (Map<String, Object>) res.get("resource");
        //// 解密结果
        //try {
        //    JSONObject resJson =
        //            JSONUtil.parseObj(WxPayUtil.decodeText(resource.get("associated_data").toString(),
        //                    resource.get("nonce").toString(), resource.get("ciphertext").toString()));
        //    switch (eventType) {
        //        // 支付成功回调
        //        case WxPayConstant.PAY_NOTICE:
        //            paySuccess(resJson);
        //            break;
        //        // 退款回调
        //        case WxPayConstant.REFUND_SUCCESS_NOTICE:
        //        case WxPayConstant.REFUND_ABNORMAL_NOTICE:
        //        case WxPayConstant.REFUND_CLOSED_NOTICE:
        //            refundSuccess(resJson);
        //            break;
        //    }
        //} catch (Exception e) {
        //    log.error("微信支付回调失败,data:[{}],msg:[{}]", res, e.getMessage());
        //}
    }


    /**
     * 手机查询订单列表
     *
     * @param phone
     * @return
     */
    @Override
    public List selectListProductOrder(Long schoolId, String phone, Long studentId) {
        EduProductOrderVO eduProductOrderVO = new EduProductOrderVO();
        eduProductOrderVO.setStudentId(schoolId);
        eduProductOrderVO.setPhone(phone);
        List<EduApplyProductOrder> list = eduApplyProductOrderMapper.listEduProductOrder(schoolId, phone, studentId);
        return list;
    }

    /**
     * 订单详情
     *
     * @param orderId
     * @return
     */
    @Override
    public EduApplyProductOrder selectEduProductOrder(Long orderId) {
        EduApplyProductOrder eduApplyProductOrder = eduApplyProductOrderMapper.selectById(orderId);
        List<EduApplyProductOrderStudent> eduApplyProductOrderStudents = eduApplyProductOrderStudentMapper
            .selectList(Wrappers.lambdaQuery(new EduApplyProductOrderStudent())
                .eq(EduApplyProductOrderStudent::getOrderId, orderId));
        eduApplyProductOrder.setOrderStudentList(eduApplyProductOrderStudents);
        if ("2".equals(eduApplyProductOrder.getPayStatus())) {
            eduApplyProductOrder.setRefund(eduApplyProductRefundMapper.selectOne(Wrappers.<EduApplyProductRefund>lambdaQuery()
                .eq(EduApplyProductRefund::getOrderCode, eduApplyProductOrder.getOrderCode())));
        }
        return eduApplyProductOrder;
    }

    @Override
    public void orderSuccess(String orderCode) {
        ORDER_SUCCESS_POOL.submit(() -> {
            EduApplyProductOrder order = baseMapper.getOrderByCode(orderCode);
            //EduProduct product = eduProductMapper.selectById(order.getProductId());
            if (order != null && order.getPraccticalMoney() > 0D && PayWay.WEI_XIN.getValue().equals(order.getPayWay()) && "0,1"
                .contains(order.getOrderStatus())) {
                boolean flag = false;
                EduPayWxConfig config = commonService.getPayWxConfigBySchool(order.getSchoolId());
                while (LocalDateTimeUtil.between(order.getCreateDate(), LocalDateTime.now()).getSeconds() < 900L) {
                    try {
                        JSONObject resJson = JSONUtil.parseObj(WxPayUtil.queryOrder(config, orderCode));
                        String tradeState = resJson.getStr("trade_state");
                        if ("NOTPAY".equals(tradeState)) {
                            continue;
                        }
                        switch (tradeState) {
                            // 支付成功情况
                            case "SUCCESS":
                            case "ACCEPT":
                                paySuccessUpdate(orderCode,
                                    DateUtil.parseLocalDateTime(resJson.getStr("success_time"), "yyyy-MM" +
                                        "-dd'T" +
                                        "'HH:mm" +
                                        ":ssXXX"));
                                flag = true;
                                break;
                            // 未完成支付，订单作废
                            case "CLOSED":
                            case "REVOKED":
                            case "PAYERROR":
                                order.setOrderStatus("4");
                                order.setPayStatus("3");
                                eduApplyProductOrderMapper.updateById(order);
                                flag = true;
                                break;
                        }
                        if (flag) {
                            break;
                        }
                        Thread.sleep(1000L);
                    } catch (Exception e) {
                        log.error("order success fail", e);
                    }
                }
            }
        });
    }

    /**
     * 支付成功回调处理
     */
    private void paySuccess(JSONObject jsonObject) {
        String orderCode = jsonObject.getStr("out_trade_no");
        String tradeState = jsonObject.getStr("trade_state");
        String successTime = jsonObject.getStr("success_time");
        String openid = jsonObject.getJSONObject("payer").getStr("openid");
        paySuccessUpdate(orderCode, DateUtil.parseLocalDateTime(successTime, "yyyy-MM-dd'T'HH:mm:ssXXX"));
    }

    /**
     * 支付成功
     */
    @Override
    public void paySuccessUpdate(String orderCode, LocalDateTime successTime) {
        // 从缓存中拿订单
        EduApplyProductOrder order =
            (EduApplyProductOrder) redisService.get(CachePrefixConstant.ORDER + orderCode);
        if (order == null) {
            order = getOne(Wrappers.lambdaQuery(new EduApplyProductOrder()).eq(EduApplyProductOrder::getOrderCode, orderCode));
            // TODO: 2021/6/9 订单已完成进入退款
        }
        // 获取商品信息
        EduProduct product = (EduProduct) redisService.hget(CachePrefixConstant.PRODUCT,
            order.getProductId().toString());
        if (product == null) {
            product = eduProductMapper.getInfo(order.getProductId());
            redisService.hset(CachePrefixConstant.PRODUCT, order.getProductId().toString(), product);
        }
        order.setPayDate(successTime);
        order.setOrderStatus("2");
        order.setPayStatus("1");
        updateById(order);
        // 保存应用和学生关联信息
        List<EduProductApply> applyList = product.getApplyList();
        // 该笔订单包含的学生
        List<EduApplyProductOrderStudent> studentList = eduApplyProductOrderStudentMapper.selectList(
            Wrappers.lambdaQuery(new EduApplyProductOrderStudent())
                .eq(EduApplyProductOrderStudent::getOrderId, order.getOrderId()));
        // 包含的实际商品
        List<EduRealProduct> realProductList = product.getRealProductList();
        // 学生-应用关联关系
//        List<EduStudentApply> studentApplyList = new ArrayList<>();
        for (EduApplyProductOrderStudent orderStudent : studentList) {
            // 删除学生订单缓存
            redisService.del(
                CachePrefixConstant.STUDENT_ORDER + orderStudent.getStudentId().toString() + "." + product.getProductId()
                    .toString());
//            // 购买了应用
//            if (CollUtil.isNotEmpty(applyList)) {
//                for (EduProductApply apply : applyList) {
//                    EduStudentApply studentApply = new EduStudentApply();
//                    studentApply.setStudentId(orderStudent.getStudentId());
//                    studentApply.setApplyCode(apply.getApplyCode());
//                    studentApply.setStartTime(apply.getBeginValidDate().atTime(0, 0, 0));
//                    studentApply.setEndTime(apply.getEndValidDate().atTime(23, 59, 59));
//                    studentApplyList.add(studentApply);
//                }
//            }
            // 购买了商品
            if (CollUtil.isNotEmpty(realProductList)) {
                for (EduRealProduct realProduct : realProductList) {
                    Map<String, String> msg = new HashMap<>();
                    msg.put("studentId", orderStudent.getStudentId().toString());
                    msg.put("identityId", realProduct.getProductValue());
                    // 发送通知
                    rabbitUtil.sendMsg(realProduct.getService(), realProduct.getProductType(), JSONUtil.toJsonStr(msg));
                }
            }
        }
//        // 保存学生-应用关联关系
//        if (CollUtil.isNotEmpty(studentApplyList)) {
//            eduStudentApplyService.saveBatch(studentApplyList);
//        }
        // 删除订单缓存
        redisService.del(CachePrefixConstant.ORDER + orderCode);
    }

    /**
     * 退款成功回调
     */
    private void refundSuccess(JSONObject jsonObject) {
        String orderCode = jsonObject.getStr("out_trade_no");
        String refundCode = jsonObject.getStr("out_refund_no");
        String refundStatus = jsonObject.getStr("refund_status");
        String successTime = jsonObject.getStr("success_time");
        // 拿订单
        EduApplyProductOrder order =
            getOne(Wrappers.lambdaQuery(new EduApplyProductOrder()).eq(EduApplyProductOrder::getOrderCode, orderCode));
        EduApplyProductRefund refund =
            eduApplyProductRefundMapper.selectOne(
                Wrappers.lambdaQuery(new EduApplyProductRefund()).eq(EduApplyProductRefund::getRefundCode, refundCode));
        if ("SUCCESS".equals(refundStatus)) {
            // 更新订单和退款单状态
            order.setOrderStatus("4");
            order.setPayStatus("2");
            order.setIsRefund("1");
            refund.setRefundTime(DateUtil.parseLocalDateTime(successTime, "yyyy-MM-dd'T'HH:mm:ssXXX"));
            updateById(order);
            eduApplyProductRefundMapper.updateById(refund);
        } else if ("CLOSE".equals(refundStatus)) {
            // 已关闭
        } else {
            // 退款异常
        }
    }

    @Override
    public PayInfoVO getWxJsSign(String orderCode, String prepayId) {
        EduApplyProductOrder order = baseMapper.getOrderByCode(orderCode);
        EduPayWxConfig config = commonService.getPayWxConfigBySchool(order.getSchoolId());
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonceStr = RandomUtil.randomString(32);
        String packge = "prepay_id=" + prepayId;
        String code = config.getWxPublicId() + "\n" + timestamp + "\n" + nonceStr + "\n" + packge + "\n";
        Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, config.getApiCreditPrivateKeyNoHead(),
            null);
        byte[] res = sign.sign(code.getBytes());
        String signRes = Base64.encode(res);
        PayInfoVO infoVO = new PayInfoVO();
        infoVO.setWxAppId(config.getWxPublicId());
        infoVO.setWxSign(signRes);
        infoVO.setWxTimestamp(timestamp);
        infoVO.setWxPackage(packge);
        infoVO.setWxNonceeStr(nonceStr);
        return infoVO;
    }

    /**
     * 订单超时变更状态，每5s检测一次
     */
    @Override
    public void updateOrderStatus() {
        // 所有已经超时订单
        List<EduApplyProductOrder> expireOrder = eduApplyProductOrderMapper.selectExpireOrder(LocalDateTime.now());
        if (CollUtil.isNotEmpty(expireOrder)) {
            for (EduApplyProductOrder order : expireOrder) {
                // 微信订单
                if (PayWay.WEI_XIN.getValue().equals(order.getPayWay())) {
                    EduPayWxConfig config = commonService.getPayWxConfigBySchool(order.getSchoolId());
                    // 主动查询是否已经支付了
                    try {
                        JSONObject resJson =
                            JSONUtil.parseObj(WxPayUtil.queryOrder(config, order.getOrderCode()));
                        log.info("resJson:[{}]", resJson);
                        if (resJson.containsKey("code") && "ORDER_NOT_EXIST".equals(resJson.getStr("code"))) {
                            // 订单不存在  取消订单
                            order.setOrderStatus("4");
                            order.setPayStatus("3");
                        } else {
                            String tradeState = resJson.getStr("trade_state");
                            switch (tradeState) {
                                // 支付成功情况
                                case "SUCCESS":
                                case "ACCEPT":
                                    paySuccessUpdate(order.getOrderCode(),
                                        DateUtil.parseLocalDateTime(resJson.getStr("success_time"), "yyyy-MM" +
                                            "-dd'T" +
                                            "'HH:mm" +
                                            ":ssXXX"));
                                    continue;
                                    // 未完成支付还需要关闭订单
                                case "NOTPAY":
                                    WxPayUtil.closeOrder(config, order.getOrderCode());
                                    // 未完成支付，订单作废
                                case "CLOSED":
                                case "REVOKED":
                                case "PAYERROR":
                                    order.setOrderStatus("4");
                                    order.setPayStatus("3");
                                    break;
                            }
                        }
                        if ("4".equals(order.getOrderStatus())) {
                            eduApplyProductOrderMapper.updateById(order);
                            // 未完成支付  增加库存
                            if (!"1".equals(order.getPayStatus())) {
                                // 获取锁
                                redisService.lock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + order.getProductId());
                                // 获取库存
                                Integer stock = (Integer) redisService
                                    .get(CachePrefixConstant.PRODUCT_STOCK + order.getProductId());
                                if (stock == null) {
                                    EduProduct product = eduProductMapper.selectById(order.getProductId());
                                    stock = product.getStock();
                                    redisService.set(CachePrefixConstant.PRODUCT_STOCK + order.getProductId(), stock, 600L);
                                }
                                // 修改库存缓存
                                redisService.incr(CachePrefixConstant.PRODUCT_STOCK + order.getProductId(),
                                    Long.valueOf(order.getOrderStudentList().size()));
                                eduProductMapper.updateProductStock(order.getProductId(),
                                    -Long.valueOf(order.getOrderStudentList().size()));
                                redisService.unlock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + order.getProductId());
                            }
                        }
                    } catch (Exception e) {
                        log.error("更新订单状态失败,order:[{}]", order, e);
                    }
                }
            }
        }
    }

    /**
     * 定时轮询查询退款中订单状态，每个整点查询一次
     */
    @Override
    public void updateRefundStatus() {
        // 查询退款中的订单
        List<RefundOrderVO> refundOrderList = eduApplyProductOrderMapper.selectRefundOrder();
        if (CollUtil.isNotEmpty(refundOrderList)) {
            for (RefundOrderVO refundOrder : refundOrderList) {
                // 微信支付退款
                if (refundOrder.getPayWay() == 1) {
                    // 查询退款进度
                    EduPayWxConfig config = commonService.getPayWxConfigBySchool(refundOrder.getSchoolId());
                    JSONObject resJson =
                        JSONUtil.parseObj(WxPayUtil.queryRefund(config, refundOrder.getRefundCode()));
                    log.info("refund,data:[{}]", resJson);
                    String status = resJson.getStr("status");
                    switch (status) {
                        case "SUCCESS":
                            EduApplyProductOrder order = eduApplyProductOrderMapper.selectById(refundOrder.getOrderId());
                            order.setOrderStatus("4");
                            order.setPayStatus("2");
                            eduApplyProductOrderMapper.updateById(order);
                            // 更新退款状态
                            EduApplyProductRefund refund =
                                eduApplyProductRefundMapper.selectById(refundOrder.getRefundId());
                            refund.setRefundTime(DateUtil.parseLocalDateTime(resJson.getStr("success_time"),
                                "yyyy-MM-dd'T'HH:mm:ssXXX"));
                            eduApplyProductRefundMapper.updateById(refund);
                            if ("2".equals(order.getOrderStatus())) {
                                // 更新商品库存
                                // 获取锁
                                redisService.lock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + order.getProductId());
                                Long num =
                                    eduApplyProductOrderStudentMapper
                                        .selectCount(Wrappers.lambdaQuery(new EduApplyProductOrderStudent())
                                            .eq(EduApplyProductOrderStudent::getOrderId, order.getOrderId()));
                                Integer stock = (Integer) redisService
                                    .get(CachePrefixConstant.PRODUCT_STOCK + order.getProductId());
                                if (stock == null) {
                                    EduProduct product = eduProductMapper.selectById(order.getProductId());
                                    stock = product.getStock();
                                    redisService.set(CachePrefixConstant.PRODUCT_STOCK + order.getProductId(), stock, 600L);
                                }
                                // 删除订单缓存
                                redisService.del(CachePrefixConstant.ORDER + order.getOrderCode());
                                // 修改库存缓存
                                redisService.incr(CachePrefixConstant.PRODUCT_STOCK + order.getProductId(), num);
                                // 修改库存数据库
                                eduProductMapper.updateProductStock(order.getProductId(), -num);
                                redisService.unlock(LockPrefixConstant.PRODUCT_STOCK_EDIT_LOCK + order.getProductId());
                                List<EduApplyProductOrderStudent> orderStudentList =
                                    eduApplyProductOrderStudentMapper.selectList(
                                        Wrappers.lambdaQuery(new EduApplyProductOrderStudent())
                                            .eq(EduApplyProductOrderStudent::getOrderId, order.getOrderId()));
                                if (CollUtil.isNotEmpty(orderStudentList)) {
                                    orderStudentList.forEach(student -> {
                                        // 删除学生订单缓存
                                        redisService.del(
                                            CachePrefixConstant.STUDENT_ORDER + student.getStudentId().toString() + "." + order
                                                .getProductId().toString());
                                    });
                                }
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }
}
