/*
 * Copyright (c) 2018-2999 广州亚米信息科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gson.internal.LinkedTreeMap;
import com.yami.shop.bean.app.dto.OrderCountData;
import com.yami.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.yami.shop.bean.dto.hb.HBBaseReq;
import com.yami.shop.bean.enums.*;
import com.yami.shop.bean.event.CancelOrderEvent;
import com.yami.shop.bean.event.ReceiptOrderEvent;
import com.yami.shop.bean.event.SubmitOrderEvent;
import com.yami.shop.bean.event.SubmitScoreOrderEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.param.*;
import com.yami.shop.bean.po.SMOrderItemPo;
import com.yami.shop.bean.po.SMOrderPo;
import com.yami.shop.bean.vo.ExportContext;
import com.yami.shop.bean.vo.OrderCountVo;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.GlobalException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageAdapter;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.R;
import com.yami.shop.dao.*;
import com.yami.shop.service.*;
import com.yami.shop.service.hb.IHBOrderService;
import com.yami.shop.utils.BinPackingUtil;
import com.yami.shop.utils.CullenUtils;
import com.yami.shop.utils.ExportUtils;
import com.yami.shop.utils.HBSignUtil;
import com.yami.shop.wx.po.RefundInfoPo;
import com.yami.shop.wx.service.WxProviderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.server.ExportException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static com.yami.shop.common.util.HttpUtil.post;

/**
 * @author lgh on 2018/09/15.
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final OrderMapper orderMapper;
    private final OrderRefundRecordMapper orderRefundRecordMapper;
    private final SkuMapper skuMapper;
    private final OrderItemMapper orderItemMapper;
    private final OrderItemService orderItemService;
    private final OrderSettlementService orderSettlementService;
    private final ProductMapper productMapper;
    private final ApplicationEventPublisher eventPublisher;
    private final OrderRefundMapper orderRefundMapper;
    private final PointsRecordMapper pointsRecordMapper;
    private final WxProviderService wxProviderService;
    private final OrderSettlementMapper orderSettlementMapper;
    private final ChannelService channelService;
    private Snowflake snowflake;
    private final OrderRefundSkuMapper orderRefundSkuMapper;
    private final HBSignUtil hbSignUtil;
    private final TzSysUserMapper userMapper;
    @Autowired
    private ExportTaskService exportTaskService;
    private final IHBOrderService hbOrderService;
    //导出
    // 线程池配置
    private final ExecutorService exportExecutor = Executors.newFixedThreadPool(
            5,
            new ThreadFactoryBuilder()
                    .setNameFormat("order-export-thread-%d")
                    .setDaemon(true)
                    .build()
    );


    @Override
    public Order getOrderByOrderNumber(String orderNumber) {
        return orderMapper.getOrderByOrderNumber(orderNumber);
    }

    @Override
    public Order getOrderByOrderNumberAndUserId(String orderNumber, String userId, boolean valid) {
        Order order = orderMapper.getOrderByOrderNumberAndUserId(orderNumber, userId);
        if (valid && order == null) {
            throw new GlobalException("订单不存在");
        }
        return order;
    }


    @Override
    public OrderPayParam getPayUserCountByshopId(Long shopId, Date startTime, Date endTime) {
        OrderPayParam nowOrderPay = orderMapper.getOrderCountByShopId(shopId, startTime, endTime);
        StatisticsRefundParam refundParam = orderRefundMapper.getRefundByShopId(shopId, startTime, endTime);
        Double onePrice = (nowOrderPay.getPayUserCount() == 0) ? 0 : (Arith.div(nowOrderPay.getPayActualTotal(), nowOrderPay.getPayUserCount(), 2));
        if (nowOrderPay.getPayActualTotal() == null) {
            nowOrderPay.setPayActualTotal(0.00);
        }
        nowOrderPay.setOnePrice(onePrice)
                .setRefund(refundParam.getPayActualTotal());
        return nowOrderPay;
    }

    @Override
    public OrderPayParam getActualTotalByHour(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotalByHour = orderMapper.getActualTotalByHour(shopId, startTime, endTime);
        Map<Integer, Double> payMap = new HashMap<>(30);
        for (OrderPayParam orderPay : actualTotalByHour) {
            payMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        List<OrderPayParam> yesterdayTotalByHour = orderMapper.getActualTotalByHour(shopId, DateUtil.beginOfDay(DateUtil.yesterday()),
                DateUtil.endOfDay(DateUtil.yesterday()));
        Map<Integer, Double> yesterdayPayMap = new HashMap<>(30);
        for (OrderPayParam orderPay : yesterdayTotalByHour) {
            yesterdayPayMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        double sum = 0.00;
        double yesterdaySum = 0.00;
        List<Double> payYesterdayActualTotal = new ArrayList<>();
        List<Double> nowActualTotal = new ArrayList<>();
        OrderPayParam param = new OrderPayParam();
        for (int i = 0; i < 24; i++) {
            if (payMap.get(i) != null) {
                sum = Arith.add(sum, payMap.get(i));
            }
            if (yesterdayPayMap.get(i) != null) {
                yesterdaySum = Arith.add(yesterdaySum, yesterdayPayMap.get(i));
            }
            payYesterdayActualTotal.add(Arith.round(yesterdaySum, 2));
            nowActualTotal.add(Arith.round(sum, 2));
        }
        param.setPayYesterdayActualTotal(payYesterdayActualTotal);
        param.setNowActualTotal(nowActualTotal);
        return param;
    }

    @Override
    public List<OrderPayParam> getActualTotalByDay(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotal = orderMapper.getPayOrderByTime(shopId, startTime, endTime);
        List<OrderPayParam> actualTotalByDay = new ArrayList<>();
        //获取本月起始时间
        DateTime dateTime = DateUtil.beginOfMonth(DateUtil.date());
        Double sum = 0.00;
        for (OrderPayParam orderPayParam : actualTotal) {
            DateTime time = DateTime.of(orderPayParam.getDates(), "yyyy-MM-dd");
            if (DateUtil.compare(time, dateTime) > 0) {
                sum = Arith.add(sum, orderPayParam.getPayActualTotal());
                orderPayParam.setOnePrice(Arith.round(sum, 2));
            }
            actualTotalByDay.add(orderPayParam);
        }
        return actualTotalByDay;
    }


    @Override
    public Order getOrderByOrderNumberAndShopId(String orderNumber, Long shopId, boolean valid) {
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber).eq(Order::getShopId, shopId));
        if (valid && order == null) {
            throw new GlobalException("订单不存在");
        }
        return order;
    }

    @Override
    @CachePut(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto putConfirmOrderCache(String userId, ShopCartOrderMergerDto shopCartOrderMergerDto) {
        return shopCartOrderMergerDto;
    }

    @Override
    @Cacheable(cacheNames = "ConfirmOrderCache", key = "#userId")
    public ShopCartOrderMergerDto getConfirmOrderCache(String userId) {
        return null;
    }

    @Override
    @CacheEvict(cacheNames = "ConfirmOrderCache", key = "#userId")
    public void removeConfirmOrderCache(String userId) {
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Order> submit(String userId, ShopCartOrderMergerDto mergerOrder) {

        Channel channel = channelService.getById(mergerOrder.getChannelId());
        if (channel == null) {
            throw new GlobalException("找不到该渠道");
        }

        List<Order> orderList = new ArrayList<>();
        // 提交订单
        eventPublisher.publishEvent(new SubmitOrderEvent(mergerOrder, orderList));
        List<Order> objects = new ArrayList<>();
        // 插入订单
        log.info("订单提交{}", orderList);
        for (Order c : orderList) {

            if (c.getDvyType().equals(1) && c.getHbOrderStatus() != 0) {
                c.setHbOrderStatus(1);
            }
            log.info("进入拆单处理 订单号：{}", c.getOrderNumber());

            //统计订单项总重量
            //TODO 拆单逻辑处理
//            if (c.getOrderItems().size() > 1) {
//                if (!c.getNextPay()) {
//                    cd(c, channel, objects);
//                }
                objects.add(c);
//            }
        }

        objects.sort(Comparator.comparingInt(order -> Optional.ofNullable(order.getOrderLevel()).orElse(0)));
        for (Order object : objects) {
            orderMapper.insert(object);
        }
        List<OrderItem> orderItems = objects.stream()
                .flatMap(order -> order.getOrderItems().stream()
                )
                .collect(Collectors.toList());
        // 插入订单项，返回主键
        orderItemService.saveBatch(orderItems);
        //计算积分情况
        if (mergerOrder.getIsScorePay() != null && mergerOrder.getIsScorePay() == 1) {
            eventPublisher.publishEvent(new SubmitScoreOrderEvent(mergerOrder, objects));
        }

        return objects;
    }


    /**
     * 自动拆单处理
     *
     * @param c
     * @param channel
     * @param objects
     */

    @Override
    public void cd(Order c, Channel channel, List<Order> objects) {
        //拆单处理
        c.setOrderLevel(0);
        c.setSplitStatus(1);
        c.setAutoSplit(1);
        if (channel.getAutoSplit() == 1 && channel.getSplitRule() == 1) {
            double sum = c.getOrderItems().stream().mapToDouble(OrderItem::getWeight).sum();
            Double weightLimit = channel.getSplitWeight() * 1000;
            if (sum > weightLimit) {
                c.setSplitStatus(4);
                log.info("===============进入自动拆单处理===============");
                // 自动拆单处理
                List<OrderItem> allItems = new ArrayList<>(c.getOrderItems());
                List<Order> subOrders = new ArrayList<>();

                // 1. 检查并处理超重单品（单件商品重量 > N kg）
                List<OrderItem> overweightItems = new ArrayList<>();
                List<OrderItem> normalItems = new ArrayList<>();

                for (OrderItem item : allItems) {
                    // 判断单个商品重量是否超重
                    if (item.getWeight() > weightLimit) {
                        overweightItems.add(item);
                    } else {
                        normalItems.add(item);
                    }
                }

                // 为每个超重单品按数量创建独立子订单（每个子订单只包含1个商品）
                for (OrderItem overweightItem : overweightItems) {
                    int prodCount = overweightItem.getProdCount();
                    // 按商品数量生成多个子订单，每个子订单只包含1个该商品
                    for (int i = 0; i < prodCount; i++) {
                        OrderItem singleItem = new OrderItem();
                        BeanUtils.copyProperties(overweightItem, singleItem);
                        singleItem.setProdCount(1); // 每个子订单只包含1个商品
                        singleItem.setOrderItemId(null);

                        Order subOrder = createSubOrder(c, Collections.singletonList(singleItem), 1);
                        subOrders.add(subOrder);
                    }
                }

                log.info("对正常商品进行贪心算法拆分（按重量从大到小排序）");
                // 2. 对正常商品进行贪心算法拆分（按单个商品重量从大到小排序）
                if (!normalItems.isEmpty()) {
                    // 将商品按数量展开为单个商品列表（每个商品拆分为多个数量为1的商品）
                    List<OrderItem> expandedItems = new ArrayList<>();
                    for (OrderItem item : normalItems) {
                        for (int i = 0; i < item.getProdCount(); i++) {
                            OrderItem singleItem = new OrderItem();
                            BeanUtils.copyProperties(item, singleItem);
                            singleItem.setProdCount(1); // 每个展开的商品数量为1
                            singleItem.setOrderItemId(null);
                            expandedItems.add(singleItem);
                        }
                    }

                    // 使用装箱算法工具类进行装箱
                    List<List<OrderItem>> subOrderItemGroups = BinPackingUtil.firstFitDecreasing(
                            expandedItems,
                            OrderItem::getWeight,
                            weightLimit
                    );

                    // 为每组创建子订单（非超重），并合并相同SKU的商品
                    for (List<OrderItem> itemGroup : subOrderItemGroups) {
                        // 合并相同SKU的商品（将数量为1的相同商品合并）
                        List<OrderItem> mergedItems = mergeSameSkuItems(itemGroup);
                        Order subOrder = createSubOrder(c, mergedItems, 0);
                        subOrders.add(subOrder);
                    }
                }
                log.info("按重量从大到小排序{}", subOrders);
                // 3. 分配积分和金额（先积分后金额）
                allocatePointsAndAmount(c, subOrders);
                log.info("分配积分和金额{}", subOrders);
                // 4. 分配运费（平均分配，向下取整，余额放第一个子订单）
                allocateFreight(c, subOrders);
                log.info("分配运费{}", subOrders);
                // 5. 设置子订单编号
                for (int i = 0; i < subOrders.size(); i++) {
                    Order subOrder = subOrders.get(i);
                    subOrder.setOrderSplitNumber(i + 1);
                    subOrder.setParentOrderNumber(c.getOrderNumber());
                    subOrder.setOrderLevel(1);
                    subOrder.setSplitStatus(1);
                    subOrder.setAutoSplit(1);

                    // 更新子订单的订单项orderNumber
                    for (OrderItem item : subOrder.getOrderItems()) {
                        item.setOrderNumber(subOrder.getOrderNumber());
                    }
                }
                log.info("将子订单添加到订单列表{}", subOrders);
                // 将子订单添加到订单列表
                objects.addAll(subOrders);
            }
        } else {
            c.setSplitStatus(2);
            c.setAutoSplit(0);
        }
    }

    /**
     * 创建子订单
     *
     * @param parentOrder    父订单
     * @param items          订单项列表
     * @param overweightFlag 超重标记 (1-超重, 0-正常)
     * @return 子订单
     */
    private Order createSubOrder(Order parentOrder, List<OrderItem> items, int overweightFlag) {
        Order subOrder = new Order();

        // 复制父订单属性
        BeanUtils.copyProperties(parentOrder, subOrder);

        // 清除父订单的ID和订单号，生成新的
        subOrder.setOrderId(null);
        subOrder.setOrderNumber("D" + snowflake.nextId( ));

        // 设置超重标记
        subOrder.setOrderSplitStatus(overweightFlag);

        // 复制订单项（深拷贝）
        List<OrderItem> subOrderItems = new ArrayList<>();
        for (OrderItem item : items) {
            OrderItem newItem = new OrderItem();
            BeanUtils.copyProperties(item, newItem);
            newItem.setOrderItemId(null); // 清除ID，让数据库自动生成
            subOrderItems.add(newItem);
        }
        subOrder.setOrderItems(subOrderItems);

        // 计算商品总数量
        int totalNums = items.stream().mapToInt(OrderItem::getProdCount).sum();
        subOrder.setProductNums(totalNums);

        return subOrder;
    }

    /**
     * 合并相同SKU的商品（将数量为1的相同商品合并为一个订单项）
     *
     * @param items 商品列表（每个商品数量为1）
     * @return 合并后的商品列表
     */
    private List<OrderItem> mergeSameSkuItems(List<OrderItem> items) {
        if (items == null || items.isEmpty()) {
            return items;
        }

        // 使用Map按skuId分组
        Map<Long, List<OrderItem>> skuMap = new HashMap<>();
        for (OrderItem item : items) {
            skuMap.computeIfAbsent(item.getSkuId(), k -> new ArrayList<>()).add(item);
        }

        // 合并相同SKU的商品
        List<OrderItem> mergedItems = new ArrayList<>();
        for (Map.Entry<Long, List<OrderItem>> entry : skuMap.entrySet()) {
            List<OrderItem> sameSkuItems = entry.getValue();
            if (sameSkuItems.size() == 1) {
                // 只有一个，直接添加
                mergedItems.add(sameSkuItems.get(0));
            } else {
                // 有多个，合并数量
                OrderItem mergedItem = new OrderItem();
                BeanUtils.copyProperties(sameSkuItems.get(0), mergedItem);

                // 计算总数量
                int totalCount = sameSkuItems.stream().mapToInt(OrderItem::getProdCount).sum();
                mergedItem.setProdCount(totalCount);
                mergedItem.setOrderItemId(null);

                mergedItems.add(mergedItem);
            }
        }

        return mergedItems;
    }

    /**
     * 分配积分和金额（按照1:100的比例处理积分和金额）
     * 先分配积分，后分配金额
     *
     * @param parentOrder 父订单
     * @param subOrders   子订单列表
     */
    private void allocatePointsAndAmount(Order parentOrder, List<Order> subOrders) {
        if (subOrders == null || subOrders.isEmpty()) {
            return;
        }

        // 父订单的总积分和总金额
        Long parentOffsetPoints = parentOrder.getOffsetPoints() != null ? parentOrder.getOffsetPoints() : 0L;
        double parentTotal = parentOrder.getTotal() != null ? parentOrder.getTotal() : 0.0;

        // 计算父订单所有订单项的actualTotal总和
//        double parentActualTotalFromItems = 0.0;
//        for (OrderItem item : parentOrder.getOrderItems()) {
//            parentActualTotalFromItems += (item.getActualTotal() != null ? item.getActualTotal() : 0.0);
//        }

        // 计算每个子订单的商品总金额和actualTotal
        List<Double> subOrderProductAmounts = new ArrayList<>();
        List<Double> subOrderActualTotals = new ArrayList<>();
        double totalProductAmount = 0.0;

        for (Order subOrder : subOrders) {
            double subProductAmount = 0.0;
            double subActualTotal = 0.0;

            for (OrderItem item : subOrder.getOrderItems()) {
                // 商品总金额 = 单价 * 数量
                subProductAmount += item.getPrice() * item.getProdCount();

                // 从父订单中找到对应的订单项，获取其actualTotal
                for (OrderItem parentItem : parentOrder.getOrderItems()) {
                    if (parentItem.getSkuId().equals(item.getSkuId())) {
                        // 按比例分配actualTotal
                        double itemActualTotal = parentItem.getActualTotal() != null ? parentItem.getActualTotal() : 0.0;
                        if (parentItem.getProdCount() > 0) {
                            // 子订单项的actualTotal = 父订单项的actualTotal * (子订单项数量 / 父订单项数量)
                            subActualTotal += (itemActualTotal / parentItem.getProdCount()) * item.getProdCount();
                        }
                        break;
                    }
                }
            }

            subOrderProductAmounts.add(subProductAmount);
            subOrderActualTotals.add(subActualTotal);
            totalProductAmount += subProductAmount;
        }

        // 1. 先分配积分（按商品金额比例）
        long remainingPoints = parentOffsetPoints;
        for (int i = 0; i < subOrders.size(); i++) {
            Order subOrder = subOrders.get(i);
            long subPoints;

            if (i == subOrders.size() - 1) {
                // 最后一个子订单分配剩余积分
                subPoints = remainingPoints;
            } else {
                // 按比例分配积分：子订单积分 = 父订单总积分 * (子订单商品金额 / 父订单商品总金额)
                if (totalProductAmount > 0) {
                    double ratio = subOrderProductAmounts.get(i) / totalProductAmount;
                    subPoints = Math.round(parentOffsetPoints * ratio);
                } else {
                    subPoints = 0L;
                }
                remainingPoints -= subPoints;
            }

            subOrder.setOffsetPoints(subPoints);

            // 为子订单的每个订单项分配积分
            allocatePointsToItems(subOrder, subPoints);
        }

        // 2. 后分配金额（total和actualTotal）
        BigDecimal remainingTotal = BigDecimal.valueOf(parentTotal);
//        BigDecimal remainingActualTotal = BigDecimal.valueOf(parentActualTotalFromItems);

        for (int i = 0; i < subOrders.size(); i++) {
            Order subOrder = subOrders.get(i);
            BigDecimal subTotal;

            if (i == subOrders.size() - 1) {
                // 最后一个子订单分配剩余金额
                subTotal = remainingTotal;
            } else {
                // 按比例分配金额
                if (totalProductAmount > 0) {
                    double ratio = subOrderProductAmounts.get(i) / totalProductAmount;
                    // total金额分配（保留2位小数）
                    subTotal = BigDecimal.valueOf(parentTotal)
                            .multiply(BigDecimal.valueOf(ratio))
                            .setScale(2, BigDecimal.ROUND_DOWN);
                } else {
                    subTotal = BigDecimal.ZERO;
                }
                remainingTotal = remainingTotal.subtract(subTotal);
            }

            subOrder.setTotal(subTotal.doubleValue());

            // 为子订单的每个订单项分配金额（基于父订单项的actualTotal）
            allocateActualTotalToItems(subOrder, parentOrder);

            // 统计子订单的actualTotal（从订单项汇总）
            double orderActualTotal = 0.0;
            for (OrderItem item : subOrder.getOrderItems()) {
                orderActualTotal += (item.getActualTotal() != null ? item.getActualTotal() : 0.0);
            }
            subOrder.setActualTotal(orderActualTotal);
        }

        // 更新父订单项的已拆单数量
        updateParentOrderItemSplitCount(parentOrder, subOrders);
    }

    /**
     * 为子订单的订单项分配积分
     */
    private void allocatePointsToItems(Order subOrder, long totalPoints) {
        List<OrderItem> items = subOrder.getOrderItems();
        if (items == null || items.isEmpty()) {
            return;
        }

        // 计算总金额
        double totalAmount = 0.0;
        for (OrderItem item : items) {
            totalAmount += item.getPrice() * item.getProdCount();
        }

        long remainingPoints = totalPoints;
        for (int i = 0; i < items.size(); i++) {
            OrderItem item = items.get(i);
            int itemPoints;

            if (i == items.size() - 1) {
                // 最后一个订单项分配剩余积分
                itemPoints = (int) remainingPoints;
            } else {
                // 按比例分配
                if (totalAmount > 0) {
                    double itemAmount = item.getPrice() * item.getProdCount();
                    double ratio = itemAmount / totalAmount;
                    itemPoints = (int) Math.round(totalPoints * ratio);
                } else {
                    itemPoints = 0;
                }
                remainingPoints -= itemPoints;
            }

            item.setUseScore(itemPoints);
        }
    }

    /**
     * 为子订单的订单项分配金额（基于total）
     */
    private void allocateAmountToItems(Order subOrder) {
        List<OrderItem> items = subOrder.getOrderItems();
        if (items == null || items.isEmpty()) {
            return;
        }

        double subOrderTotal = subOrder.getTotal();

        // 计算订单项的原始总金额
        double originalTotalAmount = 0.0;
        for (OrderItem item : items) {
            double itemAmount = item.getPrice() * item.getProdCount();
            originalTotalAmount += itemAmount;
        }

        for (OrderItem item : items) {
            double itemProductAmount = item.getPrice() * item.getProdCount();
            item.setProductTotalAmount(itemProductAmount);
        }
    }

    /**
     * 为子订单的订单项分配actualTotal（基于父订单项的actualTotal）
     */
    private void allocateActualTotalToItems(Order subOrder, Order parentOrder) {
        List<OrderItem> subItems = subOrder.getOrderItems();
        if (subItems == null || subItems.isEmpty()) {
            return;
        }

        for (OrderItem subItem : subItems) {
            // 从父订单中找到对应的订单项
            for (OrderItem parentItem : parentOrder.getOrderItems()) {
                if (parentItem.getSkuId().equals(subItem.getSkuId())) {
                    double parentActualTotal = parentItem.getActualTotal() != null ? parentItem.getActualTotal() : 0.0;

                    if (parentActualTotal == 0.0) {
                        // 如果父订单项的actualTotal为0，子订单项也应该为0
                        subItem.setActualTotal(0.0);
                    } else if (parentItem.getProdCount() > 0) {
                        // 子订单项的actualTotal = 父订单项的actualTotal * (子订单项数量 / 父订单项数量)
                        double ratio = (double) subItem.getProdCount() / parentItem.getProdCount();
                        BigDecimal itemActualTotal = BigDecimal.valueOf(parentActualTotal)
                                .multiply(BigDecimal.valueOf(ratio))
                                .setScale(2, BigDecimal.ROUND_DOWN);
                        subItem.setActualTotal(itemActualTotal.doubleValue());
                    } else {
                        subItem.setActualTotal(0.0);
                    }

                    // 设置商品总金额
                    double itemProductAmount = subItem.getPrice() * subItem.getProdCount();
                    subItem.setProductTotalAmount(itemProductAmount);
                    break;
                }
            }
        }
    }

    /**
     * 更新父订单项的已拆单数量
     */
    private void updateParentOrderItemSplitCount(Order parentOrder, List<Order> subOrders) {
        for (OrderItem parentItem : parentOrder.getOrderItems()) {
            int totalSplitCount = 0;

            // 统计该商品在所有子订单中的数量
            for (Order subOrder : subOrders) {
                for (OrderItem subItem : subOrder.getOrderItems()) {
                    if (subItem.getSkuId().equals(parentItem.getSkuId())) {
                        totalSplitCount += subItem.getProdCount();
                    }
                }
            }

            // 更新父订单项的已拆单数量
            parentItem.setSplitCount(totalSplitCount);
        }
    }

    /**
     * 分配运费（平均分配，保留两位小数，向下取整）
     * 余额自动添加到第一个子订单
     *
     * @param parentOrder 父订单
     * @param subOrders   子订单列表
     */
    private void allocateFreight(Order parentOrder, List<Order> subOrders) {
        if (subOrders == null || subOrders.isEmpty()) {
            return;
        }

        double parentFreight = parentOrder.getFreightAmount() != null ? parentOrder.getFreightAmount() : 0.0;

        if (parentFreight <= 0) {
            // 如果没有运费，所有子订单运费都设为0
            for (Order subOrder : subOrders) {
                subOrder.setFreightAmount(0.0);
            }
            return;
        }

        int subOrderCount = subOrders.size();

        // 使用BigDecimal确保精度
        BigDecimal totalFreight = BigDecimal.valueOf(parentFreight);
        BigDecimal avgFreight = totalFreight.divide(BigDecimal.valueOf(subOrderCount), 2, BigDecimal.ROUND_DOWN);

        // 计算分配后的总和
        BigDecimal allocatedTotal = avgFreight.multiply(BigDecimal.valueOf(subOrderCount));

        // 计算余额
        BigDecimal remainder = totalFreight.subtract(allocatedTotal);

        // 为每个子订单分配运费
        for (int i = 0; i < subOrders.size(); i++) {
            Order subOrder = subOrders.get(i);
            BigDecimal freight;

            if (i == 0) {
                // 第一个子订单 = 平均运费 + 余额
                freight = avgFreight.add(remainder);
            } else {
                // 其他子订单 = 平均运费
                freight = avgFreight;
            }

            subOrder.setFreightAmount(freight.doubleValue());

            // 更新actualTotal（加上运费）
//            BigDecimal currentActualTotal = BigDecimal.valueOf(subOrder.getActualTotal() != null ? subOrder.getActualTotal() : 0.0);
//            BigDecimal newActualTotal = currentActualTotal.add(freight).setScale(2, BigDecimal.ROUND_HALF_UP);
//            subOrder.setActualTotal(newActualTotal.doubleValue());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delivery(Order order) {
        orderMapper.updateById(order);
        // 发送用户发货通知
        Map<String, String> params = new HashMap<>(16);
        params.put("orderNumber", order.getOrderNumber());
//		Delivery delivery = deliveryMapper.selectById(order.getDvyId());
//		params.put("dvyName", delivery.getDvyName());
//		params.put("dvyFlowId", order.getDvyFlowId());
//		smsLogService.sendSms(SmsType.NOTIFY_DVY, order.getUserId(), order.getMobile(), params);

    }

    @Override
    public List<Order> listUnRefundOrderAndOrderItems(Integer orderStatus, DateTime lessThanUpdateTime) {
        return orderMapper.listUnRefundOrderAndOrderItems(orderStatus, lessThanUpdateTime);
    }

    @Override
    public List<Order> selectCancelOrders(Integer orderStatus, DateTime lessThanUpdateTime) {
        return orderMapper.selectCancelOrders(orderStatus, lessThanUpdateTime);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrders(List<Order> orders, String cancelReason) {
        if (CollectionUtil.isEmpty(orders)) {
            return;
        }
        orderMapper.cancelOrders(orders, cancelReason);
        List<OrderItem> allOrderItems = new ArrayList<>();
        for (Order order : orders) {
            List<OrderItem> orderItems = order.getOrderItems();
            allOrderItems.addAll(orderItems);
            eventPublisher.publishEvent(new CancelOrderEvent(order));
            // 判定是不是积分订单，如果是或者包含积分则退积分
            if (Objects.equals(OrderType.SCORE.value(), order.getOrderType())) {
                List<PointsRecord> pointsRecords = pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
                        .eq(PointsRecord::getOrderNumber, order.getOrderNumber())
                        .eq(PointsRecord::getPointsType, 2)//购物的积分
                        .and(wrapper -> wrapper
                                .gt(PointsRecord::getExpiryDate, LocalDateTime.now())
                                .or()
                                .isNull(PointsRecord::getExpiryDate)
                        ));
                for (PointsRecord pointsRecord : pointsRecords) {
                    Long l = pointsRecordMapper.statisticsPoint(pointsRecord.getUserId(), pointsRecord.getChannelId());
                    pointsRecord.setId(null);
                    pointsRecord.setCreationDate(new Date());
                    pointsRecord.setPoints(pointsRecord.getVariablePoints());
                    pointsRecord.setVariablePoints(BigDecimal.valueOf(0));
                    pointsRecord.setPointsType(3);
                    pointsRecord.setPointsAudit(1);
                    pointsRecord.setCurrentlyAvailablePoints(BigDecimal.valueOf(null != l ? l : 0).add(pointsRecord.getPoints()));
                    pointsRecordMapper.insert(pointsRecord);
                }
            }
        }
        // 如果是秒杀订单也不必还原库存
        if (CollectionUtil.isEmpty(allOrderItems) || OrderType.SECKILL.value().equals(orders.get(0).getOrderType())) {
            return;
        }
        Map<Long, Integer> prodCollect = new HashMap<>(16);
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getProdId)).forEach((prodId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            prodCollect.put(prodId, prodTotalNum);
        });
        productMapper.returnStock(prodCollect);

        Map<Long, Integer> skuCollect = new HashMap<>(16);
        allOrderItems.stream().collect(Collectors.groupingBy(OrderItem::getSkuId)).forEach((skuId, orderItems) -> {
            int prodTotalNum = orderItems.stream().mapToInt(OrderItem::getProdCount).sum();
            skuCollect.put(skuId, prodTotalNum);
        });
        skuMapper.returnStock(skuCollect);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void receiptOrder(List<Order> orders) {
        orderMapper.cancelOrders(orders, "用户主动取消");
        for (Order order : orders) {
            eventPublisher.publishEvent(new ReceiptOrderEvent(order));
        }

    }


    @Override
    public IPage<Order> pageOrdersDetialByOrderParam(Page<Order> page, OrderParam orderParam) {
        page.setRecords(orderMapper.listOrdersDetialByOrderParam(new PageAdapter(page), orderParam));
        page.setTotal(orderMapper.countOrderDetial(orderParam));
        return page;
    }

    @Override
    public IPage<Order> deliverList(PageParam<Order> page, BackendOrderParam orderParam) {
        IPage<Order> iPage = orderMapper.deliverList(page, orderParam);
        if (!ObjectUtil.isEmpty(iPage.getRecords())) {
            iPage.getRecords().forEach(c -> {
                List<OrderItem> orderItems = orderItemMapper.getListByOrderNumber(c.getOrderNumber());
                c.setOrderItems(orderItems);
                c.setGoodsTotalCount(orderItems.stream().map(OrderItem::getProdCount).reduce(0, Integer::sum));
            });
        }
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrders(List<Order> orders) {
        orderMapper.deleteOrders(orders);
    }

    @Override
    public OrderCountData getOrderCount(String userId) {
        // 获取普通订单数据
        OrderCountData countData = orderMapper.getOrderCount(userId);
        // 获取退款订单数据
        countData.setRefund(orderRefundMapper.getRefundCount(userId));
        return countData;
    }

    @Override
    public double sumTotalDistributionAmountByOrderItem(List<OrderItem> orderItems) {
        // 订单总分销金额
        double totalDistributionAmount = 0.0;
        if (CollectionUtil.isNotEmpty(orderItems)) {
            for (OrderItem orderItem : orderItems) {
                if (StrUtil.isBlank(orderItem.getDistributionCardNo())) {
                    continue;
                }
                // 如果改订单项已经退款了的话，分销员的佣金就已经回退了，不需要继续算钱
                if (Objects.equals(orderItem.getReturnMoneySts(), ReturnMoneyStsType.SUCCESS.value())) {
                    continue;
                }
                // 分销佣金
                if (orderItem.getDistributionAmount() != null && orderItem.getDistributionAmount() > 0) {
                    totalDistributionAmount = Arith.add(totalDistributionAmount, orderItem.getDistributionAmount());
                }
                // 上级分销佣金
                if (orderItem.getDistributionParentAmount() != null && orderItem.getDistributionParentAmount() > 0) {
                    totalDistributionAmount = Arith.add(totalDistributionAmount, orderItem.getDistributionParentAmount());
                }
            }
        }
        return totalDistributionAmount;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeAmount(Order order) {
        Order orderDb = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderId, order.getOrderId())
                .eq(Order::getOrderNumber, order.getOrderNumber())
        );
        if (!Objects.equals(orderDb.getHbOrderStatus(), OrderStatus.UNPAY.value())) {
            throw new GlobalException("订单状态异常，无法更改订单金额");
        }
        //减少金额
        double amount = 0.00;
        //平台优惠金额
        double platformAmount = 0.00;
        Map<Long, OrderItem> collect = order.getOrderItems().stream().collect(Collectors.toMap(OrderItem::getOrderItemId, orderItem -> orderItem));
        List<OrderItem> orderItemList = orderItemService.list(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
        for (OrderItem orderItemDb : orderItemList) {
            OrderItem orderItem = collect.get(orderItemDb.getOrderItemId());
            if (orderItem.getChageAmount() >= orderItemDb.getActualTotal() || orderItem.getChageAmount() < 0) {
                throw new GlobalException("订单金额必须大于0，或者数据发生变化(请刷新后重试)");
            }
            if (Objects.isNull(orderItem.getChageAmount()) || Objects.equals(orderItem.getChageAmount(), 0.00)) {
                continue;
            }
            //修改平台优惠金额
            double playformItemAmount = 0.00;
            if (orderItemDb.getPlatformShareReduce() > 0) {
                //金额减少比例 = 减少金额  % 总金额
                double proportion = Arith.div(orderItem.getChageAmount(), orderItemDb.getProductTotalAmount(), 6);
                //平台优惠金额减少金额 = 减少比例 * 原平台优惠金额
                playformItemAmount = Arith.round(Arith.mul(proportion, orderItemDb.getPlatformShareReduce()), 2);
                //平台优惠金额 = 原平台优惠金额 - 对应比例的金额
                orderItemDb.setPlatformShareReduce(Arith.sub(orderItemDb.getPlatformShareReduce(), playformItemAmount));
            }
            //实际金额 = 原实际金额 - 变化金额
            orderItemDb.setActualTotal(Arith.sub(orderItemDb.getActualTotal(), orderItem.getChageAmount()));
            //总优惠金额 = 变化金额 + 原总优惠金额
            orderItemDb.setShareReduce(Arith.add(orderItem.getChageAmount(), orderItemDb.getShareReduce()));

            amount = Arith.add(amount, orderItem.getChageAmount());
            platformAmount = Arith.add(platformAmount, playformItemAmount);
        }
        orderItemService.updateBatchById(orderItemList);
        OrderSettlement orderSettlement = orderSettlementService.getOne(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getOrderNumber, order.getOrderNumber()));
        //修改订单信息
        orderDb.setActualTotal(Arith.sub(orderDb.getActualTotal(), amount));
        orderDb.setReduceAmount(Arith.add(orderDb.getReduceAmount(), amount));
        orderDb.setPlatformAmount(Arith.sub(orderDb.getPlatformAmount(), platformAmount));
        //初始化
        amount = 0.00;
        // 计算运费变化金额
        if (!Objects.equals(orderDb.getFreightAmount(), order.getFreightAmount())) {
            amount = Arith.add(amount, Arith.sub(order.getFreightAmount(), orderDb.getFreightAmount()));
        }
        orderDb.setActualTotal(Arith.add(orderDb.getActualTotal(), amount));
        orderSettlement.setPayAmount(orderDb.getActualTotal());
        orderSettlementService.updateById(orderSettlement);
        //修改运费信息
        orderDb.setFreightAmount(order.getFreightAmount());
        orderMapper.updateById(orderDb);
    }

    @Override
    public void soldExcel(OrderParam orderParam, HttpServletResponse response) {
        List<Order> orders = orderMapper.listOrdersDetialByOrderInfo(orderParam);

        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter();
        // 待发货
        String[] hearder = {"订单编号", "下单时间", "收件人", "手机", "收货地址", "商品名称", "数量", "订单应付", "订单运费", "订单实付", "订单状态", "售后状态"};
        Sheet sheet = writer.getSheet();
        sheet.setColumnWidth(0, 20 * 256);
        sheet.setColumnWidth(1, 20 * 256);
        sheet.setColumnWidth(3, 20 * 256);
        sheet.setColumnWidth(4, 60 * 256);
        sheet.setColumnWidth(5, 60 * 256);

        writer.merge(hearder.length - 1, "销售信息整理");
        writer.writeRow(Arrays.asList(hearder));

        int row = 1;
        for (Order dbOrder : orders) {
            UserAddrOrder addr = dbOrder.getUserAddrOrder();
            String addrInfo = addr.getProvince() + addr.getCity() + addr.getArea() + addr.getAddr();
            List<OrderItem> orderItems = dbOrder.getOrderItems();
            int firstRow = row + 1;
            int lastRow = row + orderItems.size();
            int col = -1;
            // 订单编号
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, dbOrder.getOrderNumber());

            // 下单时间
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, dbOrder.getCreateTime());
            // 收件人
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, addr.getReceiver());
            // "手机"
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, addr.getMobile());
            addrInfo = (StringUtils.isEmpty(addr.getAddress()) ? "" : addr.getAddress()) + (StringUtils.isEmpty(addr.getAddressName()) ? "" : addr.getAddressName()) + (StringUtils.isEmpty(addr.getAddrDetail()) ? "" : addr.getAddrDetail());
            // "收货地址"
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, addrInfo);
            int prodNameCol = ++col;
            int prodCountCol = ++col;
            for (OrderItem orderItem : orderItems) {
                row++;
                // 商品名称
                writer.writeCellValue(prodNameCol, row, orderItem.getProdName());
                // 数量
                writer.writeCellValue(prodCountCol, row, orderItem.getProdCount());
            }
            // 订单应付
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, dbOrder.getTotal());
            // 订单运费
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, dbOrder.getFreightAmount());
            // 订单实付
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, dbOrder.getActualTotal());
            //订单状态
            String[] statusValue = {"", "待付款", "待发货", "待收货", "待评价", "成功", "失败", "待成团", ""};
            String status = statusValue[dbOrder.getHbOrderStatus()];

            String refundStatus = "";
            String[] refundStatusValue = {"", "申请退款", "退款成功", "退款成功", "退款失败"};
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, status);
            if (!Objects.isNull(dbOrder.getRefundStatus())) {
                refundStatus = refundStatusValue[dbOrder.getRefundStatus()];
            } else {
                refundStatus = "暂无售后";
            }
            mergeIfNeed(writer, firstRow, lastRow, ++col, col, refundStatus);
        }
        writeExcel(response, writer);
    }

    @Override
    public List<Order> getOrderPayInfoByOrderNumber(List<String> orderNumberList) {
        return orderMapper.getOrderPayInfoByOrderNumber(orderNumberList);
    }

    @Override
    public Order getOrderDetailByOrderNumberAndShopId(String orderNumber, Long shopId) {
        return orderMapper.getOrderDetailByOrderNumberAndShopId(orderNumber, shopId);
    }

    @Override
    public Map<Long, Integer> getOrderItemMap(Long orderId) {
        List<OrderRefund> orderRefunds = orderRefundMapper.selectList(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderId, orderId)
                .lt(OrderRefund::getReturnMoneySts, 6)
                .gt(OrderRefund::getReturnMoneySts, 0)
        );
        Map<Long, Integer> map = Maps.newHashMap();

        for (OrderRefund orderRefund : orderRefunds) {
            if (orderRefund.getRefundType() == 1) {
                map.put(0L, orderRefund.getReturnMoneySts());
                return map;
            }
            map.put(orderRefund.getOrderItemId(), orderRefund.getReturnMoneySts());
        }
        return map;
    }

    @Override
    public String cancelOrder(CancelOrderParam cancelOrderParam) {
        com.yami.shop.bean.app.param.OrderRefundParam orderRefundParam = new com.yami.shop.bean.app.param.OrderRefundParam();
        orderRefundParam.setOrderNumber(cancelOrderParam.getOrderNumber());
        orderRefundParam.setRefundType(cancelOrderParam.getRefundType());
        orderRefundParam.setApplyType(cancelOrderParam.getApplyType());
        orderRefundParam.setIsReceiver(cancelOrderParam.getIsReceiver());
        orderRefundParam.setBuyerReason("商家主动取消订单");
        orderRefundParam.setBuyerDesc("商家后台取消订单");

//        String userId = SecurityUtils.getUser().getUserId();
        // 获取订单信息
//        Order order = orderService.getOrderByOrderNumberAndUserId(orderRefundParam.getOrderNumber(), userId, true);
        Order order = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderRefundParam.getOrderNumber()));
        if (!Objects.equals(order.getIsPayed(), 1)) {
            throw new GlobalException("当前订单还未付款，无法取消");
        }
        orderRefundParam.setBuyerMobile(order.getUserMobile());
        orderRefundParam.setRefundAmount(order.getTotal());
        if (Objects.equals(order.getHbOrderStatus(), OrderStatus.CLOSE.value())) {
            throw new GlobalException("当前订单已失败");
        }

        if (Objects.equals(order.getHbOrderStatus(), OrderStatus.WAIT_GROUP.value())) {
            throw new GlobalException("当前订单正在等待成团状态，需等待成团才能进行下一步操作");
        }


