package com.yida.data.device.consume.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
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.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yida.data.common.core.common.ResultMsgType;
import com.yida.data.common.core.common.ResultStatusType;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.entity.Dict;
import com.yida.data.common.core.entity.apply.EduApplyProductOrder;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.UPayConstant;
import com.yida.data.common.core.entity.constant.UnionPayConstant;
import com.yida.data.common.core.entity.consume.*;
import com.yida.data.common.core.entity.pay.UPayOrder;
import com.yida.data.common.core.entity.pay.UnionPayOrder;
import com.yida.data.common.core.entity.system.EduDeptPayType;
import com.yida.data.common.core.entity.system.EduPayWxConfig;
import com.yida.data.common.core.entity.system.UnionPayConfig;
import com.yida.data.common.core.entity.user.EduParent;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.common.core.entity.user.EduStudentApply;
import com.yida.data.common.core.enums.*;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.*;
import com.yida.data.common.service.CommonService;
import com.yida.data.device.consume.mapper.EduConsumeOrderMapper;
import com.yida.data.device.consume.mapper.EduConsumeRecordMapper;
import com.yida.data.device.consume.service.EduConsumeOrderService;
import com.yida.data.device.consume.service.EduConsumeOrderStudentService;
import com.yida.data.device.consume.service.EduStudentConsumeCardService;
import com.yida.data.device.consume.service.H5ConsumeService;
import com.yida.data.device.dto.consume.CreateConsumeOrderDTO;
import com.yida.data.device.dto.consume.H5ConsumeOrderPageDTO;
import com.yida.data.device.dto.consume.H5ConsumeRecordPageDTO;
import com.yida.data.device.vo.consume.*;
import com.yida.data.user.feign.RemoteStudentApplyService;
import com.yida.data.user.feign.RemoteStudentService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

