package com.liquidnet.service.goblin.service.impl;

import com.github.pagehelper.PageInfo;
import com.google.common.base.Joiner;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.candy.constant.CandyRedisConst;
import com.liquidnet.service.candy.dto.CandyUserCouponBasicDto;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.entity.GoblinBackOrder;
import com.liquidnet.service.goblin.entity.GoblinBackOrderLog;
import com.liquidnet.service.goblin.param.GoblinAppOrderRefundParam;
import com.liquidnet.service.goblin.service.IGoblinMailTrackService;
import com.liquidnet.service.goblin.service.IGoblinOrderAppService;
import com.liquidnet.service.goblin.service.impl.helper.GoblinRefundHelper;
import com.liquidnet.service.goblin.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;

import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS;
import static com.liquidnet.commons.lang.util.DateUtil.getNowTime;


@Service
@Slf4j
public class GoblinOrderAppServiceImpl implements IGoblinOrderAppService {

    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils mongoUtils;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinOrderUtils orderUtils;
    @Autowired
    GoblinRefundHelper refundHelper;
    @Autowired
    IGoblinMailTrackService goblinMailTrackService;


    @Override
    public ResponseDto<PageInfo<GoblinAppOrderListVo>> orderList(int page, String pre) {
        String uid = CurrentUtil.getCurrentUid();
        List<GoblinAppOrderListVo> orderVoList = ObjectUtil.goblinAppOrderListVoArrayList();
        List<String> orderIds;
        if (pre == null) {
            orderIds = redisUtils.getOrderList(uid);
        } else if (pre.equals(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue())) {
            orderIds = redisUtils.getZhengzaiOrderList(uid);
        } else {
            return ResponseDto.failure("参数错误");
        }
        int size = 40;
        int finalCount = orderIds.size() - page * size;
        int initCount = orderIds.size() - (page - 1) * size - 1;
        if (finalCount <= 0) {
            finalCount = 0;
        }
        for (int i = initCount; i >= finalCount; i--) {
            String orderId = orderIds.get(i);
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
            if (orderVo == null) {
                log.info("[orderList] goblin order is null, orderId: {}", orderId);
                continue;
            }
            GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
            BeanUtils.copyProperties(orderVo, vo);
            if (vo.getReferrerApp() == null) {
                vo.setReferrerApp("");
            }
            if (vo.getReferrerUserId() == null) {
                vo.setReferrerUserId("");
            }
            vo.setRestTime(getRestTime(orderVo));
            List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
            for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                skuVos.add(orderSkuVo);
            }
            vo.setOrderSkuVos(skuVos);
            orderVoList.add(vo);
        }
        PageInfo<GoblinAppOrderListVo> pageInfo = new PageInfo(orderVoList);
        pageInfo.setTotal(orderIds.size());
        return ResponseDto.success(pageInfo);
    }

    @Override
    public ResponseDto<List<GoblinAppOrderListVo>> orderListByMaster(String orderMasterCode) {
        String[] orderIdArray = redisUtils.getMasterCode(orderMasterCode);
        List<GoblinAppOrderListVo> orderVoList = ObjectUtil.goblinAppOrderListVoArrayList();
        for (String orderId : orderIdArray) {
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
            GoblinAppOrderListVo vo = GoblinAppOrderListVo.getNew();
            BeanUtils.copyProperties(orderVo, vo);
            if (vo.getReferrerApp() == null) {
                vo.setReferrerApp("");
            }
            if (vo.getReferrerUserId() == null) {
                vo.setReferrerUserId("");
            }
            vo.setRestTime(getRestTime(orderVo));
            List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
            for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                skuVos.add(orderSkuVo);
            }
            vo.setOrderSkuVos(skuVos);
            orderVoList.add(vo);
        }
        return ResponseDto.success(orderVoList);
    }

    @Override
    public ResponseDto<GoblinAppOrderDetailsVo> orderDetails(String orderId, String uid) {
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);

        if (orderVo == null || (!orderVo.getUserId().equals(uid) && uid != null)) {
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        if (orderVo.getReferrerApp() == null) {
            orderVo.setReferrerApp("");
        }
        if (orderVo.getReferrerUserId() == null) {
            orderVo.setReferrerUserId("");
        }
        GoblinAppOrderDetailsVo vo = GoblinAppOrderDetailsVo.getNew();
        vo.setStoreOrderVo(orderVo);
        List<GoblinOrderSkuVo> skuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.desensitize();// 商品订单页面展示-关联人信息脱敏
            skuVos.add(orderSkuVo);
        }
        LocalDateTime canRefundTime = getCanRefundTime(orderVo);
        if (canRefundTime == null) {
            vo.setCanRefund(0);
        } else {
            if (LocalDateTime.now().isAfter(canRefundTime)) {
                vo.setCanRefund(0);
            } else {
                vo.setCanRefund(1);
            }
        }
        List<String> orderRefundIds = redisUtils.getBackOrderByOrderId(orderId);
        if (orderRefundIds.size() > 0) {
            GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(orderRefundIds.get(orderRefundIds.size() - 1));
            vo.setRefundStatus(backOrderVo.getStatus());
            if (vo.getCanRefund() == 1 && backOrderVo.getRefuseSize() < 1 &&
                    (backOrderVo.getStatus() == 2 || backOrderVo.getStatus() == 3 || backOrderVo.getStatus() == 5) &&
                    (vo.getStoreOrderVo().getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() || vo.getStoreOrderVo().getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {

            } else {
                vo.setCanRefund(0);
            }
        } else {
            vo.setRefundStatus(-1);
        }
        List<GoblinMailVo> mailVos = redisUtils.getGoblinMail(orderId);
        for (GoblinMailVo mailVo : mailVos) {
            mailVo.setOrderSkuVos(null);
            mailVo.setOrderSkuVoIds(null);
            try {
                GoblinMailTrackCache cache = goblinMailTrackService.resolveTrackForRead(orderId, mailVo.getMailId());
                goblinMailTrackService.fillMailSummary(mailVo, cache);
            } catch (Exception e) {
                log.warn("[orderDetails] fill mail track fail orderId={}, mailId={}", orderId, mailVo.getMailId(), e);
            }
        }
        vo.setMailVos(mailVos);
        vo.setRefuseSize(orderRefundIds.size());
        vo.setRestTime(getRestTime(orderVo));
        vo.setStoreOrderVo(orderVo);
        vo.setOrderSkuVos(skuVos);
        return ResponseDto.success(vo);
    }

    @Override
    public Integer couponState(String orderSkuId, String uid) {
        GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
        if (Objects.equals(orderSkuVo.getSkuType(), 2)) {// 券类商品-校验发放的券是否已使用
            // 券类商品默认一个商品对应一个券，下单只可购买一张
            List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtils.get(CandyRedisConst.BASIC_USER_COUPON.concat(uid));
            if (!CollectionUtil.isEmpty(vos)) {
                CandyUserCouponBasicDto basicDto = vos.stream().filter(r -> r.getUcouponId().equals(orderSkuId)).findAny().orElse(null);

                return (!Objects.isNull(basicDto) && basicDto.getState() == 5) ? 5 : 1;
            }
        }
        return 1;
    }

    @Override
    public ResponseDto<Boolean> getProduce(String orderId, String uid) {
        LocalDateTime now = LocalDateTime.now();
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.store.orderStatus.time"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        LinkedList<Object[]> orderStatus = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderSkuStatus = CollectionUtil.linkedListObjectArr();

        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (!orderVo.getUserId().equals(uid)) {
            return ResponseDto.failure("无权操作");
        }
        if (orderVo.getStatus() != GoblinStatusConst.Status.ORDER_STATUS_3.getValue()) {
            return ResponseDto.failure("不可操作");
        }
        //订单状态修改
        orderVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
        orderVo.setDeliveryTime(getNowTime()); // 设置收货时间
        orderStatus.add(new Object[]{
                orderVo.getStatus(), orderVo.getZhengzaiStatus(), now, now,
                orderVo.getOrderId(), now, now
        });
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            //订单款式状态修改
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
            //redis
            redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
            //mongo
            mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
            orderSkuStatus.add(new Object[]{
                    orderSkuVo.getStatus(), now,
                    orderSkuVo.getOrderSkuId(), now, now
            });
        }
        //redis
        redisUtils.setGoblinOrder(orderId, orderVo);
        //mongo
        mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
        //redis
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(), SqlMapping.gets(sqls, orderStatus, orderSkuStatus));
        return ResponseDto.success(true);
    }

    /**
     * 用户发起退款申请。
     * <p>
     * 发货前(status=2)：整单自动退款，含运费，直接调支付网关。
     * 发货后(status=3/4)：可选整单或指定SKU，生成待审核退款单，不含运费。
     */
    @Override
    public ResponseDto<Boolean> applyRefund(GoblinAppOrderRefundParam param) {

        // ---- 准备 SQL 容器 ----
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.user.applyRefundAuto"));
        sqls.add(SqlMapping.get("goblin_order.store.orderStatus"));
        sqls.add(SqlMapping.get("goblin_order.store.orderSkuStatus"));
        sqls.add(SqlMapping.get("goblin_order.store.refundLog"));
        sqls.add(SqlMapping.get("candy_user_coupon.update_apply_refund"));

        LinkedList<Object[]> applyRefundObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderStatusObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> orderSkuStatusObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> refundLogObjs = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> updateCouponObjs = CollectionUtil.linkedListObjectArr();

        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        String nowStr = DateUtil.getNowTime();

        // ---- 1. 订单基础校验 ----
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(param.getOrderId());
        if (orderVo == null) {
            return ResponseDto.failure("不可操作");
        }

        // ---- 2. 分布式锁防并发重复退款 ----
        String lockKey = GoblinRedisConst.REFUND_ORDER_LOCK + param.getOrderId();
        if (!redisUtils.redisUtil.lock(lockKey, 1, 30)) {
            return ResponseDto.failure("退款处理中，请勿重复操作");
        }
        try {
            // ---- 3. 退款前置校验 ----
            // 3a. 是否有处理中的退款单
            List<String> backOrderIds = redisUtils.getBackOrderByOrderId(param.getOrderId());
            for (String backOrderId : backOrderIds) {
                GoblinBackOrderVo backOrderVo = redisUtils.getBackOrderVo(backOrderId);
                if (backOrderVo != null && !GoblinRefundHelper.isBackOrderFinished(backOrderVo.getStatus())) {
                    return ResponseDto.failure("申请失败");
                }
            }
            // 3b. 订单状态：仅允许待发货(2) / 待收货(3) / 已完成(4)
            int orderStatus = orderVo.getStatus();
            if (!(orderStatus == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() || orderStatus == GoblinStatusConst.Status.ORDER_STATUS_3.getValue() || orderStatus == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {
                return ResponseDto.failure("不可操作");
            }
            // 3c. 7天可退窗口
            LocalDateTime canRefundTime = getCanRefundTime(orderVo);
            if (canRefundTime == null || LocalDateTime.now().isAfter(canRefundTime)) {
                return ResponseDto.failure("申请失败");
            }
            // 3d. 用券订单仅支持整单退款
            if (orderHasUsedCoupon(orderVo) && param.getOrderSkuId() != null) {
                return ResponseDto.failure("用券仅支持整单退款");
            }
            // 3e. 发货前仅支持整单退款
            if (orderStatus == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() && StringUtil.isNotBlank(param.getOrderSkuId())) {
                return ResponseDto.failure("发货前仅支持整单退款");
            }

            // ---- 4. 构建退款单骨架（不含SKU明细和最终金额） ----
            GoblinBackOrder backOrder = buildBackOrderSkeleton(orderVo, param, now);

            // ---- 5. 构建退款单 VO ----
            GoblinBackOrderVo vo = GoblinBackOrderVo.getNew();
            BeanUtils.copyProperties(backOrder, vo);
            vo.setCreatedAt(nowStr);

            // ---- 6. 处理退款SKU列表 ----
            List<GoblinBackOrderSkuVo> orderSkuVoList = ObjectUtil.goblinBackOrderSkuVoArrayList();
            BigDecimal skuRefundPrice = BigDecimal.ZERO;

            boolean isUnshipped = orderStatus == GoblinStatusConst.Status.ORDER_STATUS_2.getValue();
            boolean hasSpecificSku = StringUtil.isNotBlank(param.getOrderSkuId());

            if (isUnshipped) {
                // 发货前：仅支持整单退款，遍历所有SKU
                orderStatusObjs.add(new Object[]{orderVo.getStatus(), orderVo.getZhengzaiStatus(), now,
                        orderVo.getOrderId(), now, now});
                for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                    GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                    BigDecimal refundPrice = buildAndPersistRefundSku(orderSkuId, orderSkuVo, false,
                            nowStr, now, orderSkuVoList, orderSkuStatusObjs);
                    if (refundPrice.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseDto.failure("退款价格超过商品可退价格");
                    }
                    skuRefundPrice = skuRefundPrice.add(refundPrice);
                    backOrderLog(orderVo, orderSkuVo, now);
                }
            } else if (hasSpecificSku) {
                // 发货后 + 指定SKU：仅退选中的单个商品
                GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(param.getOrderSkuId());
                if (orderSkuVo == null || !orderVo.getOrderId().equals(orderSkuVo.getOrderId())) {
                    return ResponseDto.failure("不存在");
                }
                // 券类商品校验：已使用则拒绝，未使用则置为无效
                String couponError = validateAndDisableCouponForRefund(orderSkuVo, orderVo.getUserId(), now, updateCouponObjs);
                if (couponError != null) {
                    return ResponseDto.failure(couponError);
                }
                BigDecimal refundPrice = buildAndPersistRefundSku(param.getOrderSkuId(), orderSkuVo, true,
                        nowStr, now, orderSkuVoList, orderSkuStatusObjs);
                if (refundPrice.compareTo(BigDecimal.ZERO) <= 0) {
                    return ResponseDto.failure("退款价格超过商品可退价格");
                }
                skuRefundPrice = skuRefundPrice.add(refundPrice);
                backOrderLog(orderVo, orderSkuVo, now);
            } else {
                // 发货后 + 整单：遍历所有SKU
                for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
                    GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                    String couponError = validateAndDisableCouponForRefund(orderSkuVo, orderVo.getUserId(), now, updateCouponObjs);
                    if (couponError != null) {
                        return ResponseDto.failure(couponError);
                    }
                    BigDecimal refundPrice = buildAndPersistRefundSku(orderSkuId, orderSkuVo, true,
                            nowStr, now, orderSkuVoList, orderSkuStatusObjs);
                    if (refundPrice.compareTo(BigDecimal.ZERO) <= 0) {
                        return ResponseDto.failure("退款价格超过商品可退价格");
                    }
                    skuRefundPrice = skuRefundPrice.add(refundPrice);
                    backOrderLog(orderVo, orderSkuVo, now);
                }
            }

            // ---- 7. 最终金额与SKU汇总校验 ----
            if (skuRefundPrice.compareTo(BigDecimal.ZERO) <= 0) {
                return ResponseDto.failure("退款价格超过商品可退价格");
            }
            fillSkuIdNumsIfBlank(backOrder, orderSkuVoList);
            setFinalRefundPrice(backOrder, orderVo, skuRefundPrice);
            syncBackOrderVoFields(vo, backOrder, orderSkuVoList, nowStr);

            // ---- 8. 操作日志 ----
            GoblinBackOrderLog backOrderLog = initBackLog(param.getOrderId(), uid, now);
            backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
            backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
            backOrderLog.setMessage("用户发起发起：" + JsonUtils.toJson(param));

            // ---- 9. 持久化（Redis + Mongo + MySQL） ----
            applyRefundObjs.add(new Object[]{
                    backOrder.getBackOrderId(), backOrder.getBackCode(), backOrder.getOrderId(),
                    backOrder.getOrderCode(), backOrder.getStoreId(), backOrder.getUserId(),
                    backOrder.getSkuIdNums(), backOrder.getType(), backOrder.getReason(),
                    backOrder.getDescribes(), backOrder.getRealBackPrice(), backOrder.getBackPriceExpress(), backOrder.getStatus(),
                    backOrder.getLogisCompanyName(), backOrder.getMailNo(), backOrder.getPics(), backOrder.getCreatedAt(),
                    backOrder.getAuditAt(), backOrder.getErrorReason()
            });
            refundLogObjs.add(new Object[]{
                    backOrderLog.getBackOrderLogId(), backOrderLog.getBackOrderId(), backOrderLog.getOperationType(),
                    backOrderLog.getMessage(), backOrderLog.getOperationName(), backOrderLog.getStatus(), now
            });
            persistRefundOrder(orderVo, backOrder, vo,
                    sqls, applyRefundObjs, orderStatusObjs, orderSkuStatusObjs, refundLogObjs, updateCouponObjs);

            // ---- 10. 发货前自动调支付网关退款 ----
            if (isUnshipped) {
                return executeAutoRefund(orderVo, backOrder, vo, now);
            }
            return ResponseDto.success();
        } finally {
            redisUtils.redisUtil.uLock(lockKey);
        }
    }

    // ======================== 私有辅助方法 ========================

    /**
     * 判断订单是否使用了优惠券（用户券或店铺券）。
     */
    private boolean orderHasUsedCoupon(GoblinStoreOrderVo orderVo) {
        boolean hasUserCoupon = orderVo.getUcouponId() != null && !orderVo.getUcouponId().isEmpty();
        boolean hasStoreCoupon = orderVo.getStoreCouponId() != null && !orderVo.getStoreCouponId().isEmpty();
        return hasUserCoupon || hasStoreCoupon;
    }

    /**
     * 构建退款单骨架，填充与SKU无关的基础字段。
     * <p>
     * 发货前(status=2)：状态=自动退款(0)，含运费，必须整单。
     * 发货后(status=3/4)：状态=待审核(1)，不含运费，可选整单或指定SKU。
     */
    private GoblinBackOrder buildBackOrderSkeleton(GoblinStoreOrderVo orderVo,
                                                    GoblinAppOrderRefundParam param,
                                                    LocalDateTime now) {
        GoblinBackOrder backOrder = GoblinBackOrder.getNew();
        backOrder.setBackOrderId(IDGenerator.nextTimeId2());
        backOrder.setBackCode(IDGenerator.storeRefundCode(orderVo.getMasterOrderCode()));
        backOrder.setOrderId(param.getOrderId());
        backOrder.setOrderCode(orderVo.getOrderCode());
        backOrder.setStoreId(orderVo.getStoreId());
        backOrder.setLogisCompanyName(param.getCompany());
        backOrder.setMailNo(param.getMailNo());
        backOrder.setUserId(orderVo.getUserId());
        backOrder.setType(GoblinStatusConst.Type.BACK_TYPE_1.getValue());
        backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_1.getValue());
        backOrder.setCreatedAt(now);

        int orderStatus = orderVo.getStatus();
        if (orderStatus == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            // 未发货：仅支持整单退，含运费，自动退款（整单校验已在主方法完成）
            backOrder.setBackPriceExpress(orderVo.getPriceExpress() == null ? BigDecimal.ZERO : orderVo.getPriceExpress());
            backOrder.setReason(param.getReason());
            backOrder.setPics(param.getPics());
            backOrder.setDescribes(param.getDescribes());
            backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_0.getValue());
            backOrder.setAuditAt(now);
            backOrder.setSkuIdNums(Joiner.on(",").join(orderVo.getOrderSkuVoIds()));
        } else {
            // 已发货/已完成(status=3/4)：不含运费，生成待审核退款单
            backOrder.setBackPriceExpress(BigDecimal.ZERO);
            backOrder.setReason(param.getReason());
            backOrder.setPics(param.getPics());
            backOrder.setDescribes(param.getDescribes());
            backOrder.setType(param.getRefundType() == null ? GoblinStatusConst.Type.BACK_TYPE_1.getValue() : param.getRefundType());
            backOrder.setSkuIdNums(param.getOrderSkuId());
        }
        return backOrder;
    }

    /**
     * 券类商品退款前的校验与状态处理：
     * <ul>
     *   <li>非券类商品(skuType != 2)：直接通过</li>
     *   <li>券状态=5(已使用)：拒绝退款</li>
     *   <li>券状态其他：置为2(无效)，防止用户在审核期间消费该券</li>
     * </ul>
     *
     * @return 错误提示，null 表示校验通过
     */
    private String validateAndDisableCouponForRefund(GoblinOrderSkuVo orderSkuVo,
                                                      String userId,
                                                      LocalDateTime now,
                                                      LinkedList<Object[]> updateCouponObjs) {
        if (!Objects.equals(orderSkuVo.getSkuType(), 2)) {
            return null; // 非券类商品，无需校验
        }
        // 券类商品默认一个商品对应一个券，下单只可购买一张
        String ucKey = CandyRedisConst.BASIC_USER_COUPON.concat(userId);
        List<CandyUserCouponBasicDto> vos = (List<CandyUserCouponBasicDto>) redisUtils.get(ucKey);
        if (vos == null || vos.isEmpty()) {
            log.warn("券类商品订单申请退款，未找到用户券列表[orderSkuId={},uid={}]",
                    orderSkuVo.getOrderSkuId(), userId);
            return null;
        }
        int idx = IntStream.range(0, vos.size())
                .filter(i -> vos.get(i).getUcouponId().equals(orderSkuVo.getOrderSkuId()))
                .findFirst().orElse(-1);
        if (-1 != idx) {
            CandyUserCouponBasicDto basicDto = vos.get(idx);
            if (5 == basicDto.getState()) {
                return "券已使用，不可申请"; // 券已使用，不可退款
            }
            // 置为无效，防止用户在后台审核过程中使用券
            basicDto.setState(2);
            vos.set(idx, basicDto);
            redisUtils.redisUtil.set(ucKey, vos);
            updateCouponObjs.add(new Object[]{basicDto.getState(), userId, now, basicDto.getUcouponId()});
        } else {
            log.warn("券类商品订单申请退款，未找到对应券[orderSkuId={},uid={}]",
                    orderSkuVo.getOrderSkuId(), userId);
        }
        return null;
    }

    /**
     * 为单个SKU：计算可退金额、构建 BackOrderSkuVo、更新SKU状态到Redis/Mongo、生成SQL参数。
     *
     * @param orderSkuId    SKU子订单ID
     * @param orderSkuVo    对应的SKU VO（调用方已从Redis获取）
     * @param setSkuType    是否设置skuType（发货后需要，发货前不需要）
     * @return 该SKU的可退金额（remainRefundPrice 结果）
     */
    private BigDecimal buildAndPersistRefundSku(String orderSkuId,
                                                 GoblinOrderSkuVo orderSkuVo,
                                                 boolean setSkuType,
                                                 String nowStr,
                                                 LocalDateTime now,
                                                 List<GoblinBackOrderSkuVo> orderSkuVoList,
                                                 LinkedList<Object[]> orderSkuStatusObjs) {
        // 计算可退金额 = skuPriceActual - priceRefund - 申请中的退款额
        BigDecimal applyingRefundPrice = mongoUtils.getRefundOrderSkuVoPriceBySkuId(orderSkuId);
        BigDecimal refundPrice = GoblinRefundHelper.remainRefundPrice(orderSkuVo, applyingRefundPrice);

        // 更新SKU状态为"退款中"
        orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_61.getValue());

        // 构建 BackOrderSkuVo
        GoblinBackOrderSkuVo backOrderSkuVo = GoblinBackOrderSkuVo.getNew();
        backOrderSkuVo.setOrderSkuId(orderSkuId);
        backOrderSkuVo.setSpuId(orderSkuVo.getSpuId());
        backOrderSkuVo.setSpuName(orderSkuVo.getSpuName());
        backOrderSkuVo.setSkuId(orderSkuVo.getSkuId());
        backOrderSkuVo.setSkuPic(orderSkuVo.getSkuImage());
        backOrderSkuVo.setSkuName(orderSkuVo.getSkuName());
        backOrderSkuVo.setSkuSpecs(orderSkuVo.getSkuSpecs());
        backOrderSkuVo.setRefundPrice(refundPrice);
        backOrderSkuVo.setCreatedAt(nowStr);
        if (setSkuType) {
            backOrderSkuVo.setSkuType(orderSkuVo.getSkuType());
        }
        orderSkuVoList.add(backOrderSkuVo);

        // 持久化SKU状态：Redis + Mongo
        redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
        mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);

        // 生成MySQL更新参数
        orderSkuStatusObjs.add(new Object[]{
                orderSkuVo.getStatus(), now,
                orderSkuVo.getOrderSkuId(), now, now
        });

        return refundPrice;
    }

    /**
     * 如果 skuIdNums 为空（发货后整单退场景），从 orderSkuVoList 中收集填充。
     */
    private void fillSkuIdNumsIfBlank(GoblinBackOrder backOrder, List<GoblinBackOrderSkuVo> orderSkuVoList) {
        if (StringUtil.isNotBlank(backOrder.getSkuIdNums())) {
            return;
        }
        List<String> refundOrderSkuIds = new LinkedList<>();
        for (GoblinBackOrderSkuVo vo : orderSkuVoList) {
            refundOrderSkuIds.add(vo.getOrderSkuId());
        }
        backOrder.setSkuIdNums(Joiner.on(",").join(refundOrderSkuIds));
    }

    /**
     * 计算并设置最终退款金额。
     * 发货前：SKU总额 + 运费；发货后：仅SKU总额。
     */
    private void setFinalRefundPrice(GoblinBackOrder backOrder, GoblinStoreOrderVo orderVo, BigDecimal skuRefundPrice) {
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            backOrder.setRealBackPrice(GoblinRefundHelper.beforeShipRefundPrice(skuRefundPrice, backOrder.getBackPriceExpress()));
        } else {
            backOrder.setRealBackPrice(skuRefundPrice);
            backOrder.setBackPriceExpress(BigDecimal.ZERO);
        }
    }

    /**
     * 将 backOrder 中的最终字段同步到 vo 中。
     */
    private void syncBackOrderVoFields(GoblinBackOrderVo vo, GoblinBackOrder backOrder,
                                        List<GoblinBackOrderSkuVo> orderSkuVoList, String nowStr) {
        vo.setRealBackPrice(backOrder.getRealBackPrice());
        vo.setBackPriceExpress(backOrder.getBackPriceExpress());
        vo.setStatus(backOrder.getStatus());
        vo.setAuditAt(backOrder.getAuditAt() == null ? null : nowStr);
        vo.setBackOrderSkuVos(orderSkuVoList);
        vo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
    }

    /**
     * 持久化退款单到 Redis + Mongo + MySQL(MQ异步)。
     */
    private void persistRefundOrder(GoblinStoreOrderVo orderVo,
                                     GoblinBackOrder backOrder,
                                     GoblinBackOrderVo vo,
                                     LinkedList<String> sqls,
                                     LinkedList<Object[]> applyRefundObjs,
                                     LinkedList<Object[]> orderStatusObjs,
                                     LinkedList<Object[]> orderSkuStatusObjs,
                                     LinkedList<Object[]> refundLogObjs,
                                     LinkedList<Object[]> updateCouponObjs) {
        // Redis
        redisUtils.setBackOrderVo(backOrder.getBackOrderId(), vo);
        redisUtils.setGoblinOrder(orderVo.getOrderId(), orderVo);
        redisUtils.addBackOrderByOrderId(orderVo.getOrderId(), backOrder.getBackOrderId());
        // Mongo
        mongoUtils.insertGoblinBackOrderVo(vo);
        mongoUtils.updateGoblinStoreOrderVo(orderVo.getOrderId(), orderVo);
        // MySQL (MQ异步)
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(),
                SqlMapping.gets(sqls, applyRefundObjs, orderStatusObjs, orderSkuStatusObjs, refundLogObjs, updateCouponObjs));
    }

    /**
     * 发货前自动退款：调用支付网关，失败则回滚状态。
     */
    private ResponseDto<Boolean> executeAutoRefund(GoblinStoreOrderVo orderVo,
                                                    GoblinBackOrder backOrder,
                                                    GoblinBackOrderVo vo,
                                                    LocalDateTime now) {
        String returnString;
        try {
            returnString = refundHelper.initRefund(orderVo, backOrder.getRealBackPrice(), backOrder.getBackCode());
        } catch (Exception e) {
            log.error("REFUND EXCEPTION, orderId={}", orderVo.getOrderId(), e);
            rollbackAutoRefund(orderVo, backOrder, vo, now, "退款异常：" + e.getMessage());
            return ResponseDto.failure("退款失败:退款异常：" + e.getMessage());
        }
        if (!refundHelper.isRefundSuccess(returnString)) {
            // 退款失败，回滚退款单及SKU状态
            String message = refundHelper.getRefundMessage(returnString);
            log.error("REFUND DATA = " + returnString);
            rollbackAutoRefund(orderVo, backOrder, vo, now, "失败原因：" + message);
            return ResponseDto.failure("退款失败:失败原因：" + message);
        }
        // 支付宝micropay需主动查询结果
        if (DragonConstant.REFUND_TYPE_MICROPAY_ALIPAY.equals(orderVo.getPaymentType())) {
            refundHelper.alipayCallBack(orderVo, backOrder.getBackCode());
        }
        return ResponseDto.success();
    }

    /**
     * 发货前自动退款失败/异常时，回滚退款单和SKU状态。
     */
    private void rollbackAutoRefund(GoblinStoreOrderVo orderVo,
                                     GoblinBackOrder backOrder,
                                     GoblinBackOrderVo vo,
                                     LocalDateTime now,
                                     String errorReason) {
        backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_10.getValue());
        backOrder.setErrorReason(errorReason);
        vo.setStatus(backOrder.getStatus());
        vo.setErrorReason(backOrder.getErrorReason());
        redisUtils.setBackOrderVo(backOrder.getBackOrderId(), vo);
        mongoUtils.updateGoblinBackOrderVo(backOrder.getBackOrderId(), vo);
        // 回滚SKU状态到订单原始状态
        int rollbackStatus = orderVo.getStatus();
        for (String orderSkuId : orderVo.getOrderSkuVoIds()) {
            GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
            if (orderSkuVo != null) {
                orderSkuVo.setStatus(rollbackStatus);
                redisUtils.setGoblinOrderSku(orderSkuId, orderSkuVo);
                mongoUtils.updateGoblinOrderSkuVo(orderSkuId, orderSkuVo);
            }
        }
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(),
                SqlMapping.get("goblin_order.store.applyRefund",
                        vo.getStatus(), vo.getReason(), vo.getAuditAt(), now,
                        backOrder.getBackOrderId(), now, now
                )
        );
    }

    @Override
    public ResponseDto<Boolean> againRefund(GoblinAppOrderRefundParam param) {
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_order.user.againRefund"));
        sqls.add(SqlMapping.get("goblin_order.store.refundLog"));

        LinkedList<Object[]> applyRefund = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> refundLog = CollectionUtil.linkedListObjectArr();

        String uid = CurrentUtil.getCurrentUid();
        LocalDateTime now = LocalDateTime.now();
        GoblinBackOrderVo backOrder = redisUtils.getBackOrderVo(param.getOrderBackId());
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(backOrder.getOrderId());
        if (!orderVo.getUserId().equals(uid) || !backOrder.getStatus().equals(GoblinStatusConst.Status.ORDER_BACK_STATUS_3.getValue())) {
            return ResponseDto.failure("无权操作");
        }
        if (!(orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue() ||
                orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue())) {
            return ResponseDto.failure("不可操作");
        }
        //判断7天
        LocalDateTime canRefundTime = getCanRefundTime(orderVo);
        if (canRefundTime == null) {
            return ResponseDto.failure("申请失败");
        } else {
            if (LocalDateTime.now().isAfter(canRefundTime)) {
                return ResponseDto.failure("申请失败");
            }
        }
        backOrder.setStatus(GoblinStatusConst.Status.ORDER_BACK_STATUS_1.getValue());
        backOrder.setDescribes(param.getDescribes());
        backOrder.setPics(param.getPics());
        backOrder.setReason(param.getReason());
        backOrder.setType(param.getRefundType());
        //添加日志
        GoblinBackOrderLog backOrderLog = initBackLog(backOrder.getOrderId(), uid, now);
        backOrderLog.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
        backOrderLog.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
        backOrderLog.setMessage("用户再次发起退款：" + backOrder);
        //redis
        redisUtils.setBackOrderVo(backOrder.getBackOrderId(), backOrder);
        //mongo
        mongoUtils.updateGoblinBackOrderVo(backOrder.getBackOrderId(), backOrder);
        //mysql
        applyRefund.add(new Object[]{
                backOrder.getStatus(),
                backOrder.getDescribes(), backOrder.getPics(), backOrder.getReason(), backOrder.getType(),
                now, backOrder.getBackOrderId()
        });
        //添加日志
        refundLog.add(new Object[]{
                backOrderLog.getBackOrderLogId(), backOrderLog.getBackOrderId(), backOrderLog.getOperationType(),
                backOrderLog.getMessage(), backOrderLog.getOperationName(), backOrderLog.getStatus(), now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_USER_ORDER_OPERA.getKey(), SqlMapping.gets(sqls, applyRefund, refundLog));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<List<GoblinBackOrderVo>> refundDetails(String orderId) {
        List<GoblinBackOrderVo> vos = ObjectUtil.goblinBackOrderVoArrayList();
        List<String> backOrderList = redisUtils.getBackOrderByOrderId(orderId);
        for (String backOrderId : backOrderList) {
            GoblinBackOrderVo vo = redisUtils.getBackOrderVo(backOrderId);
            if (vo == null) {
                continue;
            }
            GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(vo.getOrderId());
            if (orderVo != null) {
                vo.setPayType(orderVo.getPayType());
            }
            vo.setOperationType(GoblinRefundHelper.resolveBackOrderOperationType(vo));
            vos.add(vo);
        }
        return ResponseDto.success(vos);
    }

//    @Override
//    public String huiFuSync(HttpServletRequest request) {
//        try {
//            // 验签请参data
//            String responseData = request.getParameter("resp_data");
//            // 验签请参sign
//            String sign = request.getParameter("sign");
//            // 使用汇付公钥验签
////            if (!RsaUtils.verify(responseData, PUBLIC_KEY, sign)) {
////                // 验签失败处理
////                return "";
////            }
//            JSONObject dataObj = JSON.parseObject(responseData);
//            String subRespCode = dataObj.getString("sub_resp_code");
//            String reqSeqId = dataObj.getString("req_seq_id");
//            String orderMasterCode = dataObj.getString("mer_ord_id");
//            String payCode = dataObj.getString("mer_ord_id");
//            String paymentType = dataObj.getString("trans_type");
//            String paymentId = dataObj.getString("hf_seq_id");
//            String paymentAt = dataObj.getString("end_time");
//            if ("00000000".equals(subRespCode)) {
//                log.debug("SYNC PARAM = " + responseData);
//                //支付时间
//                LocalDateTime now = LocalDateTime.now();
//                String[] array = redisUtils.getMasterCode(orderMasterCode);
//                String uid = "zhengzai";
//                BigDecimal priceActual = BigDecimal.ZERO;
//                for (String orderId : array) {
//                    GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
//                    if(orderVo.getStatus()==GoblinStatusConst.Status.ORDER_STATUS_4.getValue()){
//                        continue;
//                    }
//                    uid = orderVo.getUserId();
//                    priceActual = priceActual.add(orderVo.getPriceActual());
//                    if (orderVo == null) {
//                        log.error("订单号：" + orderMasterCode + " 订单不存在");
//                        return "fail";//订单不存在
//                    }
//                    LinkedList<String> sqls = CollectionUtil.linkedListString();
//                    LinkedList<Object[]> sqlDataOrder = CollectionUtil.linkedListObjectArr();
//                    LinkedList<Object[]> sqlDataSku = CollectionUtil.linkedListObjectArr();
//                    GoblinStoreOrder storeOrder = GoblinStoreOrder.getNew();
//                    storeOrder.setPaymentType(paymentType);
//                    storeOrder.setPaymentId(paymentId);
//                    storeOrder.setPayCode(payCode);
//                    LocalDateTime payTime = LocalDateTime.parse(paymentAt, DTFYMDHMS);
//                    storeOrder.setPayTime(payTime);
//                    if (orderVo.getWriteOffCode().equals("EMPTY")) {
//                        storeOrder.setWriteOffCode(IDGenerator.getWriteOffCode());
//                    } else {
//                        storeOrder.setWriteOffCode("");
//                    }
//                    storeOrder.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
//                    storeOrder.setUpdatedAt(now);
//                    sqls.add(SqlMapping.get("goblin_order.pay.order"));
//                    sqlDataOrder.add(new Object[]{
//                            storeOrder.getPaymentType(), storeOrder.getPaymentId(), storeOrder.getPayCode(), storeOrder.getPayTime(), storeOrder.getWriteOffCode(), storeOrder.getStatus(), storeOrder.getUpdatedAt(),
//                            orderId, now, now
//                    });
//                    sqls.add(SqlMapping.get("goblin_order.pay.sku"));
//                    List<String> skuList = orderVo.getOrderSkuVoIds();
//                    for (String orderSkuVoIds : skuList) {
//                        GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuVoIds);
//                        //增加销量
//                        redisUtils.incrSkuSaleCount(orderSkuVo.getSpuId(), orderSkuVo.getSkuId(), orderSkuVo.getNum());
//                        orderSkuVo.setStatus(GoblinStatusConst.Status.ORDER_STATUS_4.getValue());
//                        //redis
//                        redisUtils.setGoblinOrderSku(orderSkuVo.getOrderSkuId(), orderSkuVo);
//                        //mongo
//                        mongoUtils.updateGoblinOrderSkuVo(orderSkuVo.getOrderSkuId(), orderSkuVo);
//                        //mongo 添加操作日志
//                        GoblinOrderLogVo logVo = GoblinOrderLogVo.getNew();
//                        logVo.setOrderId(orderVo.getOrderId());
//                        logVo.setOrderCode(orderVo.getOrderCode());
//                        logVo.setPayCode(orderVo.getPayCode());
//                        logVo.setStoreId(orderVo.getStoreId());
//                        if (orderSkuVo.getSkuId().indexOf(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue()) > 0) {
//                            logVo.setOrderType("zhengzai");
//                        } else {
//                            logVo.setOrderType("order");
//                        }
//                        logVo.setSpuId(orderSkuVo.getSpuId());
//                        logVo.setSkuId(orderSkuVo.getSkuId());
//                        logVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual().multiply(new BigDecimal(100)).longValue());
//                        logVo.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getValue());
//                        logVo.setRemark(GoblinStatusConst.Status.ORDER_LOG_STATUS_11.getDesc());
//                        logVo.setOperationId(uid);
//                        logVo.setOperationName(orderVo.getUserName());
//                        logVo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_1.getValue());
//                        logVo.setCreatedAt(LocalDateTime.now());
//                        mongoUtils.insertGoblinOrderLogVo(logVo);
//                        //mysql
//                        sqlDataSku.add(new Object[]{
//                                orderSkuVo.getStatus(), now,
//                                orderSkuVo.getOrderSkuId(), now, now
//                        });
//                    }
//                    //redis
//                    orderVo.setPayCode(storeOrder.getPayCode());
//                    orderVo.setPayTime(paymentAt);
//                    orderVo.setWriteOffCode(storeOrder.getWriteOffCode());
//                    orderVo.setStatus(storeOrder.getStatus());
//                    orderVo.setPaymentId(paymentId);
//                    orderVo.setPaymentType(paymentType);
//                    orderVo.setOrderSkuVoIds(skuList);
//                    redisUtils.setGoblinOrder(orderId, orderVo);
//                    redisUtils.setOffCode(orderVo.getWriteOffCode(), orderVo.getMasterOrderCode());
//                    //删除未支付订单
//                    redisUtils.removeGoblinOrder(orderVo.getRandomKey() + "", orderId);
//                    //mongo
//                    mongoUtils.updateGoblinStoreOrderVo(orderId, orderVo);
//                    //mysql
//                    queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_ORDER_CREATE_PAY.getKey(),
//                            SqlMapping.gets(sqls, sqlDataOrder, sqlDataSku));
//                }
//                //加分
//                if (noZhengzaiOrder(uid)) {
//                    orderUtils.doTask(uid, priceActual);
//                }
//            } else {
//                // 业务处理失败
//                log.info("处理失败");
//            }
//            return "RECV_ORD_ID_" + reqSeqId;
//        } catch (Exception e) {
//            log.info("异步回调开始，参数，request={},异常={}", request, e);
//            e.printStackTrace();
//        }
//        return "";
//    }

    private GoblinBackOrderLog initBackLog(String orderId, String uid, LocalDateTime now) {
        GoblinBackOrderLog log = GoblinBackOrderLog.getNew();
        log.setBackOrderId(orderId);
        log.setOperationName(uid);
        log.setBackOrderLogId(IDGenerator.nextTimeId2());
        log.setCreatedAt(now);
        return log;
    }

    private void backOrderLog(GoblinStoreOrderVo orderVo, GoblinOrderSkuVo orderSkuVo, LocalDateTime now) {
        //操作日志vo
        GoblinOrderLogVo logVo = GoblinOrderLogVo.getNew();
        logVo.setOrderId(orderVo.getOrderId());
        logVo.setOrderCode(orderVo.getOrderCode());
        logVo.setPayCode(orderVo.getPayCode());
        if (orderSkuVo.getSkuId().indexOf(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue()) > 0) {
            logVo.setOrderType("zhengzai");
        } else {
            logVo.setOrderType("order");
        }
        logVo.setStoreId(orderVo.getStoreId());
        logVo.setSpuId(orderSkuVo.getSpuId());
        logVo.setSpuName(orderSkuVo.getSpuName());
        logVo.setSkuId(orderSkuVo.getSkuId());
        logVo.setSkuPriceActual(orderSkuVo.getSkuPriceActual().multiply(BigDecimal.valueOf(100)).negate().longValue());
        logVo.setStatus(GoblinStatusConst.Status.ORDER_LOG_STATUS_21.getValue());
        logVo.setRemark("申请退款,orderSkuVoId=" + orderSkuVo.getOrderSkuId());
        logVo.setOperationId(orderVo.getUserId());
        logVo.setOperationType(GoblinStatusConst.Type.OPERATION_TYPE_2.getValue());
        logVo.setCreatedAt(now);
        mongoUtils.insertGoblinOrderLogVo(logVo);
    }

    @Override
    public ResponseDto<List<GoblinMailVo>> getMail(String orderId, String mailId) {
        List<GoblinMailVo> voList = redisUtils.getGoblinMail(orderId);
        for (GoblinMailVo vo : voList) {
            if (mailId.equals(vo.getMailId())) {
                List<GoblinOrderSkuVo> orderSkuVos = ObjectUtil.getGoblinOrderSkuVoArrayList();
                for (String orderSkuId : vo.getOrderSkuVoIds()) {
                    GoblinOrderSkuVo orderSkuVo = redisUtils.getGoblinOrderSkuVo(orderSkuId);
                    orderSkuVos.add(orderSkuVo);
                }
                vo.setOrderSkuVos(orderSkuVos);
            }
        }
        return ResponseDto.success(voList);
    }

    @Override
    public ResponseDto<GoblinMailTrackCache> logisticsDetail(String orderId, String mailId, String uid) {
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || (uid != null && !orderVo.getUserId().equals(uid))) {
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        GoblinMailTrackCache cache = goblinMailTrackService.resolveTrackForRead(orderId, mailId);
        if (cache == null) {
            // findMail 未命中：请确认传的是订单详情里的 mailId，不是 mailNo
            return ResponseDto.failure("快递信息不存在，请确认 mailId 是否正确");
        }
        return ResponseDto.success(cache);
    }

    @Override
    public ResponseDto<List<GoblinStoreRecommendGoodsVo>> recommendStoreGoods(String orderId, String uid) {
        GoblinStoreOrderVo orderVo = redisUtils.getGoblinOrder(orderId);
        if (orderVo == null || (uid != null && !orderVo.getUserId().equals(uid))) {
            return ResponseDto.failure(ErrorMapping.get("20003"));
        }
        return goblinMailTrackService.recommendStoreGoods(orderId);
    }

    //获取 订单剩余可支付时间[S]
    private long getRestTime(GoblinStoreOrderVo orderVo) {
        long restTime = 0L;
        int time = orderVo.getPayCountdownMinute();
        if (orderVo.getMarketType() != null && orderVo.getMarketType().equals(GoblinStatusConst.MarketPreStatus.MARKET_PRE_ZHENGZAI.getValue())) {
            time = 0;
        }
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_0.getValue()) {
            try {
                Date OverdueAt = DateUtil.addMin(DateUtil.parse(orderVo.getCreatedAt(), "yyyy-MM-dd HH:mm:ss"), time);
                restTime = DateUtil.intervalSeconds(
                        OverdueAt,
                        DateUtil.parse(DateUtil.getNowTime(), "yyyy-MM-dd HH:mm:ss")
                );
                if (restTime <= 0L) {
                    restTime = 0L;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return restTime;
    }

    //获取 可申请退款时间
    private LocalDateTime getCanRefundTime(GoblinStoreOrderVo orderVo) {
        LocalDateTime canRefundTimeDateTime = null;
        if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_2.getValue()) {
            try {
                // 允许退款修改成发货时间+14天
//                canRefundTimeDateTime = LocalDateTime.parse(orderVo.getPayTime(), DTF_YMD_HMS).plusDays(7);
//                if (StringUtil.isBlank(orderVo.getDeliveryTime())) {
//                    canRefundTimeDateTime = LocalDateTime.parse(orderVo.getPayTime(), DTF_YMD_HMS).plusDays(7);
//                }else {
//                    canRefundTimeDateTime = LocalDateTime.parse(orderVo.getDeliveryTime(), DTF_YMD_HMS).plusDays(14);
//                }
                // 未发货商品 可直接退款
                canRefundTimeDateTime = LocalDateTime.now().plusDays(7);
//                log.info("[getCanRefundTime] 未发货商品可退款时间: {}", canRefundTimeDateTime);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_3.getValue()
                || orderVo.getStatus() == GoblinStatusConst.Status.ORDER_STATUS_4.getValue()) {
            if (StringUtil.isBlank(orderVo.getDeliveryTime())) {
                canRefundTimeDateTime = LocalDateTime.parse(orderVo.getPayTime(), DTF_YMD_HMS).plusDays(7);
            } else {
                canRefundTimeDateTime = LocalDateTime.parse(orderVo.getDeliveryTime(), DTF_YMD_HMS).plusDays(7);
            }
        }
        log.info("[getCanRefundTime] 订单可退款时间: orderId: {}, orderStatus: {}, canRefundTimeDateTime: {}",
                orderVo.getOrderId(), orderVo.getStatus(), canRefundTimeDateTime);
        return canRefundTimeDateTime;
    }

    private boolean noZhengzaiOrder(String uid) {
        return !uid.equals("zhengzai");
    }
}