//        if (!Objects.equals(orderRefundParam.getRefundType(),RefundType.ALL.value()) && Objects.equals(order.getStatus(),OrderStatus.PADYED.value())) {
//            throw new GlobalException("未发货订单仅支持整单退款");
//        }
//        // 代发货整单退款不可以输入金额，为固定全额退款
//        if (Objects.equals(orderRefundParam.getRefundType(),RefundType.ALL.value()) && Objects.equals(order.getStatus(),OrderStatus.PADYED.value())) {
//            orderRefundParam.setRefundAmount(order.getActualTotal());
//        }

//        if (orderRefundParam.getRefundAmount() > order.getActualTotal()) {
//            throw new GlobalException("退款金额已超出订单金额，无法申请");
//        }

        //待收货 -> 整单退款 -> 退款金额 < 订单金额 - 运费金额
        if (Objects.equals(order.getHbOrderStatus(), OrderStatus.CONSIGNMENT.value()) && orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            Double refundAmount = Arith.sub(order.getActualTotal(), order.getFreightAmount());
            if (orderRefundParam.getRefundAmount() > refundAmount) {
                throw new GlobalException("退款金额已超出订单金额，无法申请");
            }
        }

        if (!checkRefundDate(order)) {
            throw new GlobalException("当前订单已确认收货超过" + Constant.MAX_FINALLY_REFUND_TIME + "天，无法退款");
        }
        if (Objects.equals(order.getOrderType(), Constant.ORDER_TYPE_SCORE)) {
            throw new GlobalException("积分商品，无法退款");
        }
        if (Objects.equals(orderRefundParam.getRefundType(), RefundType.ALL.value()) && (!Objects.isNull(order.getRefundStatus()) && !Objects.equals(order.getRefundStatus(), RefundStatusEnum.DISAGREE.value()))) {
            throw new GlobalException("77该订单已有商品正在退款中，不能再进行整单退款");
        }
        // 生成退款单信息
        OrderRefund newOrderRefund = new OrderRefund();

        // 获取所有正在进行中的退款订单
        List<OrderRefund> orderRefunds = orderRefundMapper.getProcessingOrderRefundByOrderId(order.getOrderId());

        for (OrderRefund orderRefund : orderRefunds) {
            if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
                throw new GlobalException("该订单正在进行整单退款，无法进行新的退款操作");
            }
            if (Objects.equals(orderRefund.getOrderItemId(), orderRefundParam.getOrderItemId())) {
                throw new GlobalException("该商品正在进行退款中，无法进行新的退款操作");
            }
        }

        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.getOrderItemsByOrderNumber(order.getOrderNumber());
        // 判断退款单类型（1:整单退款,2:单个物品退款）
        if (orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            // 全部物品退款
            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(this.sumTotalDistributionAmountByOrderItem(orderItemList));
            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            newOrderRefund.setPlatformRefundAmount(order.getPlatformAmount());
        } else {
            // 部分物品退款
            OrderItem orderItem = orderItemService.getOne(new LambdaQueryWrapper<OrderItem>()
                    .eq(OrderItem::getOrderItemId, orderRefundParam.getOrderItemId())
                    .eq(OrderItem::getOrderNumber, orderRefundParam.getOrderNumber()));
            if (orderItem == null) {
                throw new GlobalException("该物品在订单中不存在");
            }
            boolean isCanRefund = false;
            //  查看是否有支付金额和积分都为空的订单，有则抛出异常
            for (OrderItem item : orderItemList) {
                if (item.getActualTotal() <= 0.0 && item.getUseScore() <= 0.0) {
                    isCanRefund = true;
                    break;
                }
            }
            if (isCanRefund) {
                throw new GlobalException("该订单部分订单项支付金额和积分为0，无法使用部分退款！");
            }

            if (order.getPlatformAmount() > 0 && !Arith.isEquals(orderRefundParam.getRefundAmount(), orderItem.getActualTotal())) {
                throw new GlobalException("该订单有使用平台优惠，无法使用部分退款！");
            }
            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(this.sumTotalDistributionAmountByOrderItem(Collections.singletonList(orderItem)));

            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            //此处设置实际平台抵现金额
            newOrderRefund.setPlatformRefundAmount(orderItem.getPlatformShareReduce());

            // 退款物品数量为null或者0时，则为退款全部数量
            if (orderRefundParam.getGoodsNum() <= 0) {
                orderRefundParam.setGoodsNum(orderItem.getProdCount());
            }

            // 判断退款数量是否溢出
            if (orderRefundParam.getGoodsNum() > orderItem.getProdCount()) {
                throw new GlobalException("退款物品数量已超出订单中的数量，不允许申请");
            }

            // 判断退款金额是否超出订单金额
            double refundSingleAmount = Arith.div(orderRefundParam.getRefundAmount(), orderRefundParam.getGoodsNum(), 3);
            double singleAmount = Arith.div(orderItem.getActualTotal(), orderItem.getProdCount(), 3);
            if (refundSingleAmount > orderItem.getProductTotalAmount() || refundSingleAmount > singleAmount) {
                throw new GlobalException("退款金额已超出订单金额，无法申请");
            }

            // 一个订单项只能申请一次退款
            for (OrderRefund orderRefund : orderRefunds) {
                if (Objects.equals(orderRefund.getOrderId(), orderItem.getOrderItemId())) {
                    throw new GlobalException("退款订单项已处理，请勿重复申请");
                }
            }
        }

        newOrderRefund.setShopId(order.getShopId());
        newOrderRefund.setUserId(order.getUserId());
        newOrderRefund.setOrderId(order.getOrderId());
        newOrderRefund.setRefundSn(String.valueOf(snowflake.nextId()));
        newOrderRefund.setRefundType(orderRefundParam.getRefundType());

        newOrderRefund.setRefundAmount(orderRefundParam.getRefundAmount());
        if (Objects.equals(RefundType.ALL.value(), orderRefundParam.getRefundType())) {
            newOrderRefund.setOrderItemId(0L);
        } else {
            newOrderRefund.setOrderItemId(orderRefundParam.getOrderItemId());
            // 待发货状态-最后一件商品进行退款，退款金额 =  商品金额 + 订单运费金额
            if (Objects.equals(order.getHbOrderStatus(), OrderStatus.PADYED.value()) && order.getFreightAmount() > 0) {
                int orderItenCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
                if (Objects.equals(orderRefunds.size(), orderItenCount - 1)) {
                    newOrderRefund.setRefundAmount(Arith.add(newOrderRefund.getRefundAmount(), order.getFreightAmount()));
                }
            }
        }
        newOrderRefund.setGoodsNum(orderRefundParam.getGoodsNum());
        newOrderRefund.setApplyType(orderRefundParam.getApplyType());
        if (Objects.equals(orderRefundParam.getApplyType(), 2)) {
            newOrderRefund.setIsReceiver(true);
        } else {
            newOrderRefund.setIsReceiver(orderRefundParam.getIsReceiver());
        }
        newOrderRefund.setBuyerReason(orderRefundParam.getBuyerReason());
        newOrderRefund.setBuyerDesc(orderRefundParam.getBuyerDesc());
        newOrderRefund.setBuyerMobile(orderRefundParam.getBuyerMobile());
        newOrderRefund.setPhotoFiles(orderRefundParam.getPhotoFiles());
        newOrderRefund.setReturnMoneySts(ReturnMoneyStsType.APPLY.value());
        newOrderRefund.setApplyTime(new Date());
        newOrderRefund.setUpdateTime(new Date());
        applyRefund(newOrderRefund);
        return newOrderRefund.getRefundSn();
    }

    @Transactional(rollbackFor = Exception.class)
    public void applyRefund(OrderRefund orderRefund) {
        // 生成退款单
        orderRefundMapper.insert(orderRefund);
        // 更新订单状态
        Order order = this.getById(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.APPLY.value());
        this.updateById(order);
    }

    private boolean checkRefundDate(Order order) {
        // 判断是否超过支持的退款天数
        if (Objects.equals(order.getHbOrderStatus(), OrderStatus.SUCCESS.value())) {
            long finallyTime = order.getFinallyTime().getTime();
            long currentTime = System.currentTimeMillis();
            int miniTime = Constant.MAX_FINALLY_REFUND_TIME * 24 * 60 * 60 * 1000;
            if (currentTime - finallyTime > miniTime) {
                return false;
            }
        }
        return true;
    }

    /**
     * 如果需要合并的话，就合并
     */
    private void mergeIfNeed(ExcelWriter writer, int firstRow, int lastRow, int firstColumn, int lastColumn, Object content) {
        if (lastRow - firstRow > 0 || lastColumn - firstColumn > 0) {
            writer.merge(firstRow, lastRow, firstColumn, lastColumn, content, false);
        } else {
            writer.writeCellValue(firstColumn, firstRow, content);
        }

    }

    private void writeExcel(HttpServletResponse response, ExcelWriter writer) {
        //response为HttpServletResponse对象
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=1.xls");

        ServletOutputStream servletOutputStream = null;
        try {
            servletOutputStream = response.getOutputStream();
            writer.flush(servletOutputStream);
            servletOutputStream.flush();
        } catch (IORuntimeException | IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
            try {
                if (servletOutputStream != null) {
                    servletOutputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 生成退款单 请求
     *
     * @param orderRefundParam 退款单数据
     * @return rReturnMoneySts
     */
    @Override
    public OrderRefund applyAgain(OrderRefundParam orderRefundParam, Integer rReturnMoneySts) {
        log.info(" 海博申请退款参数:{}", JSONObject.toJSONString(orderRefundParam));
        List<OrderRefundSku> orderRefundSkuList = orderRefundParam.getOrderRefundSkuList();

        Order order = orderMapper.getOrderAndOrderItemByOrderNumber(orderRefundParam.getOrderNumber());

        if (!Objects.equals(order.getIsPayed(), 1)) {
            throw new GlobalException("当前订单还未付款，无法申请");
        }


        if (Objects.equals(orderRefundParam.getRefundType(), RefundType.ALL.value()) && (!Objects.isNull(order.getRefundStatus()) && !Objects.equals(order.getRefundStatus(), RefundStatusEnum.DISAGREE.value()))) {
            throw new GlobalException("88该订单已有商品正在退款中，不能再进行整单退款");
        }

        OrderRefund newOrderRefund = new OrderRefund();

        // 获取所有正在进行中的退款订单
        List<OrderRefund> orderRefunds = orderRefundMapper.getProcessingOrderRefundByOrderId(order.getOrderId());

        for (OrderRefund orderRefund : orderRefunds) {
            if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
                throw new GlobalException("该订单正在进行整单退款，无法进行新的退款操作");
            }

//            if (Objects.equals(orderRefund.getOrderItemId(), orderRefundParam.getOrderItemId())) {
//                throw new GlobalException("该商品正在进行退款中，无法进行新的退款操作");
//            }
        }

        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.getOrderItemsByOrderNumber(order.getOrderNumber());
        // 判断退款单类型（1:整单退款,2:单个物品退款）


        if (orderRefundParam.getRefundType().equals(RefundType.ALL.value())) {
            // 全部物品退款
            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(sumTotalDistributionAmountByOrderItem(orderItemList));
            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            newOrderRefund.setPlatformRefundAmount(order.getPlatformAmount());
            newOrderRefund.setOrderItemId(0L);
        } else {
            CullenUtils.validateDataThrowException(orderRefundSkuList.isEmpty(), "退款商品不能为空...");
            // 部分物品退款
            OrderItem orderItem = orderItemService.getOne(new LambdaQueryWrapper<OrderItem>()
                    .eq(OrderItem::getOrderNumber, orderRefundParam.getOrderNumber()));
            if (orderItem == null) {
                throw new GlobalException("该物品在订单中不存在");
            }
            boolean isCanRefund = false;
            //  查看是否有支付金额和积分都为空的订单，有则抛出异常
            for (OrderItem item : orderItemList) {
                if (item.getActualTotal() <= 0.0 && item.getUseScore() <= 0.0) {
                    isCanRefund = true;
                    break;
                }
            }
            if (isCanRefund) {
                throw new GlobalException("该订单部分订单项支付金额和积分为0，无法使用部分退款！");
            }

            // 计算该订单项的分销金额
            newOrderRefund.setDistributionTotalAmount(sumTotalDistributionAmountByOrderItem(Collections.singletonList(orderItem)));

            // 计算平台退款金额（退款时将这部分钱退回给平台，所以商家要扣除从平台这里获取的金额）
            newOrderRefund.setPlatformRefundAmount(orderItem.getPlatformShareReduce());

            // 退款物品数量为null或者0时，则为退款全部数量
            if (orderRefundParam.getGoodsNum() <= 0) {
                orderRefundParam.setGoodsNum(orderItem.getProdCount());
            }

            // 判断退款数量是否溢出
            if (orderRefundParam.getGoodsNum() > orderItem.getProdCount()) {
                throw new GlobalException("退款物品数量已超出订单中的数量，不允许申请");
            }

            // 判断退款金额是否超出订单金额
//            double refundSingleAmount = Arith.div(orderRefundParam.getRefundAmount(), orderRefundParam.getGoodsNum(), 3);
//            double singleAmount = Arith.div(orderItem.getActualTotal(), orderItem.getProdCount(), 3);
//            if (refundSingleAmount > orderItem.getProductTotalAmount() || refundSingleAmount > singleAmount) {
//                throw new GlobalException("退款金额已超出订单金额，无法申请");
//            }

            // 待发货状态-最后一件商品进行退款，退款金额 =  商品金额 + 订单运费金额
            if ((Objects.equals(order.getHbOrderStatus(), OrderStatus.PADYED.value()) ||
                    Objects.equals(order.getHbOrderStatus(), OrderStatus.CONSIGNMENT.value())) && order.getFreightAmount() > 0) {
                int orderItenCount = orderItemService.count(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, order.getOrderNumber()));
                if (Objects.equals(orderRefunds.size(), orderItenCount - 1)) {
                    newOrderRefund.setRefundAmount(Arith.add(newOrderRefund.getRefundAmount(), order.getFreightAmount()));
                    newOrderRefund.setFreightAmount(order.getFreightAmount());
                }
            }
        }

        newOrderRefund.setShopId(order.getShopId());
        newOrderRefund.setUserId(order.getUserId());
        newOrderRefund.setOrderId(order.getOrderId());
        newOrderRefund.setOrderNumber(order.getOrderNumber());
        //退款单号   T+年+月+日+时+分+秒+随机四个数字。
        String T = "T" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + RandomUtil.randomNumbers(4);

        newOrderRefund.setRefundSn(T);
        newOrderRefund.setRefundType(orderRefundParam.getRefundType());
        newOrderRefund.setRefundAmount(orderRefundParam.getRefundAmount());

        newOrderRefund.setGoodsNum(orderRefundParam.getGoodsNum());
        newOrderRefund.setApplyType(orderRefundParam.getApplyType());
        if (Objects.equals(orderRefundParam.getApplyType(), 2)) {
            newOrderRefund.setIsReceiver(true);
        } else {
            newOrderRefund.setIsReceiver(orderRefundParam.getIsReceiver());
        }
        newOrderRefund.setBuyerReason(orderRefundParam.getBuyerReason());
        newOrderRefund.setBuyerDesc(orderRefundParam.getBuyerDesc());
        newOrderRefund.setBuyerMobile(orderRefundParam.getBuyerMobile());
        newOrderRefund.setPhotoFiles(orderRefundParam.getPhotoFiles());
        newOrderRefund.setReturnMoneySts(rReturnMoneySts);
        newOrderRefund.setApplyTime(new Date());
        newOrderRefund.setUpdateTime(new Date());

        //TODO 待完善 积分
        log.info("生成退款单：{}", newOrderRefund);

        List<OrderRefundAmountParam> sukList = Lists.newArrayList();
        orderRefundParam.getOrderRefundSkuList().forEach(c -> {
            OrderRefundAmountParam orderRefundAmountParam = new OrderRefundAmountParam();
            orderRefundAmountParam.setSkuId(c.getSkuId());
            orderRefundAmountParam.setProdCount(c.getProductCount());
            sukList.add(orderRefundAmountParam);
        });

        // 生成退款单
        orderRefundMapper.insert(newOrderRefund);
        // 更新订单状态
        Integer refundType = newOrderRefund.getRefundType();
        if (Objects.equals(refundType, RefundType.ALL.value())) {
            order.setRefundStatus(RefundStatusEnum.APPLY.value());
        } else {
            order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
        }
        orderMapper.updateById(order);

        if (ObjectUtil.isNotEmpty(orderRefundSkuList)) {
            orderRefundSkuList.forEach(c -> {
                c.setOrderRefundId(newOrderRefund.getRefundId());
                orderRefundSkuMapper.insert(c);
            });
        }
        return newOrderRefund;
    }


    /**
     * 退货退款
     */
    @Override
    public void returnRefund(String orderNumber) {
        log.info("====================开始退货退款orderNumber：{}====================", orderNumber);
        OrderRefund orderRefund = orderRefundMapper.selectOne(new LambdaQueryWrapper<OrderRefund>()
                .eq(OrderRefund::getOrderNumber, orderNumber)
                .eq(OrderRefund::getReturnMoneySts, 70)
                .eq(OrderRefund::getHandler, Boolean.FALSE)
        );
        if (ObjectUtils.isNotEmpty(orderRefund)) {
            Order order = orderMapper.selectById(orderRefund.getOrderId());

            //生成待商家审核记录
            addOrderRefundRecord(orderRefund.getRefundId(), 25, 6, "平台已退款到微信账户中");
            addOrderRefundRecord(orderRefund.getRefundId(), 30, 10, "商家已同意收货，正在为你处理退款。");
            //如果是分次退款最后一个商品需要改变订单状态
            updateOrderStatus(order);


            if (ObjectUtils.isNotEmpty(orderRefund)) {
                //退款的金额
                BigDecimal refundActual = BigDecimal.ZERO;
                //退款的积分
                Long refundScore = 0L;
                //过期的积分
                long refundExpiredScore = 0L;
                //退款总积分
                Long refundOffsetPoints = 0L;

                if (null == order) throw new GlobalException("该订单不支持退款");
                //判定已完成的时间
                if (Objects.equals(order.getHbOrderStatus(), OrderStatus.SUCCESS.value()) && isPaymentOver7Days(order.getPayTime())) {
                    throw new GlobalException("支付完成已经超过7天，不支持退款");
                }
                //"订单退款状态（1:申请退款 2:退款成功 3:部分退款成功 4:退款失败）"
                switch (orderRefund.getRefundType()) {
                    case 1://1:整单退款
                        order.setRefundStatus(2);
                        if (order.getActualTotal() > 0) {
                            OrderSettlement orderSettlement = orderSettlementMapper.selectOne(new LambdaQueryWrapper<OrderSettlement>()
                                    .eq(OrderSettlement::getOrderNumber, order.getOrderNumber())
                                    .eq(OrderSettlement::getPayType, 1));
                            if (ObjectUtil.isNotEmpty(order.getOffsetPoints()) && order.getOffsetPoints() > 0) {//混合支付
                                //退钱
                                RefundInfoPo po = new RefundInfoPo();
                                po.setOutTradeNo(orderSettlement.getPayNo());
                                //混合支付，有积分时运费优先扣积分
                                po.setTotal((int) Arith.mul(order.getActualTotal(), 100));
                                po.setRefundMoney((int) Arith.mul(order.getActualTotal(), 100));
                                String s = wxProviderService.refundOrder(po);
                                System.out.println("微信退款结果：" + s);
                                refundActual = BigDecimal.valueOf(order.getActualTotal());
                                //优先退未过期的积分,退积分
//                            List<PointsRecord> pointsRecords = pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
//                                    .eq(PointsRecord::getOrderNumber, order.getOrderNumber()).eq(PointsRecord::getPointsType, 2)
//                                    .orderByDesc(PointsRecord::getExpiryDate));
                                List<PointsRecord> pointsRecords = pointsRecordMapper.findByOrderNumber(order.getOrderNumber(), 2);
                                for (PointsRecord pointsRecord : pointsRecords) {
//                                refundScore =  (refundScore + order.getOffsetPoints());
                                    PointsRecord npr = new PointsRecord();
                                    BeanUtils.copyProperties(pointsRecord, npr);
                                    npr.setId(null);
                                    npr.setPointsType(3);
                                    npr.setPointsAudit(1);
                                    npr.setPoints(pointsRecord.getVariablePoints());
                                    npr.setVariablePoints(BigDecimal.valueOf(0));
                                    Long l = pointsRecordMapper.statisticsPoint(pointsRecord.getUserId(), pointsRecord.getChannelId());
                                    if (null == l) {
                                        l = 0L;
                                    }
                                    if (null != pointsRecord.getVariablePoints()) {
                                        if (pointsRecord.getExpiryStatus() == 1) {
                                            npr.setCurrentlyAvailablePoints(pointsRecord.getVariablePoints().add(BigDecimal.valueOf(l)));
                                        } else {
                                            npr.setCurrentlyAvailablePoints(BigDecimal.ZERO.add(BigDecimal.valueOf(l)));
                                        }
                                        if (pointsRecord.getExpiryStatus() == 2) {
                                            refundExpiredScore += pointsRecord.getVariablePoints().longValue();
                                        }
                                        refundScore = (refundScore + pointsRecord.getVariablePoints().intValue());
                                    } else {
                                        npr.setCurrentlyAvailablePoints(BigDecimal.ZERO.add(BigDecimal.valueOf(l)));
                                    }
                                    npr.setCreationDate(new Date());
                                    pointsRecordMapper.insert(npr);
                                }
//                            refundExpiredScore = order.getOffsetPoints() - refundScore;
                            } else {//仅微信支付
                                RefundInfoPo po = new RefundInfoPo();
                                po.setOutTradeNo(orderSettlement.getPayNo());
                                po.setTotal((int) Arith.mul(Arith.add(order.getTotal(), order.getFreightAmount()), 100));
                                po.setRefundMoney((int) Arith.mul(Arith.add(order.getTotal(), order.getFreightAmount()), 100));
                                String s = wxProviderService.refundOrder(po);
                                System.out.println("微信退款结果：" + s);
                                refundActual = BigDecimal.valueOf(Arith.add(order.getTotal(), order.getFreightAmount()));
                            }
                        } else {
                            //退，积分【优先退未过期的积分】
//                        List<PointsRecord> pointsRecords = pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
//                                .eq(PointsRecord::getOrderNumber, order.getOrderNumber()).eq(PointsRecord::getPointsType, 2)
//                                .orderByDesc(PointsRecord::getExpiryDate));
                            List<PointsRecord> pointsRecords = pointsRecordMapper.findByOrderNumber(order.getOrderNumber(), 2);
                            for (PointsRecord pointsRecord : pointsRecords) {
                                PointsRecord npr = new PointsRecord();
                                BeanUtils.copyProperties(pointsRecord, npr);
                                npr.setId(null);
                                npr.setPointsType(3);
                                npr.setPointsAudit(1);
                                npr.setPoints(pointsRecord.getVariablePoints());
                                npr.setVariablePoints(BigDecimal.valueOf(0));
                                Long l = pointsRecordMapper.statisticsPoint(pointsRecord.getUserId(), pointsRecord.getChannelId());
                                if (null == l) {
                                    l = 0L;
                                }
                                if (null != pointsRecord.getVariablePoints()) {
                                    if (pointsRecord.getExpiryStatus() == 1) {
                                        npr.setCurrentlyAvailablePoints(pointsRecord.getVariablePoints().add(BigDecimal.valueOf(l)));
                                    } else {
                                        npr.setCurrentlyAvailablePoints(BigDecimal.valueOf(0.0).add(BigDecimal.valueOf(l)));
                                    }
                                    if (pointsRecord.getExpiryStatus() == 2) {
                                        refundExpiredScore += pointsRecord.getVariablePoints().longValue();
                                    }
                                    refundScore = (refundScore + pointsRecord.getVariablePoints().intValue());
                                } else {
                                    npr.setCurrentlyAvailablePoints(BigDecimal.ZERO.add(BigDecimal.valueOf(l)));
                                }
                                npr.setCreationDate(new Date());
                                pointsRecordMapper.insert(npr);
                            }
//                            refundExpiredScore = order.getOffsetPoints() - refundScore;
                        }
                        break;
                    case 2://2:单个物品退款
                        order.setRefundStatus(3);
                        List<OrderRefundSku> orderRefundSkus = orderRefundSkuMapper.selectList(new LambdaQueryWrapper<OrderRefundSku>()
                                .eq(OrderRefundSku::getOrderRefundId, orderRefund.getRefundId()));
                        List<PointsRecord> pointsRecords = pointsRecordMapper.findByOrderNumber(order.getOrderNumber(), 2);
                        List<OrderRefund> orderRefundList = orderRefundMapper.findByOrderNumber(order.getOrderNumber(), 70);

                        for (OrderRefund refund : orderRefundList) {
                            refundOffsetPoints += refund.getOffsetPoints();
                        }
//                            pointsRecordMapper.selectList(new LambdaQueryWrapper<PointsRecord>()
//                            .eq(PointsRecord::getOrderNumber, order.getOrderNumber())
//                            .eq(PointsRecord::getPointsType, 2)
//                            .and(wrapper -> wrapper
////                                    .gt(PointsRecord::getExpiryDate, LocalDateTime.now())
////                                    .or()
//                                    .isNull(PointsRecord::getExpiryDate)
//                            ).orderByDesc(PointsRecord::getExpiryDate));
                        //TODO (int) Arith.mul(order.getFreightAmount(), 100),加在这里就是每次部分退单都要减掉，有可能会出现退的积分比下单总积分少。少的值恰好为一次运费
                        int totalRefundScore = 0;//需要退款的金额，部分退款时不需要退运费。
                        int freightAmountScore = -(int) Arith.mul(order.getFreightAmount(), 100);//需要退的总积分,先把运费剔除掉
                        double totalRefundActual = 0.0;//需要退的总金额
                        int shoppingScore = 0;
                        for (OrderRefundSku refundSkus : orderRefundSkus) {
                            Integer productCount = refundSkus.getProductCount();//退款的数量
                            OrderItem orderItem = orderItemMapper.selectById(refundSkus.getOrderItemId());
                            Double actualTotal = orderItem.getActualTotal();//付的钱
                            Integer useScore = orderItem.getUseScore();//使用的总积分
                            if (ObjectUtil.isNotEmpty(order.getOffsetPoints())) {
                                shoppingScore = order.getOffsetPoints().intValue() + freightAmountScore;//退款商品的总积分
                            }

                            if (useScore > 0) {
                                //退的积分不一定等于下单的数量
                                totalRefundScore = (int) (totalRefundScore + Arith.mul(productCount * orderItem.getPrice(), 100));
                            }
                            if (actualTotal > 0) {
                                totalRefundActual = Arith.add(totalRefundActual, productCount * orderItem.getPrice());
                            }
                        }
                        log.info("退款积分：refundOffsetPoints：" + refundOffsetPoints + ";shoppingScore：" + shoppingScore + ";totalRefundScore:" + totalRefundScore);
                        //退积分
                        if (totalRefundScore > 0) {
                            refundScore = (long) totalRefundScore;
                            for (PointsRecord pointsRecord : pointsRecords) {
                                //下单支付的金额
                                int variablePoints = pointsRecord.getVariablePoints().intValue();//574
                                PointsRecord npr = new PointsRecord();
                                BeanUtils.copyProperties(pointsRecord, npr);
                                npr.setId(null);
                                npr.setPointsType(3);
                                Long l = pointsRecordMapper.statisticsPoint(pointsRecord.getUserId(), pointsRecord.getChannelId());
                                if (null == l) {
                                    l = 0L;
                                }
                                npr.setCreationDate(new Date());
                                //574>188
                                if (variablePoints < totalRefundScore) {//下单金额全退
                                    npr.setPoints(pointsRecord.getVariablePoints());
                                    npr.setVariablePoints(BigDecimal.valueOf(0));
                                    npr.setPointsAudit(1);
                                    if (pointsRecord.getExpiryStatus() == 1) {//当过期状态等于1时才进行变更可用金额 否则不变更
                                        if (null != pointsRecord.getVariablePoints()) {
                                            npr.setCurrentlyAvailablePoints(pointsRecord.getVariablePoints().add(BigDecimal.valueOf(l)));
                                        } else {
                                            npr.setCurrentlyAvailablePoints(BigDecimal.valueOf(0.0).add(BigDecimal.valueOf(l)));
                                        }
                                    } else {
                                        npr.setCurrentlyAvailablePoints(BigDecimal.valueOf(0.0).add(BigDecimal.valueOf(l)));
                                    }
                                    if (pointsRecord.getExpiryStatus() == 2) {
                                        refundExpiredScore += variablePoints;
                                    }
                                    totalRefundScore -= variablePoints;
                                    pointsRecordMapper.insert(npr);
                                } else if (totalRefundScore > 0) {//574>188,应退188
                                    npr.setPoints(BigDecimal.valueOf(totalRefundScore));
                                    npr.setVariablePoints(BigDecimal.valueOf(0));
                                    npr.setPointsAudit(1);
                                    if (pointsRecord.getExpiryStatus() == 1) {//当过期状态等于1时才进行变更可用金额 否则不变更
                                        BigDecimal bigDecimal = BigDecimal.valueOf(totalRefundScore);
                                        npr.setCurrentlyAvailablePoints(bigDecimal.add(BigDecimal.valueOf(l)));
                                    } else {
                                        npr.setCurrentlyAvailablePoints(BigDecimal.valueOf(0.0).add(BigDecimal.valueOf(l)));
                                    }
                                    if (pointsRecord.getExpiryStatus() == 2) {
                                        refundExpiredScore += totalRefundScore;
                                    }
                                    totalRefundScore = 0;
                                    pointsRecordMapper.insert(npr);
                                }
                                log.info("退积分：当前退款金额为：totalRefundScore：" + totalRefundScore);
                                if (totalRefundScore == 0 && shoppingScore >= refundOffsetPoints) {
                                    orderRefund.setRefundAmount(refundActual.doubleValue());
                                    orderRefund.setOffsetPoints(refundScore);
                                    orderRefund.setHandler(Boolean.TRUE);
                                    orderRefund.setRefundExpiredScore(refundExpiredScore);
                                    log.info("仅退积分-退款单修改状态和积分{}", orderRefund);
                                    orderRefundMapper.updateById(orderRefund);
                                    return;
                                }
                            }
                        }
                        //退钱
                        if (totalRefundActual > 0) {
                            int refundMoney = 0;//需要退款的金额
                            if (totalRefundScore > 0) {
                                if (totalRefundActual >= totalRefundScore) {
                                    refundMoney = totalRefundScore;
                                } else {
                                    System.out.println("退款金额大于支付金额");
                                }
                            } else if (totalRefundScore == 0) {
                                refundMoney = (int) Arith.mul(totalRefundActual, 100);
                            } else {
                                System.out.println("单笔退款未知状态");
                                break;
                            }
                            OrderSettlement orderSettlement = orderSettlementMapper.selectOne(new LambdaQueryWrapper<OrderSettlement>()
                                    .eq(OrderSettlement::getOrderNumber, order.getOrderNumber())
                                    .eq(OrderSettlement::getPayType, 1));
                            RefundInfoPo po = new RefundInfoPo();
                            po.setOutTradeNo(orderSettlement.getPayNo());
                            po.setTotal((int) Arith.mul(order.getActualTotal(), 100));
                            po.setRefundMoney(refundMoney);
                            if (refundMoney != 0) {
                                String s = wxProviderService.refundOrder(po);
                                System.out.println("微信退款结果：" + s);
                            }
                            refundActual = BigDecimal.valueOf(refundMoney);
                        }
                        break;
                }
                if (1 == orderRefund.getRefundType()) {
                    order.setHbOrderStatus(OrderStatus.CLOSE.value());
                } else {
                    List<OrderRefund> orderRefundList = orderRefundMapper.selectList(new LambdaQueryWrapper<OrderRefund>()
                            .eq(OrderRefund::getOrderNumber, orderNumber)
                            .eq(OrderRefund::getReturnMoneySts, 70)
                    );
                    //统计全部退货商品数量(goodsNum)
                    int goodsNum = orderRefundList.stream().mapToInt(OrderRefund::getGoodsNum).sum();
                    if (goodsNum == order.getProductNums()) {
                        order.setHbOrderStatus(OrderStatus.CLOSE.value());
                    }
                }
                orderMapper.updateById(order);

                        orderRefund.setRefundAmount(refundActual.doubleValue());
                        orderRefund.setOffsetPoints(refundScore);
                        orderRefund.setHandler(Boolean.TRUE);
                        orderRefund.setRefundExpiredScore(refundExpiredScore);
                        log.info("退款单修改状态和积分{}", orderRefund);
                        orderRefundMapper.updateById(orderRefund);

            }
        }
    }

    /**
     * 退款成功后，修改订单状态
     *
     * @param order 订单
     *              退款单
     */
    private void updateOrderStatus(Order order) {
        //定义变量是否需要通知海博改变订单状态
        boolean status = true;
        for (OrderItem orderItem : orderItemMapper.getListByOrderNumber(order.getOrderNumber())) {
            List<OrderRefundSku> orderRefundSkus = orderRefundSkuMapper.selectByOrderItemList(orderItem.getOrderItemId());
            if (ObjectUtils.isEmpty(orderRefundSkus)) {
                status = false;
                break;
            }
            //统计orderRefundSkus里面商品数量
            int refundCount = orderRefundSkus.stream().mapToInt(OrderRefundSku::getProductCount).sum();
            if (!orderItem.getProdCount().equals(refundCount)) {
                status = false;
                break;
            }
        }

        if (status) {
            order.setHbOrderStatus(OrderStatus.CLOSE.value());
            orderMapper.updateById(order);
            //通知海博改变订单状态
            HBBaseReq<Object> build = HBBaseReq.create();
            build.setAppId(hbSignUtil.getAppId());

            // 3. 构建外层请求体
            JSONObject requestBody = new JSONObject();
            requestBody.put("channelOrderId", order.getOrderNumber());
            requestBody.put("operator", "admin");
            // 订单操作时间戳毫秒数
            requestBody.put("operatorTime", System.currentTimeMillis());
            //操作类型 （20：订单已接单 30：订单待配送 60：订单已取消 80：订单已完成）
            requestBody.put("operatorType", OrderStatus.CLOSE.value());
            // 4. 将整个JSON对象序列化为字符串并设置
            build.setBody(JSON.toJSONString(requestBody));

            build.setSign(hbSignUtil.signMd5(build));
            log.info("post 订单推送单号参数：{}", JSON.toJSONString(build));
            String post = post(hbSignUtil.getHBHost() + "/api/order/changeOrderStatus", build);
            log.info("post 订单推送结果：{}", post);
        }
    }

    private void addOrderRefundRecord(Long refundId, Integer auditStatus, Integer sort, String instructions) {
        OrderRefundRecord orderRefundRecord = new OrderRefundRecord();
        orderRefundRecord.setOrderRefundId(refundId);
        orderRefundRecord.setInstructions(instructions);
        Date date = new Date();
        orderRefundRecord.setCreateTime(date);
        orderRefundRecord.setUpdateTime(date);
        orderRefundRecord.setAuditStatus(auditStatus);
        orderRefundRecord.setSort(sort);
        orderRefundRecordMapper.insert(orderRefundRecord);
    }

    @Override
    public OrderRefundAmountDTO computeOrderRefundAmount(String orderNumber, List<OrderRefundAmountParam> suk) {
        BigDecimal orderRefundAmount = BigDecimal.ZERO;
        Long offsetPoints = 0L;
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, orderNumber)
                .eq(Order::getDeleteStatus, 0));
        List<OrderItem> orderItems = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>().eq(OrderItem::getOrderNumber, orderNumber));
        return OrderRefundAmountDTO.builder().orderRefundAmount(orderRefundAmount).offsetPoints(offsetPoints).build();
    }

    @Override
    public Map<String, Integer> deliverListStatusNum(BackendOrderParam orderParam) {
        Map<String, Integer> map = new LinkedTreeMap<>();
        map.put("all", orderMapper.statusCount(Lists.newArrayList(0, 1, 20, 30, 40, 50, 60, 70, 80), orderParam));
        map.put("paddingPay", orderMapper.statusCount(Lists.newArrayList(0), orderParam));
        map.put("paddingShipped", orderMapper.statusCount(Lists.newArrayList(1), orderParam));
        map.put("paddingReceived", orderMapper.statusCount(Lists.newArrayList(20, 30, 40, 70), orderParam));
        map.put("completed", orderMapper.statusCount(Lists.newArrayList(80), orderParam));
        map.put("cancel", orderMapper.statusCount(Lists.newArrayList(60, 50), orderParam));
        //待拆单数量
        orderParam.setSplitStatus(2);
        map.put("split", orderMapper.statusCount(Lists.newArrayList(1,20), orderParam));
        return map;
    }


    @Override
    public OrderCountParam selectOrderCount(OrderParam orderParam) {
        return orderMapper.selectOrderCount(orderParam);
    }

    @Override
    public IPage<Order> deliveryOrder(PageParam<Order> page, OrderStatisticsParam orderParam) {
        IPage<Order> orderIPage = orderMapper.deliveryOrder(page, orderParam);
        orderIPage.getRecords().forEach(order -> {
            order.setOrderItems(orderItemService.getOrderItemsByOrderNumber(order.getOrderNumber()));
        });
        return orderIPage;
    }

    private boolean isPaymentOver7Days(Date paymentDate) {
        // 1. 将支付时间转换为 Instant
        Instant paymentInstant = paymentDate.toInstant();
        // 2. 增加 7 天（精确到毫秒，考虑时区）
        Instant expirationInstant = paymentInstant.plus(7, java.time.temporal.ChronoUnit.DAYS);
        // 3. 获取当前时间
        Instant nowInstant = Instant.now();
        // 4. 比较时间
        return nowInstant.isAfter(expirationInstant) || nowInstant.equals(expirationInstant);
    }

        /**
         * 导出正常订单
         *
         * @param orderParam
         * @param userId
         */
        @Override
        public R<String> export (BackendOrderParam orderParam, Long userId) {
            List<Order> orderList = orderMapper.findList(orderParam);
            if (!orderList.isEmpty()) {
                orderList.forEach(c -> {
                    List<OrderItem> orderItems = orderItemMapper.getListByOrderNumber(c.getOrderNumber());
                    c.setOrderItems(orderItems);
                    c.setGoodsTotalCount(orderItems.stream().map(OrderItem::getProdCount).reduce(0, Integer::sum));
                });
            }
            if (orderList.isEmpty()) {
                return R.FAIL("未查询到数据不允许导出");
            }
            String taskId = UUID.randomUUID().toString();
            ExportTask exportTask = new ExportTask();
            exportTask.setUserId(userId);
            exportTask.setExportStatus(0);//导出状态进行中
            exportTask.setTaskId(taskId);
            exportTask.setExportType(1);//导出类型
            exportTask.setTaskName("正常订单导出");
            exportTask.setExportMsg("导出中");
            exportTask.setCreateTime(new Date());
            exportTask.setUpdateTime(new Date());
            exportTaskService.save(exportTask);
            // 异步执行导出
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                Thread currentThread = Thread.currentThread();
                ExportContext context = new ExportContext(null, currentThread, false, 0);
                exportTaskService.putTaskId(taskId,context);
                try {
                    // 记录任务开始
                    log.info("开始执行导出任务，用户ID: {}", userId);
                    exportNormalOrders(orderList,exportTask, "order",context);
                    // 记录任务完成
                    log.info("导出任务完成，用户ID: {}", userId);
                } catch (Exception e) {
                    log.error("导出任务异常，用户ID: {}", userId, e);
                    exportTask.setExportStatus(2);
                    exportTask.setExportMsg("导出失败,"+e.getMessage());
                    exportTaskService.updateById(exportTask);
                }finally {
                    exportTaskService.removeTaskId(taskId);
                }
            }, exportExecutor);
            // 存储任务上下文
            exportTaskService.putTaskId(taskId, new ExportContext(future, null, false, 0));
           return R.SUCCESS("成功");
        }
    @Override
    public OrderCountVo orderCount(BackendOrderParam orderParam) {
        OrderCountVo orderCountVo = orderMapper.orderCount(orderParam);
        if (orderCountVo!=null){
            if (orderCountVo.getOrderMoneyTotal()!=null&&orderCountVo.getCarriageMoneyTotal()!=null){
                BigDecimal add = orderCountVo.getOrderMoneyTotal().add(orderCountVo.getCarriageMoneyTotal());
                orderCountVo.setOrderMoneyTotal(add);
                orderCountVo.setPayMoneyTotal(add);
            }
            if (orderCountVo.getOrderTotal()!=0L
                    &&orderCountVo.getOrderMoneyTotal()!=null
                    &&orderCountVo.getOrderMoneyTotal().compareTo(BigDecimal.ZERO) != 0){
                BigDecimal unitPrice = orderCountVo.getOrderMoneyTotal().divide(new BigDecimal(orderCountVo.getOrderTotal()), 2, RoundingMode.HALF_UP);
                orderCountVo.setAverageOrderValueMoney(unitPrice);
            }
        }
        return orderCountVo;
    }

    /**
         * 导出正常订单数据到Excel（直接输出到HttpServletResponse）
         */
        public void exportNormalOrders (List < Order > orderList, ExportTask exportTask,
                String fileName,ExportContext context){
            // 2. 生成安全的文件名
            String safeFileName = ExportUtils.generateSafeFileName(fileName);
            // 3. 准备文件路径
            try {
                ExportUtils.prepareExportFile(safeFileName, exportTask);
            } catch (ExportException e) {
                exportTask.setExportStatus(2);//处理失败
                exportTask.setExportMsg(e.getMessage());
                exportTaskService.updateById(exportTask);
                return;
            }
            File file = new File(exportTask.getFileUrl());
            try (Workbook workbook = new SXSSFWorkbook(100)) {
                // 创建Sheet
                Sheet sheet = workbook.createSheet("正常订单");

                // 设置列宽
                setupColumnWidth(sheet);

                // 创建表头样式
                CellStyle headerStyle = ExportUtils.createHeaderStyle(workbook);

                // 创建数据样式
                CellStyle dataStyle = ExportUtils.createDataStyle(workbook);
                CellStyle numberStyle = ExportUtils.createNumberStyle(workbook);
                CellStyle dateStyle = ExportUtils.createDateStyle(workbook);


                String[] headers = {
                        "序号", "订单编号", "下单时间", "付款时间", "订单状态", "订单类型",
                        "商品名称", "规格", "单价(元)", "数量", "小计(元)",
                        "商品总数量", "商品总额(元)", "运费(元)", "积分抵扣(元)",
                        "实付金额", "所属企业", "买家姓名", "买家电话"
                };
                // 创建合并单元格的表头
                ExportUtils.createMergedHeader(sheet, headerStyle, "正常订单",18);

                // 创建列标题行
                ExportUtils.createColumnHeaders(sheet, headerStyle, headers);

                // 填充数据
                fillOrderData(sheet, orderList, dataStyle, numberStyle, dateStyle, context);
                // 写入文件
                try (FileOutputStream fos = new FileOutputStream(file);
                     BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                    workbook.write(bos);
                }
                // 检查是否被中断
                if (context.isCancelled() || Thread.currentThread().isInterrupted()) {
                    log.info("导出任务 {} 被中断，已处理 {} 行", exportTask.getTaskId(), context.getProcessedRows());
                    exportTask.setExportStatus(1); // 3-已取消
                    exportTask.setExportMsg("导出被用户取消，已处理" + context.getProcessedRows() + "行");
                    exportTaskService.updateById(exportTask);
                    return;
                }
                log.info("订单导出成功，文件：{}，记录数：{}", fileName, orderList.size());
                exportTask.setExportStatus(1);
                exportTask.setExportMsg("导出成功");
                exportTask.setUpdateTime(new Date());
                exportTaskService.updateById(exportTask);
            } catch (InterruptedException e) {
                log.error("导出任务 {} 被中断", exportTask.getTaskId());
                Thread.currentThread().interrupt(); // 重新设置中断状态
                exportTask.setExportStatus(4);
                exportTask.setExportMsg("导出被用户取消");
                exportTaskService.updateById(exportTask);
            } catch (Exception e) {
                log.error("订单导出失败", e);
                exportTask.setExportStatus(2);
                exportTask.setExportMsg("导出失败：" + e.getMessage());
                exportTaskService.updateById(exportTask);
            }
        }

        /**
         * 设置列宽
         */
        private void setupColumnWidth (Sheet sheet){
            // 根据模板设置列宽（单位：1/256字符宽度）
            sheet.setColumnWidth(0, 12 * 256);   // 序号
            sheet.setColumnWidth(1, 12 * 256);   // 订单编号
            sheet.setColumnWidth(2, 18 * 256);   // 下单时间
            sheet.setColumnWidth(3, 18 * 256);   // 付款时间
            sheet.setColumnWidth(4, 10 * 256);   // 订单状态
            sheet.setColumnWidth(5, 8 * 256);    // 订单类型
            sheet.setColumnWidth(6, 25 * 256);   // 商品名称
            sheet.setColumnWidth(7, 20 * 256);   // 规格
            sheet.setColumnWidth(8, 10 * 256);   // 单价
            sheet.setColumnWidth(9, 8 * 256);    // 数量
            sheet.setColumnWidth(10, 10 * 256);   // 小计
            sheet.setColumnWidth(11, 12 * 256);  // 商品总数量
            sheet.setColumnWidth(12, 12 * 256);  // 商品总额
            sheet.setColumnWidth(13, 8 * 256);   // 运费
            sheet.setColumnWidth(14, 12 * 256);  // 积分抵扣
            sheet.setColumnWidth(15, 10 * 256);  // 实付金额
            sheet.setColumnWidth(16, 15 * 256);  // 所属企业
            sheet.setColumnWidth(17, 10 * 256);  // 买家姓名
            sheet.setColumnWidth(18, 15 * 256);  // 买家电话
        }

        /**
         * 填充订单数据
         */
        private void fillOrderData (Sheet sheet, List < Order > orderList,
                CellStyle dataStyle, CellStyle numberStyle, CellStyle dateStyle,ExportContext context)  throws InterruptedException{
            int batchSize = 100; // 每批处理1000条
            int totalRows = orderList.size();
            int rowNum = 2; // 从第3行开始（0-based索引）
            int indexNum = 1; //序号
            for (int i = 0; i < totalRows; i += batchSize) {
                int end = Math.min(i + batchSize, totalRows);
                List<Order> batch = orderList.subList(i, end);
                for (Order order : batch) {
                    // 定期检查中断标志
                    if (context.isCancelled() || Thread.currentThread().isInterrupted()) {
                        context.setProcessedRows(indexNum);
                        break;
//                    throw new InterruptedException("导出被中断");
                    }
                    Row row = sheet.createRow(rowNum++);
                    row.setHeightInPoints(18);
                    //序号
                    ExportUtils.createCell(sheet, row, 0, order.getOrderItems().size(), rowNum, indexNum, dataStyle);
                    fillOrderRowData(sheet, rowNum, row, order, dataStyle, numberStyle, dateStyle);
                    rowNum += order.getOrderItems().size() - 1;
                    indexNum++;
                }

                // 定期刷新到磁盘
                if (rowNum % 100 == 0) {
                    try {
                        ((SXSSFSheet) sheet).flushRows(100);
                    } catch (IOException e) {
                        log.warn("刷新行数据失败", e);
                    }
                }
            }


        }

        /**
         * 填充单行订单数据
         */
        private void fillOrderRowData (Sheet sheet,int rowNum, Row row, Order order,
                CellStyle dataStyle, CellStyle numberStyle, CellStyle dateStyle){

            // 订单编号
            ExportUtils.createCell(sheet, row, 1, order.getOrderItems().size(), rowNum, order.getOrderNumber(), dataStyle);

            // 下单时间
            ExportUtils.createCell(sheet, row, 2, order.getOrderItems().size(), rowNum, ExportUtils.formatDate(order.getCreateTime()), dateStyle);

            // 付款时间
            ExportUtils.createCell(sheet, row, 3, order.getOrderItems().size(), rowNum, ExportUtils.formatDate(order.getPayTime()), dateStyle);

            // 订单状态
            ExportUtils.createCell(sheet, row, 4, order.getOrderItems().size(), rowNum, getHbOrderStatus(order.getHbOrderStatus()), dataStyle);

            // 订单类型
            ExportUtils.createCell(sheet, row, 5, order.getOrderItems().size(), rowNum, getDvyType(order.getDvyType()), dataStyle);
            // 商品明细行（每个订单项一行）
            fillOrderItems(sheet, rowNum, row, order, dataStyle, numberStyle);

            // 商品总数量
            ExportUtils.createCell(sheet, row, 11, order.getOrderItems().size(), rowNum, order.getProductNums(), dataStyle);

            // 商品总额(元)
            ExportUtils.createCell(sheet, row, 12, order.getOrderItems().size(), rowNum, order.getTotal(), numberStyle);

            // 运费(元)
            ExportUtils.createCell(sheet, row, 13, order.getOrderItems().size(), rowNum, order.getFreightAmount(), numberStyle);

            // 积分抵扣(元) - 显示为负数
            ExportUtils.createCell(sheet, row, 14, order.getOrderItems().size(), rowNum, "-" + (order.getOffsetPoints() == null ? 0 : Arith.div(Double.valueOf(order.getOffsetPoints()), 100)), numberStyle);

            // 实付金额
            ExportUtils.createCell(sheet, row, 15, order.getOrderItems().size(), rowNum, order.getActualTotal(), numberStyle);

            // 所属企业
            ExportUtils.createCell(sheet, row, 16, order.getOrderItems().size(), rowNum, order.getChannelName(), dataStyle);

            // 买家姓名
            ExportUtils.createCell(sheet, row, 17, order.getOrderItems().size(), rowNum, order.getReceiver(), dataStyle);

            // 买家电话
            ExportUtils.createCell(sheet, row, 18, order.getOrderItems().size(), rowNum, order.getUserMobile(), dataStyle);
        }

        /**
         * 填充订单项明细
         */
        private void fillOrderItems (Sheet sheet,int rowNum, Row row, Order order,
                CellStyle dataStyle, CellStyle numberStyle){
            int itemSize = order.getOrderItems().size();

            for (int i = 0; i < itemSize; i++) {
                Row currentRow = (i < 1) ? row : sheet.createRow(rowNum + (i - 1));
                OrderItem item = order.getOrderItems().get(i);

                // 商品名称
                ExportUtils.createCell(sheet, currentRow, 6, 0, rowNum, item.getProdName(), dataStyle);

                // 规格
                ExportUtils.createCell(sheet, currentRow, 7, 0, rowNum, item.getSpec(), dataStyle);

                // 单价(元)
                ExportUtils.createCell(sheet, currentRow, 8, 0, rowNum, item.getPrice(), numberStyle);

                // 数量
                ExportUtils.createCell(sheet, currentRow, 9, 0, rowNum, item.getProdCount(), dataStyle);

                // 小计(元)
                ExportUtils.createCell(sheet, currentRow, 10, 0, rowNum, item.getProductTotalAmount(), numberStyle);

            }
        }

        /**
         * 海博订单状态
         *
         * @param status
         * @return
         */
        private String getHbOrderStatus (Integer status){
            switch (status) {
                case 0:
                    return "待支付";
                case 1:
                    return "待发货";
                case 20:
                    return "待收货";
                case 30:
                    return "待收货";
                case 40:
                    return "待收货";
                case 50:
                    return "订单取消待审核";
                case 60:
                    return "订单取消";
                case 70:
                    return "待收货";
                case 80:
                    return "订单完成";
                default:
                    return "未知状态";
            }
        }

        /**
         * 订单类型
         *
         * @param dvyType
         * @return
         */
        private String getDvyType (Integer dvyType){
            switch (dvyType) {
                case 1:
                    return "快递";
                case 2:
                    return "自提";
                case 3:
                    return "及时配送";
                default:
                    return "未知类型";
            }
        }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public Order manualSplitOrder(ManualSplitOrderParam param) {
        // 1. 查询父订单
        Order parentOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, param.getOrderNumber()));

        if (parentOrder == null) {
            throw new GlobalException("订单不存在");
        }

        // 2. 验证订单状态（只有待拆单或拆单中的订单才能进行手动拆单）
        if (parentOrder.getSplitStatus() != 2 && parentOrder.getSplitStatus() != 3) {
            throw new GlobalException("订单状态不允许拆单，只有待拆单或拆单中的订单才能进行手动拆单");
        }

        // 3. 查询父订单的订单项
        List<OrderItem> parentOrderItems = orderItemService.getOrderItemsByOrderNumber(param.getOrderNumber());
        if (parentOrderItems == null || parentOrderItems.isEmpty()) {
            throw new GlobalException("订单项不存在");
        }
        parentOrder.setOrderItems( parentOrderItems);
        // 4. 验证拆单数量
        Map<Long, OrderItem> parentItemMap = parentOrderItems.stream()
                .collect(Collectors.toMap(OrderItem::getSkuId, item -> item));

        List<OrderItem> subOrderItems = new ArrayList<>();
        for (ManualSplitOrderParam.ManualSplitOrderItemParam itemParam : param.getOrderItems()) {
            OrderItem parentItem = parentItemMap.get(itemParam.getSkuId());
            if (parentItem == null) {
                throw new GlobalException("SKU ID " + itemParam.getSkuId() + " 在订单中不存在");
            }

            // 验证数量：已拆单数量 + 本次拆单数量 不能超过总数量
            int currentSplitCount = parentItem.getSplitCount() != null ? parentItem.getSplitCount() : 0;
            if (currentSplitCount + itemParam.getProdCount() > parentItem.getProdCount()) {
                throw new GlobalException("商品 " + parentItem.getProdName() + " 拆单数量超过可用数量");
            }

            // 创建子订单项
            OrderItem subItem = new OrderItem();
            BeanUtils.copyProperties(parentItem, subItem);
            subItem.setOrderItemId(null);
            subItem.setProdCount(itemParam.getProdCount());
            subItem.setSplitCount(null);
            subOrderItems.add(subItem);
        }

        if (subOrderItems.isEmpty()) {
            throw new GlobalException("子订单项不能为空");
        }

        // 5. 创建子订单
        Order subOrder = new Order();
        //通过用户ID获取用户信息

        BeanUtils.copyProperties(parentOrder, subOrder);
        subOrder.setOrderId(null);
        subOrder.setSplitUserId(param.getSplitUserId());
        subOrder.setOrderNumber("D" + snowflake.nextId());
        subOrder.setParentOrderNumber(parentOrder.getOrderNumber());
        subOrder.setOrderLevel(1); // 子订单
        subOrder.setSplitStatus(0); // 临时保存
        subOrder.setAutoSplit(0); // 手动拆单
        subOrder.setOrderSplitStatus(0); // 未超重

        // 更新子订单项的orderNumber
        for (OrderItem item : subOrderItems) {
            item.setOrderNumber(subOrder.getOrderNumber());
        }
        subOrder.setOrderItems(subOrderItems);

        // 6. 计算子订单的积分和金额（按比例分配）
        allocatePointsAndAmountForManualSplit(parentOrder, subOrder, parentOrderItems);

        // 7. 计算子订单的运费（默认为0，后续确认拆单时再分配）
        subOrder.setFreightAmount(0.0);

        // 8. 保存子订单和订单项
        orderMapper.insert(subOrder);
        orderItemService.saveBatch(subOrderItems);

        // 9. 更新父订单状态为拆单中
        Order updateParentOrder = new Order();
        updateParentOrder.setOrderId(parentOrder.getOrderId());
        updateParentOrder.setSplitStatus(3); // 拆单中
        updateParentOrder.setUpdateTime(new Date());
        orderMapper.updateById(updateParentOrder);

        // 10. 更新父订单项的已拆单数量
        for (ManualSplitOrderParam.ManualSplitOrderItemParam itemParam : param.getOrderItems()) {
            OrderItem parentItem = parentItemMap.get(itemParam.getSkuId());
            int currentSplitCount = parentItem.getSplitCount() != null ? parentItem.getSplitCount() : 0;
            
            OrderItem updateItem = new OrderItem();
            updateItem.setOrderItemId(parentItem.getOrderItemId());
            updateItem.setSplitCount(currentSplitCount + itemParam.getProdCount());
            orderItemService.updateById(updateItem);
        }

        log.info("手动拆单成功，父订单号：{}，子订单号：{}", parentOrder.getOrderNumber(), subOrder.getOrderNumber());

        return subOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmSplitOrder(ConfirmSplitOrderParam param ) {
        // 1. 查询父订单
        Order parentOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, param.getOrderNumber()));

        if (parentOrder == null) {
            throw new GlobalException("订单不存在");
        }

        // 2. 验证父订单状态（只有拆单中的订单才能确认）
        if (parentOrder.getSplitStatus() != 3) {
            throw new GlobalException("订单状态不允许确认拆单，只有拆单中的订单才能确认");
        }

        // 3. 查询所有临时子订单
        List<Order> tempSubOrders = orderMapper.selectList(new LambdaQueryWrapper<Order>()
                .eq(Order::getParentOrderNumber, param.getOrderNumber())
                .eq(Order::getSplitStatus, 0)
                .eq(Order::getOrderLevel, 1));

        if (tempSubOrders == null || tempSubOrders.isEmpty()) {
            throw new GlobalException("没有找到临时子订单，无法确认拆单");
        }

        // 4. 查询每个子订单的订单项
        for (Order subOrder : tempSubOrders) {
            List<OrderItem> items = orderItemService.getOrderItemsByOrderNumber(subOrder.getOrderNumber());
            subOrder.setOrderItems(items);
        }

        // 5. 分配运费（平均分配，余额归首单）
        allocateFreight(parentOrder, tempSubOrders);

        // 6. 重新计算子订单的actualTotal（加上运费）
        for (Order subOrder : tempSubOrders) {
            double itemsActualTotal = subOrder.getOrderItems().stream()
                    .mapToDouble(item -> item.getActualTotal() != null ? item.getActualTotal() : 0.0)
                    .sum();
            double freight = subOrder.getFreightAmount() != null ? subOrder.getFreightAmount() : 0.0;
            subOrder.setActualTotal(itemsActualTotal + freight);
        }

        // 7. 设置子订单编号
        for (int i = 0; i < tempSubOrders.size(); i++) {
            tempSubOrders.get(i).setOrderSplitNumber(i + 1);
        }

        // 8. 更新父订单状态为已拆单
        Order updateParentOrder = new Order();
        updateParentOrder.setOrderId(parentOrder.getOrderId());
        updateParentOrder.setSplitStatus(4); // 已拆单
        updateParentOrder.setSplitUserId(param.getSplitUserId());
        updateParentOrder.setUpdateTime(new Date());
        orderMapper.updateById(updateParentOrder);

        // 9. 更新子订单状态为不拆单
        for (Order subOrder : tempSubOrders) {
            Order updateSubOrder = new Order();
            updateSubOrder.setOrderId(subOrder.getOrderId());
            updateSubOrder.setSplitStatus(1); // 不拆单
            updateSubOrder.setFreightAmount(subOrder.getFreightAmount());
            updateSubOrder.setActualTotal(subOrder.getActualTotal());
            updateSubOrder.setOrderSplitNumber(subOrder.getOrderSplitNumber());
            updateSubOrder.setUpdateTime(new Date());
            orderMapper.updateById(updateSubOrder);
        }

        log.info("确认拆单成功，父订单号：{}，子订单数量：{}", parentOrder.getOrderNumber(), tempSubOrders.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTempSubOrder(String subOrderNumber) {
        // 1. 查询子订单
        Order subOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, subOrderNumber));

        if (subOrder == null) {
            throw new GlobalException("子订单不存在");
        }

        // 2. 验证子订单状态（只能删除临时保存的子订单）
        if (subOrder.getSplitStatus() != 0 || subOrder.getOrderLevel() != 1) {
            throw new GlobalException("只能删除临时保存的子订单");
        }

        String parentOrderNumber = subOrder.getParentOrderNumber();
        if (StringUtils.isBlank(parentOrderNumber)) {
            throw new GlobalException("子订单没有父订单号");
        }

        // 3. 查询父订单
        Order parentOrder = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, parentOrderNumber));

        if (parentOrder == null) {
            throw new GlobalException("父订单不存在");
        }

        // 4. 查询子订单项
        List<OrderItem> subOrderItems = orderItemService.getOrderItemsByOrderNumber(subOrderNumber);

        // 5. 查询父订单项
        List<OrderItem> parentOrderItems = orderItemService.getOrderItemsByOrderNumber(parentOrderNumber);
        Map<Long, OrderItem> parentItemMap = parentOrderItems.stream()
                .collect(Collectors.toMap(OrderItem::getSkuId, item -> item));

        // 6. 减少父订单项的已拆单数量
        for (OrderItem subItem : subOrderItems) {
            OrderItem parentItem = parentItemMap.get(subItem.getSkuId());
            if (parentItem != null) {
                int currentSplitCount = parentItem.getSplitCount() != null ? parentItem.getSplitCount() : 0;
                int newSplitCount = Math.max(0, currentSplitCount - subItem.getProdCount());

                OrderItem updateItem = new OrderItem();
                updateItem.setOrderItemId(parentItem.getOrderItemId());
                updateItem.setSplitCount(newSplitCount);
                orderItemService.updateById(updateItem);
            }
        }

        // 7. 删除子订单项
        orderItemMapper.delete(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, subOrderNumber));

        // 8. 删除子订单
        orderMapper.deleteById(subOrder.getOrderId());

        // 9. 检查是否还有其他临时子订单，如果没有，将父订单状态改回待拆单
        Integer tempSubOrderCount = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getParentOrderNumber, parentOrderNumber)
                .eq(Order::getSplitStatus, 0)
                .eq(Order::getOrderLevel, 1));

        if (tempSubOrderCount == 0) {
            Order updateParentOrder = new Order();
            updateParentOrder.setOrderId(parentOrder.getOrderId());
            updateParentOrder.setSplitStatus(2); // 待拆单
            updateParentOrder.setUpdateTime(new Date());
            orderMapper.updateById(updateParentOrder);
        }

        log.info("删除临时子订单成功，子订单号：{}，父订单号：{}", subOrderNumber, parentOrderNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSMOrder(SMOrderPo orderPo) {
        Order order = new Order();
        order.setShopId(0L);
        order.setChannelId(0L);
        order.setUserId("");
        order.setOrderNumber(orderPo.getOrderNumber());
        order.setTotal(orderPo.getTotal());
        order.setActualTotal(orderPo.getActualTotal());
        order.setPayType(orderPo.getPayType());
        order.setRemarks(orderPo.getRemarks());
        order.setHbOrderStatus(10);
        order.setHbLogisticStatus(0);
        order.setDvyType(orderPo.getDvyType());
        order.setFreightAmount(orderPo.getFreightAmount());
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        order.setPayTime(orderPo.getPayTime());
        order.setIsPayed(1);
        order.setDeleteStatus(0);
        order.setOrderType(4);
        order.setCommSts(0);
        order.setOffsetPoints(orderPo.getOffsetPoints());
        List<SMOrderItemPo> orderItems = orderPo.getOrderItems();
        List<String> list = orderItems.stream().map(SMOrderItemPo::getSkuName).collect(Collectors.toList());
        order.setProdName(String.join(",",list));
        order.setProductNums(orderItems.stream().map(SMOrderItemPo::getProdCount).reduce(0, Integer::sum));
        orderMapper.insert(order);
        orderItems.forEach(c->{
            OrderItem item = new OrderItem();
            item.setShopId(0L);
            item.setOrderNumber(order.getOrderNumber());
            item.setProdId(c.getProdId());
            item.setSkuId(c.getSkuId());
            item.setProdCount(c.getProdCount());
            item.setProdName(c.getProdName());
            item.setSkuName(c.getSkuName());
            item.setPic(c.getPic());
            item.setPrice(c.getPrice());
            item.setUserId("");
            item.setProductTotalAmount(c.getProductTotalAmount());
            item.setRecTime(c.getRecTime());
            item.setCommSts(0);
            item.setBasketDate(new Date());
            item.setUseScore(c.getUseScore());
            item.setGainScore(c.getGainScore());
            orderItemService.save(item);
        });

        hbOrderService.createOrderAsync(order.getOrderNumber());
    }

    /**
     * 为手动拆单的子订单分配积分和金额
     */
    private void allocatePointsAndAmountForManualSplit(Order parentOrder, Order subOrder, List<OrderItem> parentOrderItems) {
        // 父订单的总积分和总金额
        Long parentOffsetPoints = parentOrder.getOffsetPoints() != null ? parentOrder.getOffsetPoints() : 0L;
        double parentTotal = parentOrder.getTotal() != null ? parentOrder.getTotal() : 0.0;

        // 计算父订单的商品总金额
        double parentProductAmount = 0.0;
        for (OrderItem item : parentOrderItems) {
            parentProductAmount += item.getPrice() * item.getProdCount();
        }

        // 计算子订单的商品总金额
        double subProductAmount = 0.0;
        for (OrderItem item : subOrder.getOrderItems()) {
            subProductAmount += item.getPrice() * item.getProdCount();
        }

        // 1. 分配积分（按商品金额比例）
        long subPoints = 0L;
        if (parentProductAmount > 0) {
            double ratio = subProductAmount / parentProductAmount;
            subPoints = Math.round(parentOffsetPoints * ratio);
        }
        subOrder.setOffsetPoints(subPoints);

        // 为子订单的订单项分配积分
        allocatePointsToItems(subOrder, subPoints);

        // 2. 分配金额（total和actualTotal）
        BigDecimal subTotal = BigDecimal.ZERO;
        if (parentProductAmount > 0) {
            double ratio = subProductAmount / parentProductAmount;
            subTotal = BigDecimal.valueOf(parentTotal)
                    .multiply(BigDecimal.valueOf(ratio))
                    .setScale(2, BigDecimal.ROUND_DOWN);
        }
        subOrder.setTotal(subTotal.doubleValue());

        // 为子订单的订单项分配金额
        allocateActualTotalToItems(subOrder, parentOrder);

        // 统计子订单的actualTotal（从订单项汇总）
        double orderActualTotal = 0.0;
        for (OrderItem item : subOrder.getOrderItems()) {
            orderActualTotal += (item.getActualTotal() != null ? item.getActualTotal() : 0.0);
        }
        subOrder.setActualTotal(orderActualTotal);

        // 计算商品总数量
        int totalNums = subOrder.getOrderItems().stream().mapToInt(OrderItem::getProdCount).sum();
        subOrder.setProductNums(totalNums);
    }
}