/**
 * 消费机前端service
 *
 * @author ZYJ
 * @date 2023/3/16
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class H5ConsumeServiceImpl implements H5ConsumeService {

    private final EduConsumeOrderService eduConsumeOrderService;
    private final EduStudentConsumeCardService eduStudentConsumeCardService;
    private final EduConsumeOrderStudentService eduConsumeOrderStudentService;

    private final EduConsumeOrderMapper eduConsumeOrderMapper;
    private final EduConsumeRecordMapper eduConsumeRecordMapper;

    private final RemoteStudentService remoteStudentService;
    private final RemoteStudentApplyService remoteStudentApplyService;

    private final RedisService redisService;
    private final CommonService commonService;
    private final UnionPayPublicUtil unionPayPublicUtil;

    private static final ExecutorService CONSUME_ORDER_SUCCESS_POOL = ThreadPoolUtil.getThreadPool("consume-order-pool-%d");
    private static final Snowflake ORDER_CODE_GENERATOR = new Snowflake(1, 1);

    private static final String CONSUME_WX_PAY_NOTIFY_URL = "device/in/consume/wxPayNotify";
    private static final String CONSUME_WX_REFUND_NOTIFY_URL = "device/in/consume/wxRefundNotify";

    private static final String CONSUME_UNION_PAY_NOTIFY_URL = "device/in/consume/unionPayNotify";
    private static final String CONSUME_UNION_PAY_RETURN_URL = "";

    @Value("${febs.apiUrl}")
    private String apiUrl;

    @Value("${febs.pageUrl}")
    private String pageUrl;

    @Override
    public ConsumeVipVO checkVip(Long studentId, Long schoolId) {
        Dict dict = commonService.getDictByTypeAndValueOrLabel("apply_type", null, "食堂消费");
        // 查询是否是会员
        EduStudentApply studentApply = remoteStudentApplyService.getStudentApply(studentId, dict.getValue()).getData();
        ConsumeVipVO consumeVipVO = new ConsumeVipVO();
        if (Objects.isNull(studentApply)) {
            consumeVipVO.setVipFlag(false);
        } else {
            consumeVipVO.setVipFlag(true);
            consumeVipVO.setStartTime(studentApply.getStartTime());
            consumeVipVO.setEndTime(studentApply.getEndTime());
            EduStudentConsumeCard consumeCard = eduStudentConsumeCardService.getOne(Wrappers.lambdaQuery(new EduStudentConsumeCard())
                    .eq(EduStudentConsumeCard::getStudentId, studentId));
            if (Objects.nonNull(consumeCard)) {
                consumeVipVO.setBalance(consumeCard.getBalance());
                consumeVipVO.setCardStatus(consumeCard.getCardStatus());
                EduStudent student = remoteStudentService.getStudentNoPermission(studentId).getData();
                consumeVipVO.setStuCardNum(student.getStuCardNumber());
            }
            EduDeptPayType deptPayWay = commonService.getDeptPayWay(schoolId);
            if (Objects.nonNull(deptPayWay)) {
                consumeVipVO.setPayWay(deptPayWay.getPayWay());
                consumeVipVO.setPayType(deptPayWay.getSupportType());
            }
        }
        return consumeVipVO;
    }

    @Override
    public String reportLoss(Long studentId) {
        EduStudentConsumeCard consumeCard = eduStudentConsumeCardService.getOne(Wrappers.lambdaQuery(new EduStudentConsumeCard())
                .eq(EduStudentConsumeCard::getStudentId, studentId));
        if (Objects.isNull(consumeCard)) {
            throw new FebsException(ResultMsgType.CARD_STATUS_ERROR.getValue());
        }
        EduStudent eduStudent = remoteStudentService.getStudentNoPermission(studentId).getData();
        // 获取学校消费机服务器信息
        EduConsumeConfig consumeConfig = commonService.getConsumeConfigByDept(consumeCard.getDeptId());
        // 调用消费机挂失接口
        ConsumeUtil.lockCard(consumeConfig, ConsumeUtil.getPersonInfo(consumeConfig, eduStudent.getStuCardNumber()).getStr("cardID"));
        consumeCard.setCardStatus(EduStudentConsumeCard.LOSS_CARD);
        eduStudentConsumeCardService.updateById(consumeCard);
        return EduStudentConsumeCard.LOSS_CARD.toString();
    }

    @Override
    public String unfreeze(Long studentId) {
        EduStudentConsumeCard consumeCard = eduStudentConsumeCardService.getOne(Wrappers.lambdaQuery(new EduStudentConsumeCard())
                .eq(EduStudentConsumeCard::getStudentId, studentId));
        if (Objects.isNull(consumeCard)) {
            throw new FebsException(ResultMsgType.CARD_STATUS_ERROR.getValue());
        }
        EduStudent eduStudent = remoteStudentService.getStudentNoPermission(studentId).getData();
        // 获取学校消费机服务器信息
        EduConsumeConfig consumeConfig = commonService.getConsumeConfigByDept(consumeCard.getDeptId());
        // 调用消费机解挂接口
        ConsumeUtil.unLockCard(consumeConfig, ConsumeUtil.getPersonInfo(consumeConfig, eduStudent.getStuCardNumber()).getStr("cardID"));
        consumeCard.setCardStatus(EduStudentConsumeCard.NORMAL_CARD);
        eduStudentConsumeCardService.updateById(consumeCard);
        return EduStudentConsumeCard.NORMAL_CARD.toString();
    }

    @Override
    public ConsumePayInfoVO createConsumeOrder(CreateConsumeOrderDTO dto) {
        CurrentUser currentUser = FebsUtil.getCurrentUser();
        // 查询学生信息
        EduStudent student = remoteStudentService.getStudentNoPermission(dto.getStudentId()).getData();
        if (Objects.isNull(student)) {
            throw new FebsException("学生信息错误");
        }
        if (NumberUtil.isLessOrEqual(dto.getMoney(), BigDecimal.ZERO)) {
            throw new FebsException("请输入正确的充值金额");
        }
        // 判断是否有下单缓存信息
        ConsumeOrderStudentCacheVO existOrderStudent = (ConsumeOrderStudentCacheVO) redisService.get(
                CachePrefixConstant.CONSUME_ORDER_STUDENT + dto.getStudentId().toString());
        if (Objects.nonNull(existOrderStudent)) {
            return ConsumePayInfoVO.builder()
                    .errorCode(ResultStatusType.FAIL.getValue())
                    .errorMessage(String.format("%s%s正在支付中, 请耐心等待",
                            existOrderStudent.getStudentName(), existOrderStudent.getParentType()))
                    .orderCode(existOrderStudent.getOrderNo())
                    .build();
        }
        if (StringUtils.isEmpty(dto.getPayWay()) ||
                PayWay.ALIPAY.getValue().equals(dto.getPayWay())) {
            throw new FebsException(ResultMsgType.PAY_TYPE_ERROR.getValue());
        }
        // 家长信息
        List<EduParent> parents = student.getParents();
        EduParent orderParent = parents.stream().filter(
                x -> currentUser.getMobile().equals(x.getMobile())).collect(Collectors.toList()).get(0);
        if (Objects.isNull(orderParent)) {
            log.error("家长信息错误, studentId: {}, mobile: {}", dto.getStudentId(), currentUser.getMobile());
            throw new FebsException("学生信息错误");
        }
        String orderCode = "";
        try {
            // 订单号 需要根据支付方式生成不同的订单号
            String orderNo = "";
            if (PayWay.WEI_XIN.getValue().equals(dto.getPayWay())) {
                // 微信
                orderNo = String.valueOf(ORDER_CODE_GENERATOR.nextId());
            } else if (PayWay.UNION.getValue().equals(dto.getPayWay())) {
                // 银联
                // 获取银联商户号相关信息
                UnionPayConfig config = commonService.getUnionPayConfigByDept(student.getSchoolId());
                orderNo = UnionPayUtil.getOrderNumber(Objects.nonNull(config.getParentConfig())
                        ? config.getParentConfig().getSourceNumber() : config.getSourceNumber());
            } else if (PayWay.U_PAY.getValue().equals(dto.getPayWay())) {
                // 收钱吧
                orderNo = String.valueOf(ORDER_CODE_GENERATOR.nextId());
            }
            if (StringUtils.isEmpty(orderNo)) {
                log.error("生成订单号失败！");
                throw new FebsException(ResultMsgType.ORDER_FAIL.getValue());
            }
            orderCode = orderNo;
            ConsumeOrderStudentCacheVO consumeOrderStudentCacheVO = ConsumeOrderStudentCacheVO.builder()
                    .studentId(dto.getStudentId())
                    .studentName(student.getStuName())
                    .parentId(orderParent.getId())
                    .parentType(orderParent.getParentType())
                    .mobile(currentUser.getMobile())
                    .orderNo(orderNo)
                    .build();
            // 添加学生消费订单缓存
            redisService.set(CachePrefixConstant.CONSUME_ORDER_STUDENT + dto.getStudentId().toString(), consumeOrderStudentCacheVO, UPayConstant.ORDER_TIME);
            return createOrder(dto, student, orderParent, currentUser, orderNo);
        } catch (FebsException e) {
            // 删除学生消费订单缓存
            redisService.del(CachePrefixConstant.CONSUME_ORDER_STUDENT + dto.getStudentId());
            // 删除消费订单对应缓存
            if (StringUtils.isNotBlank(orderCode)) {
                redisService.del(CachePrefixConstant.CONSUME_ORDER + orderCode);
                redisService.del(CachePrefixConstant.CONSUME_ORDER_FLAG + orderCode);
            }
            throw new FebsException(e.getMessage());
        } catch (Exception e) {
            // 删除学生消费订单缓存
            redisService.del(CachePrefixConstant.CONSUME_ORDER_STUDENT + dto.getStudentId());
            // 删除消费订单对应缓存
            if (StringUtils.isNotBlank(orderCode)) {
                redisService.del(CachePrefixConstant.CONSUME_ORDER + orderCode);
                redisService.del(CachePrefixConstant.CONSUME_ORDER_FLAG + orderCode);
            }
            throw new FebsException(ResultMsgType.ORDER_FAIL.getValue());
        }
    }

    /**
     * 生成订单并返回支付信息
     *
     * @param dto         生成消费订单请求类
     * @param student     学生信息
     * @param orderParent 下单家长
     * @param currentUser 登录用户信息
     * @param orderNo     订单号
     * @return com.yida.data.device.vo.consume.ConsumePayInfoVO
     * @author ZYJ
     * @date 2023/3/23 15:50
     */
    private ConsumePayInfoVO createOrder(CreateConsumeOrderDTO dto, EduStudent student,
                                         EduParent orderParent, CurrentUser currentUser, String orderNo) {
        // 生成消费订单信息
        EduConsumeOrder eduConsumeOrder = new EduConsumeOrder();
        eduConsumeOrder.setOrderCode(orderNo);
        // 流水号
        eduConsumeOrder.setTransactionNumber(PayUtil.generateSerialNumber("P", dto.getSchoolId(), ""));
        eduConsumeOrder.setStudentId(student.getId());
        eduConsumeOrder.setTotalMoney(dto.getMoney());
        eduConsumeOrder.setPracticalMoney(dto.getMoney());
        eduConsumeOrder.setPhone(currentUser.getMobile());
        // 订单状态和支付状态
        eduConsumeOrder.setOrderStatus(OrderStatusEnum.NOT_PAY.getStatus());
        eduConsumeOrder.setPayStatus(PayStatusEnum.NOT_PAY.getStatus());
        eduConsumeOrder.setPayWay(dto.getPayWay());
        eduConsumeOrder.setPayType(dto.getPayType());
        eduConsumeOrder.setDeptId(student.getSchoolId());
        // 保存订单主体信息
        eduConsumeOrderService.save(eduConsumeOrder);
        // 保存学生信息
        EduConsumeOrderStudent eduConsumeOrderStudent = new EduConsumeOrderStudent();
        BeanUtils.copyProperties(student, eduConsumeOrderStudent);
        eduConsumeOrderStudent.setId(null);
        eduConsumeOrderStudent.setOrderId(eduConsumeOrder.getOrderId());
        eduConsumeOrderStudent.setStudentId(student.getId());
        eduConsumeOrderStudent.setStudentName(student.getStuName());
        eduConsumeOrderStudent.setStudentNumber(student.getStuNumber());
        eduConsumeOrderStudent.setStuCardNumber(student.getStuCardNumber());
        eduConsumeOrderStudent.setStudentFamilyType(student.getFamilyType());
        eduConsumeOrderStudent.setStudentParentType(orderParent.getParentType());
        eduConsumeOrderStudentService.save(eduConsumeOrderStudent);

        // 下单返回信息
        String result = placeOrder(student, eduConsumeOrder, orderParent);
        // 添加消费订单缓存
        redisService.set(CachePrefixConstant.CONSUME_ORDER + eduConsumeOrder.getOrderCode(), eduConsumeOrder, UPayConstant.ORDER_TIME);
        redisService.set(CachePrefixConstant.CONSUME_ORDER_FLAG + eduConsumeOrder.getOrderCode(), result, UPayConstant.ORDER_TIME);

        return getPayInfo(eduConsumeOrder.getOrderCode(), result, eduConsumeOrder.getDeptId(), true,
                dto.getPayWay(), dto.getPayType());
    }

    /**
     * 调用第三方接口生成支付信息
     *
     * @param student         学生信息
     * @param eduConsumeOrder 订单信息
     * @param orderParent     下单家长
     * @return java.lang.String
     * @author ZYJ
     * @date 2023/3/23 15:43
     */
    private String placeOrder(EduStudent student, EduConsumeOrder eduConsumeOrder, EduParent orderParent) {
        // 下单返回信息
        String result = "";
        try {
            if (PayWay.WEI_XIN.getValue().equals(eduConsumeOrder.getPayWay())) {
                // 微信支付
                EduPayWxConfig config = commonService.getPayWxConfigBySchool(student.getSchoolId());
                EduApplyProductOrder order = new EduApplyProductOrder();
                order.setProductName("");
                order.setOrderCode(eduConsumeOrder.getOrderCode());
                order.setPraccticalMoney(eduConsumeOrder.getPracticalMoney().doubleValue());
                String ip = FebsUtil.getHttpServletRequestIpAddress();
                // js api下单
                if (WxPayTypeEnum.JS_TYPE.getStatus().equals(eduConsumeOrder.getPayType())) {
                    result = WxPayUtil.placeOrderJs(config, order, orderParent.getWxPublicOpenId(), ip,
                            apiUrl + CONSUME_WX_PAY_NOTIFY_URL);
                } else {
                    // h5下单
                    result = WxPayUtil.placeOrderH5(config, order, ip, apiUrl + CONSUME_WX_PAY_NOTIFY_URL);
                }
            } else if (PayWay.UNION.getValue().equals(eduConsumeOrder.getPayWay())) {
                // 获取对应支付类型枚举
                UnionPayTypeEnum unionPayTypeEnum = EnumUtils.valueOf(UnionPayTypeEnum.class, eduConsumeOrder.getPayType(),
                        UnionPayTypeEnum.class.getMethod("getType"));
                // 银联云闪付
                result = UnionPayUtil.placeOrder(commonService.getUnionPayConfigByDept(student.getSchoolId()),
                        UnionPayOrder.builder()
                                .orderNo(eduConsumeOrder.getOrderCode())
                                .transactionNumber(eduConsumeOrder.getTransactionNumber())
                                .payMoney(eduConsumeOrder.getPracticalMoney())
                                .notifyUrl(apiUrl + CONSUME_UNION_PAY_NOTIFY_URL)
                                .returnUrl(pageUrl + CONSUME_UNION_PAY_RETURN_URL)
                                .payTypeEnum(unionPayTypeEnum)
                                .build());
            } else if (PayWay.U_PAY.getValue().equals(eduConsumeOrder.getPayWay())) {
                // 收钱吧
                DeptConsumeTerminalCache terminalCache = commonService.getDeptConsumeTerminal(eduConsumeOrder.getDeptId());
                result = UPayUtil.placeOrder(UPayOrder.builder()
                        .clientSn(eduConsumeOrder.getOrderCode())
                        .totalAmount(eduConsumeOrder.getPracticalMoney())
                        .operator(orderParent.getMobile())
                        .notifyUrl(apiUrl + UPayConstant.NOTIFY_URL)
//                        .returnUrl(pageUrl + UPayConstant.RETURN_URL)
                        .returnUrl("http://zbztest.yd-data.com")
                        .build(), terminalCache.getTerminalSn(), terminalCache.getTerminalKey());
            }
        } catch (Exception e) {
            log.error("消费下单失败", e);
            throw new FebsException(ResultMsgType.ORDER_FAIL.getValue());
        }
        if (StringUtils.isEmpty(result)) {
            log.error("消费下单失败, 没有支付信息");
            throw new FebsException(ResultMsgType.ORDER_FAIL.getValue());
        }
        return result;
    }

    /**
     * 获取订单支付信息
     *
     * @param orderCode 订单号
     * @param orderFlag 微信js支付prepayId, h5支付跳转地址
     * @param deptId    学校id
     * @param needToPay 是否需要跳转支付
     * @param payWay    支付方式 {@link PayWay}
     * @param payType   支付类型
     * @return com.yida.data.device.vo.consume.ConsumePayInfoVO
     * @author ZYJ
     * @date 2023/3/23 15:48
     */
    public ConsumePayInfoVO getPayInfo(String orderCode, String orderFlag, Long deptId,
                                       boolean needToPay, String payWay, Integer payType) {
        ConsumePayInfoVO consumePayInfoVO = null;
        if (PayWay.WEI_XIN.getValue().equals(payWay)) {
            // 微信
            consumePayInfoVO = getWxJsSign(orderCode, orderFlag, deptId, needToPay, payType);
        } else if (PayWay.UNION.getValue().equals(payWay)) {
            // 银联
            consumePayInfoVO = ConsumePayInfoVO.builder()
                    .orderCode(orderCode)
                    .needToPay(needToPay)
                    .payWay(payWay)
                    .payType(payType)
                    .payDomain(UnionPayConstant.URL)
                    .payUrl(orderFlag)
                    .build();
        } else if (PayWay.U_PAY.getValue().equals(payWay)) {
            // 收钱吧
            consumePayInfoVO = ConsumePayInfoVO.builder()
                    .orderCode(orderCode)
                    .needToPay(needToPay)
                    .payWay(payWay)
                    .payType(payType)
                    .payDomain(UPayConstant.URL)
                    .payUrl(orderFlag)
                    .build();
        }
        return consumePayInfoVO;
    }

    /**
     * 生成微信支付信息
     *
     * @param orderCode 订单号
     * @param orderFlag 微信js支付prepayId, h5支付跳转地址
     * @param deptId    学校id
     * @param needToPay 是否需要跳转支付
     * @param wxPayType 微信支付类型 {@link WxPayTypeEnum}
     * @return com.yida.data.device.vo.consume.ConsumePayInfoVO
     * @author ZYJ
     * @date 2023/3/23 15:47
     */
    public ConsumePayInfoVO getWxJsSign(String orderCode, String orderFlag, Long deptId,
                                        boolean needToPay, Integer wxPayType) {
        ConsumePayInfoVO infoVO = new ConsumePayInfoVO();
        infoVO.setOrderCode(orderCode);
        infoVO.setNeedToPay(needToPay);
        infoVO.setPayWay(PayWay.WEI_XIN.getValue());
        infoVO.setPayType(wxPayType);

        // js api类型
        if (Objects.isNull(wxPayType) || WxPayTypeEnum.JS_TYPE.getStatus().equals(wxPayType)) {
            EduPayWxConfig config = commonService.getPayWxConfigBySchool(deptId);
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonceStr = RandomUtil.randomString(32);
            String packages = "prepay_id=" + orderFlag;
            String code = config.getWxPublicId() + "\n" + timestamp + "\n" + nonceStr + "\n" + packages + "\n";
            Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, config.getApiCreditPrivateKeyNoHead(),
                    null);
            byte[] res = sign.sign(code.getBytes());
            String signRes = Base64.encode(res);
            infoVO.setWxAppId(config.getWxPublicId());
            infoVO.setWxSign(signRes);
            infoVO.setWxTimestamp(timestamp);
            infoVO.setWxPackage(packages);
            infoVO.setWxNonceStr(nonceStr);
        } else {
            infoVO.setPayUrl(orderFlag);
        }
        return infoVO;
    }

    @Override
    public void consumeOrderSuccess(String orderCode) {
        CONSUME_ORDER_SUCCESS_POOL.execute(() -> {
            EduConsumeOrder order = eduConsumeOrderService.getOne(new LambdaQueryWrapper<>(new EduConsumeOrder())
                    .eq(EduConsumeOrder::getOrderCode, orderCode));

            if (Objects.nonNull(order)
                    && (OrderStatusEnum.NOT_PAY.getStatus().equals(order.getOrderStatus())
                    || OrderStatusEnum.USER_PAYING.getStatus().equals(order.getOrderStatus()))) {
                if (PayWay.WEI_XIN.getValue().equals(order.getPayWay())) {
                    // 微信
                    wxConsumeOrderSuccess(order);
                } else if (PayWay.UNION.getValue().equals(order.getPayWay())) {
                    // 银联
                    unionConsumeOrderSuccess(order);
                } else if (PayWay.U_PAY.getValue().equals(order.getPayWay())) {
                    // 收钱吧
                    uPayConsumeOrderSuccess(order);
                }
            }
        });
    }

    /**
     * 处理微信查询订单
     *
     * @param order 订单信息
     * @author ZYJ
     * @date 2023/3/23 16:48
     */
    private void wxConsumeOrderSuccess(EduConsumeOrder order) {
        boolean flag = false;
        // 订单号
        String orderCode = order.getOrderCode();
        // 查询学校微信配置信息
        EduPayWxConfig config = commonService.getPayWxConfigBySchool(order.getDeptId());
        while (LocalDateTimeUtil.between(order.getCreateDate(), LocalDateTime.now()).getSeconds() < UPayConstant.ORDER_TIME) {
            try {
                JSONObject resJson = JSONUtil.parseObj(WxPayUtil.queryOrder(config, orderCode));
                String tradeState = resJson.getStr("trade_state");
                if (WxTradeStateEnum.NOT_PAY.getStatus().equals(tradeState)) {
                    continue;
                }
                WxTradeStateEnum wxTradeStateEnum = EnumUtils.valueOf(WxTradeStateEnum.class, tradeState,
                        WxTradeStateEnum.class.getMethod("getStatus"));
                switch (Objects.requireNonNull(wxTradeStateEnum)) {
                    // 支付成功
                    case SUCCESS:
                        consumeOrderPaySuccess(orderCode, DateUtil.parseLocalDateTime(resJson.getStr("success_time"), "yyyy-MM" + "-dd'T" + "'HH:mm" + ":ssXXX"));
                        flag = true;
                        break;
                    // 作废订单
                    case CLOSED:
                    case REVOKED:
                    case PAY_ERROR:
                        order.setOrderStatus(OrderStatusEnum.CLOSED.getStatus());
                        order.setPayStatus(PayStatusEnum.CANCEL.getStatus());
                        eduConsumeOrderService.updateById(order);
                        flag = true;
                        break;
                    default:
                        break;
                }
                if (flag) {
                    break;
                }
                Thread.sleep(1000L);
            } catch (Exception e) {
                log.error("消费订单(微信支付方式)完成失败, orderNo: {}", orderCode, e);
            }
        }
    }

    /**
     * 处理银联查询订单
     *
     * @param order 订单信息
     * @author ZYJ
     * @date 2023/3/23 16:50
     */
    private void unionConsumeOrderSuccess(EduConsumeOrder order) {
        boolean flag = false;
        // 订单号
        String orderCode = order.getOrderCode();
        // 查询学校银联配置信息
        UnionPayConfig config = commonService.getUnionPayConfigByDept(order.getDeptId());
        // 主商户信息
        UnionPayConfig parentConfig = config.getParentConfig();

        while (LocalDateTimeUtil.between(order.getCreateDate(), LocalDateTime.now()).getSeconds() < UPayConstant.ORDER_TIME) {
            try {
                JSONObject resJson = UnionPayUtil.queryOrder(config,
                        unionPayPublicUtil.getAccessToken(
                                Objects.nonNull(parentConfig) ? parentConfig.getAppId() : config.getAppId(),
                                Objects.nonNull(parentConfig) ? parentConfig.getAppKey() : config.getAppKey()
                        ), orderCode);
                // 支付状态
                String status = (String) resJson.get("status");
                if (UnionTradeStateEnum.NEW_ORDER.getStatus().equals(status)
                        || UnionTradeStateEnum.UNKNOWN.getStatus().equals(status)
                        || UnionTradeStateEnum.WAIT_BUYER_PAY.getStatus().equals(status)) {
                    return;
                }
                UnionTradeStateEnum tradeStateEnum = EnumUtils.valueOf(UnionTradeStateEnum.class, status,
                        UnionTradeStateEnum.class.getMethod("getStatus"));
                switch (Objects.requireNonNull(tradeStateEnum)) {
                    // 支付成功
                    case TRADE_SUCCESS:
                        consumeOrderPaySuccess(order.getOrderCode(),
                                LocalDateTimeUtil.parse((String) resJson.get("payTime"), DatePattern.NORM_DATETIME_PATTERN));
                        flag = true;
                        break;
                    // 订单关闭
                    case TRADE_CLOSED:
                        order.setOrderStatus(OrderStatusEnum.CLOSED.getStatus());
                        order.setPayStatus(PayStatusEnum.CANCEL.getStatus());
                        eduConsumeOrderService.updateById(order);
                        flag = true;
                        break;
                    default:
                        break;
                }
                if (flag) {
                    break;
                }
                Thread.sleep(1000L);
            } catch (Exception e) {
                log.error("消费订单(云闪付支付方式)完成失败, orderNo: {}", orderCode, e);
            }
        }
    }

    /**
     * 处理收钱吧查询订单
     *
     * @param order 订单信息
     * @author ZYJ
     * @date 2023/3/23 17:29
     */
    private void uPayConsumeOrderSuccess(EduConsumeOrder order) {
        boolean flag = false;
        // 订单号
        String orderCode = order.getOrderCode();

        while (LocalDateTimeUtil.between(order.getCreateDate(), LocalDateTime.now()).getSeconds() < UPayConstant.ORDER_TIME) {
            try {
                DeptConsumeTerminalCache terminalCache = commonService.getDeptConsumeTerminal(order.getDeptId());
                JSONObject jsonObject = UPayUtil.queryOrder(orderCode, terminalCache.getTerminalSn(), terminalCache.getTerminalKey());
                JSONObject resJson = jsonObject.getJSONObject("biz_response").getJSONObject("data");
                // 支付状态
                String status = (String) resJson.get("order_status");
                if (UPayTradeStateEnum.CREATED.getStatus().equals(status)
                        || UPayTradeStateEnum.INVALID_STATUS_CODE.getStatus().equals(status)) {
                    return;
                }
                UPayTradeStateEnum tradeStateEnum = EnumUtils.valueOf(UPayTradeStateEnum.class, status,
                        UnionTradeStateEnum.class.getMethod("getStatus"));
                switch (Objects.requireNonNull(tradeStateEnum)) {
                    // 支付成功
                    case PAID:
                        consumeOrderPaySuccess(order.getOrderCode(), LocalDateTimeUtil.ofUTC(Long.parseLong(resJson.getStr("finish_time"))));
                        flag = true;
                        break;
                    // 订单关闭
                    case PAY_CANCELED:
                        order.setOrderStatus(OrderStatusEnum.CLOSED.getStatus());
                        order.setPayStatus(PayStatusEnum.CANCEL.getStatus());
                        eduConsumeOrderService.updateById(order);
                        flag = true;
                        break;
                    default:
                        break;
                }
                if (flag) {
                    break;
                }
                Thread.sleep(1000L);
            } catch (Exception e) {
                log.error("消费订单(收钱吧支付方式)完成失败, orderNo: {}", orderCode, e);
            }
        }
    }

    /**
     * 消费订单支付成功
     *
     * @param orderCode 订单号
     * @param payDate   支付时间
     * @author ZYJ
     * @date 2023/3/23 17:06
     */
    @Override
    public void consumeOrderPaySuccess(String orderCode, LocalDateTime payDate) {
        EduConsumeOrder order = eduConsumeOrderService.getOne(new LambdaQueryWrapper<>(new EduConsumeOrder())
                .eq(EduConsumeOrder::getOrderCode, orderCode));
        order.setPayDate(payDate);
        order.setOrderStatus(OrderStatusEnum.PAY_SUCCESS.getStatus());
        order.setPayStatus(PayStatusEnum.PAY_SUCCESS.getStatus());
        eduConsumeOrderService.updateById(order);
        // 获取学校消费机服务器信息
        EduConsumeConfig consumeConfig = commonService.getConsumeConfigByDept(order.getDeptId());
        EduStudent student = remoteStudentService.getStudentNoPermission(order.getStudentId()).getData();
        // 调用消费机接口
        ConsumeUtil.recharge(consumeConfig, Recharge.builder()
                .amount(order.getPracticalMoney().toString())
                .accountNo(student.getStuCardNumber())
                .increase(true)
                .walletType(1)
                .transactionNumber(order.getTransactionNumber())
                .paymentModel(Recharge.PaymentModel.builder()
                        // 支付方式. 0：现金 1：微信 2：支付宝 4：银行卡 8：其他APP
                        .payType(1)
                        .payTime(LocalDateTimeUtil.format(payDate, DatePattern.NORM_DATETIME_PATTERN))
                        .orderNumber(orderCode)
                        .build())
                .build());
        // 处理对应消费机信息金额
        EduStudentConsumeCard consumeCard = eduStudentConsumeCardService.getOne(Wrappers.lambdaQuery(new EduStudentConsumeCard())
                .eq(EduStudentConsumeCard::getStudentId, order.getStudentId()));
        if (Objects.nonNull(consumeCard)) {
            consumeCard.setBalance(NumberUtil.add(consumeCard.getBalance(), order.getPracticalMoney()));
            eduStudentConsumeCardService.updateById(consumeCard);
        }
        // 删除学生消费订单缓存
        redisService.del(CachePrefixConstant.CONSUME_ORDER_STUDENT + order.getStudentId().toString());
        // 删除消费订单对应缓存
        redisService.del(CachePrefixConstant.CONSUME_ORDER + orderCode);
        redisService.del(CachePrefixConstant.CONSUME_ORDER_FLAG + orderCode);
    }

    @Override
    public IPage<H5ConsumeOrderPageVO> listH5ConsumeOrderPage(H5ConsumeOrderPageDTO dto) {
        return eduConsumeOrderMapper.listH5ConsumeOrderPage(dto.toPage(), dto);
    }

    @Override
    public H5ConsumeOrderPageVO getH5ConsumeOrderInfo(Long orderId, String orderCode) {
        return eduConsumeOrderMapper.getH5ConsumeOrderInfo(orderId, orderCode);
    }

    @Override
    public ConsumePayInfoVO continuePayOrder(String orderCode, Long deptId) {
        EduConsumeOrder order = eduConsumeOrderService.getOne(new LambdaQueryWrapper<>(new EduConsumeOrder())
                .eq(EduConsumeOrder::getOrderCode, orderCode));
        if (Objects.isNull(order) || OrderStatusEnum.CLOSED.getStatus().equals(order.getOrderStatus())) {
            throw new FebsException(ResultMsgType.ORDER_INVALID.getValue());
        }
        // 判断当前订单能否被当前用户支付
        ConsumeOrderStudentCacheVO existConsumeOrderStudent = (ConsumeOrderStudentCacheVO) redisService.get(
                CachePrefixConstant.CONSUME_ORDER_STUDENT + order.getStudentId().toString());
        if (Objects.nonNull(existConsumeOrderStudent)
                && !FebsUtil.getCurrentUser().getMobile().equals(existConsumeOrderStudent.getMobile())) {
            throw new FebsException(String.format("%s%s正在支付中, 请耐心等待",
                    existConsumeOrderStudent.getStudentName(),
                    existConsumeOrderStudent.getParentType()));
        }
        // 获取对应待支付信息缓存
        Object orderFlag = redisService.get(CachePrefixConstant.CONSUME_ORDER_FLAG + orderCode);
        if (Objects.isNull(orderFlag)) {
            throw new FebsException("当前订单已失效！");
        }
        return getPayInfo(orderCode, orderFlag.toString(), deptId,
                true, order.getPayWay(), order.getPayType());
    }

    @Override
    public void cancelOrder(String orderCode) {
        // TODO 2023/3/31 需要做状态判断能否取消订单
        EduConsumeOrder order = eduConsumeOrderService.getOne(new LambdaQueryWrapper<>(new EduConsumeOrder())
                .eq(EduConsumeOrder::getOrderCode, orderCode));
        if (OrderStatusEnum.CLOSED.getStatus().equals(order.getOrderStatus())) {
            throw new FebsException(ResultMsgType.ORDER_INVALID.getValue());
        }
        // 判断当前订单能否被当前用户取消
        ConsumeOrderStudentCacheVO existConsumeOrderStudent = (ConsumeOrderStudentCacheVO) redisService.get(
                CachePrefixConstant.CONSUME_ORDER_STUDENT + order.getStudentId().toString());
        if (Objects.nonNull(existConsumeOrderStudent)
                && !FebsUtil.getCurrentUser().getMobile().equals(existConsumeOrderStudent.getMobile())) {
            throw new FebsException(String.format("%s%s正在支付中, 请耐心等待",
                    existConsumeOrderStudent.getStudentName(), existConsumeOrderStudent.getParentType()));
        }
        order.setOrderStatus(OrderStatusEnum.CLOSED.getStatus());
        order.setPayStatus(PayStatusEnum.CANCEL.getStatus());
        eduConsumeOrderService.updateById(order);
        try {
            // 判断支付方式
            if (PayWay.WEI_XIN.getValue().equals(order.getPayWay())) {
                // 关闭微信订单
                WxPayUtil.closeOrder(commonService.getPayWxConfigBySchool(order.getDeptId()), order.getOrderCode());
            } else if (PayWay.UNION.getValue().equals(order.getPayWay())
                    && !UnionPayTypeEnum.UNION_H5_TYPE.getType().equals(order.getPayType())) {
                // 关闭银联订单 (银联云闪付不支付关闭订单)
                UnionPayConfig unionPayConfig = commonService.getUnionPayConfigByDept(order.getDeptId());
                UnionPayConfig parentConfig = unionPayConfig.getParentConfig();
                UnionPayUtil.closeOrder(unionPayConfig,
                        unionPayPublicUtil.getAccessToken(
                                Objects.nonNull(parentConfig) ? parentConfig.getAppId() : unionPayConfig.getAppId(),
                                Objects.nonNull(parentConfig) ? parentConfig.getAppKey() : unionPayConfig.getAppKey()
                        ), order.getOrderCode());
            } else if (PayWay.U_PAY.getValue().equals(order.getPayWay())) {
                // 关闭收钱吧订单
                DeptConsumeTerminalCache terminalCache = commonService.getDeptConsumeTerminal(order.getDeptId());
                UPayUtil.closeOrder(orderCode, terminalCache.getTerminalSn(), terminalCache.getTerminalKey());
            }
        } catch (Exception e) {
            log.error("关闭订单失败, order: {}", order, e);
            throw new FebsException("取消订单失败");
        }
        // 删除学生消费订单缓存
        redisService.del(CachePrefixConstant.CONSUME_ORDER_STUDENT + order.getStudentId().toString());
        // 删除消费订单对应缓存
        redisService.del(CachePrefixConstant.CONSUME_ORDER + orderCode);
        redisService.del(CachePrefixConstant.CONSUME_ORDER_FLAG + orderCode);
    }

    @Override
    public IPage<H5ConsumeRecordPageVO> listH5ConsumeRecordPage(H5ConsumeRecordPageDTO dto) {
        return eduConsumeRecordMapper.listH5ConsumeRecordPage(dto.toPage(), dto);
    }
}
