package com.ruoyi.logistics.service.impl;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.datascope.annotation.DataScope;
import com.ruoyi.common.redis.service.RedisIdGenerator;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.front.service.impl.Kuaidi100Service;
import com.ruoyi.logistics.constant.JDDictConstants;
import com.ruoyi.logistics.constant.RedisCacheConstants;
import com.ruoyi.logistics.domain.BizAddressBook;
import com.ruoyi.logistics.domain.BizWaybillCostDetails;
import com.ruoyi.logistics.domain.dto.*;
import com.ruoyi.logistics.domain.SysDeptRate;
import com.ruoyi.logistics.domain.dto.OrderStatisticsDto;
import com.ruoyi.logistics.domain.dto.RecentAddressDto;
import com.ruoyi.logistics.domain.dto.JDOrderDTO;
import com.ruoyi.logistics.enums.OrderStatusEnum;
import com.ruoyi.logistics.mapper.BizAddressBookMapper;
import com.ruoyi.logistics.mapper.BizWaybillCostDetailsMapper;
import com.ruoyi.logistics.service.LogisticsOrderService;
import com.ruoyi.system.api.domain.SysDictData;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.system.mapper.SysDictDataMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.logistics.mapper.BizWaybillOrderMapper;
import com.ruoyi.logistics.domain.BizWaybillOrder;
import com.ruoyi.logistics.service.IBizWaybillOrderService;

/**
 * 运单管理Service业务层处理
 * 
 * @author RuiJing
 * @date 2026-01-29
 */
@Slf4j
@Service
public class BizWaybillOrderServiceImpl implements IBizWaybillOrderService 
{
    @Autowired
    private BizWaybillOrderMapper bizWaybillOrderMapper;
    @Autowired
    LogisticsOrderService logisticsOrderService;

    @Autowired
    private RedisIdGenerator redisIdGenerator;

    @Autowired
    private BizWaybillCostDetailsMapper bizWaybillCostDetailsMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private BizAddressBookMapper bizAddressBookMapper;

    @Autowired
    private SysDeptRateServiceImpl sysDeptRateService;
    @Autowired
    Kuaidi100Service kuaidi100Service;
    @Autowired
    private SysDictDataMapper dictDataMapper;
    /**
     * 查询运单管理
     * 
     * @param waybillId 运单管理主键
     * @return 运单管理
     */
    @Override
    public BizWaybillOrder selectBizWaybillOrderByWaybillId(Long waybillId)
    {

        return bizWaybillOrderMapper.selectBizWaybillOrderByWaybillId(waybillId);
    }

    /**
     * 查询运单管理列表
     * 
     * @param bizWaybillOrder 运单管理
     * @return 运单管理
     */
    @DataScope(deptAlias = "d", userAlias = "u")
    @Override
    public List<BizWaybillOrder> selectBizWaybillOrderList(BizWaybillOrder bizWaybillOrder)
    {
        return bizWaybillOrderMapper.selectBizWaybillOrderList(bizWaybillOrder);
    }

    /**
     * 新增运单管理
     * 
     * @param bizWaybillOrder 运单管理
     * @return 结果
     */
    @Override
    public int insertBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException, JsonProcessingException {

        LoginUser loginUser = SecurityUtils.getLoginUser();
        String orderId = redisIdGenerator.generateUniqueId("RJSD");
        bizWaybillOrder.setWaybillNo(orderId);
        bizWaybillOrder.setOrderStatus(OrderStatusEnum.ORDER_STATUS_1.getCode());
        //前置校验
        JSONObject jsonObject= logisticsOrderService.precheckOrder(bizWaybillOrder);
        if(!jsonObject.getBooleanValue("success")){
            throw new ServiceException("下单前置校验未通过！ 原因:"+jsonObject.getString("msg"));
        }
        JSONObject orderObject= logisticsOrderService.createOrder(bizWaybillOrder);
        if(!orderObject.getBooleanValue("success")){
            throw new ServiceException("下单失败！ 原因:"+orderObject.getString("msg"));
        }
        if(2==bizWaybillOrder.getOrderType()){
            //顺丰物流返回的运单号
            JSONArray waybillNoArray=orderObject.getJSONArray("data");
            for (int i = 0; i < waybillNoArray.size(); i++) {
                JSONObject waybillNoJSONObject = waybillNoArray.getJSONObject(i);
                int waybillType = waybillNoJSONObject.getIntValue("waybillType");
                String  waybillNo = waybillNoJSONObject.getString("waybillNo");
                if(waybillType==1){
                    bizWaybillOrder.setExternalWaybillNo(waybillNo) ;
                }
            }
        }


        bizWaybillOrder.setPickupType(1);
        bizWaybillOrder.setCreateTime(DateUtils.getNowDate());
        bizWaybillOrder.setUserId(loginUser.getUserid());
        bizWaybillOrder.setDeptId(loginUser.getSysUser().getDeptId());
        // 保存寄件地址和收件地址到Redis作为用户最近使用地址
        saveRecentAddresses(bizWaybillOrder, loginUser.getUserid());
        return bizWaybillOrderMapper.insertBizWaybillOrder(bizWaybillOrder);
    }

    /**
     * 修改运单管理
     * 
     * @param bizWaybillOrder 运单管理
     * @return 结果
     */
    @Override
    public int updateBizWaybillOrder(BizWaybillOrder bizWaybillOrder){
        bizWaybillOrder.setUpdateTime(DateUtils.getNowDate());
        return  bizWaybillOrderMapper.updateBizWaybillOrder(bizWaybillOrder);
    }

    /**
     * 批量删除运单管理
     * 
     * @param waybillIds 需要删除的运单管理主键
     * @return 结果
     */
    @Override
    public int deleteBizWaybillOrderByWaybillIds(Long[] waybillIds)
    {
        return bizWaybillOrderMapper.deleteBizWaybillOrderByWaybillIds(waybillIds);
    }

    /**
     * 删除运单管理信息
     * 
     * @param waybillId 运单管理主键
     * @return 结果
     */
    @Override
    public int deleteBizWaybillOrderByWaybillId(Long waybillId)
    {
        return bizWaybillOrderMapper.deleteBizWaybillOrderByWaybillId(waybillId);
    }

    @Override
    public BizWaybillOrder selectBizWaybillOrderByQuery(BizWaybillOrder query) {
        return bizWaybillOrderMapper.selectBizWaybillOrderByQuery(query);
    }

    @Override
    public void updateBizWaybillOrderState(BizWaybillOrder bizWaybillOrder) {
         bizWaybillOrderMapper.updateBizWaybillOrderState(bizWaybillOrder);

    }

    @Override
    public int canceleBizWaybillOrder(BizWaybillOrder bizWaybillOrder) throws UnsupportedEncodingException {
        JSONObject orderObject= logisticsOrderService.cancelOrder(bizWaybillOrder);
        if(!orderObject.getBooleanValue("success")){
            throw new ServiceException(orderObject.getString("msg"));
        }
        bizWaybillOrder.setOrderStatus(6);
        return bizWaybillOrderMapper.canceleBizWaybillOrder(bizWaybillOrder);

    }

    @DataScope(deptAlias = "d", userAlias = "u")
    @Override
    public OrderStatisticsDto getTotalOrdersByOrderType(BizWaybillOrder bizWaybillOrder, BizWaybillCostDetails bizWaybillCostDetails) {
        OrderStatisticsDto orderStatisticsDto = bizWaybillOrderMapper.selectTotalOrdersByOrderType(bizWaybillOrder);
        BigDecimal totalAmount = bizWaybillCostDetailsMapper.selectBizWaybillCostDetailsSum(bizWaybillCostDetails);
        orderStatisticsDto.setTotalAmount(totalAmount);
        return orderStatisticsDto;
    }

    @DataScope(deptAlias = "d", userAlias = "u")
    @Override
    public List<DailyOrderStatisticsDto> getLast7DaysOrderStatistics(BizWaybillOrder bizWaybillOrder) {
        // 获取最近7天的日期范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(14); // 包含今天在内的7天
        bizWaybillOrder.setStartDate(startDate);
        bizWaybillOrder.setEndDate(endDate);
        
        // 查询数据库中指定日期范围的所有数据
        List<DailyOrderStatisticsDto> recentData = bizWaybillOrderMapper.selectLast7DaysOrderStatisticsByDateRange(bizWaybillOrder);

        // 创建一个Map来存储查询结果，以日期为键
        Map<String, DailyOrderStatisticsDto> dataMap = new HashMap<>();
        for (DailyOrderStatisticsDto dto : recentData) {
            String dateStr = DateFormatUtils.format(dto.getStatisticsDate(), "yyyy-MM-dd"); // 假设日期格式为yyyy-MM-dd
            dataMap.put(dateStr, dto);
        }
        
        // 构建完整的7天数据，缺失的日期用0填充
        List<DailyOrderStatisticsDto> result = new ArrayList<>();
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            String dateStr = date.toString();
            if (dataMap.containsKey(dateStr)) {
                result.add(dataMap.get(dateStr));
            } else {
                // 如果当天没有数据，则创建一个全为0的记录
                DailyOrderStatisticsDto emptyDto = new DailyOrderStatisticsDto();
                emptyDto.setStatisticsDate(java.util.Date.from(date.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant()));
                emptyDto.setJdOrderCount(0L);
                emptyDto.setSfOrderCount(0L);
                emptyDto.setTotalOrderCount(0L);
                result.add(emptyDto);
            }
        }
        
        return result;
    }

    /**
     * 保存寄件地址和收件地址到Redis作为用户最近使用地址
     * @param userId 用户ID
     */
    private void saveRecentAddresses(BizWaybillOrder bizWaybillOrder, Long userId) {
        try {
            // 保存寄件地址
            saveRecentAddressToRedis(bizWaybillOrder.getSenderProvince(),
                    bizWaybillOrder.getSenderCity(),
                    bizWaybillOrder.getSenderCounty(),
                    bizWaybillOrder.getSenderAddress(),
                    bizWaybillOrder.getSenderName(),
                    bizWaybillOrder.getSenderPhone(),
                    "sender", userId);
            
            // 保存收件地址
            saveRecentAddressToRedis(bizWaybillOrder.getReceiverProvince(),
                    bizWaybillOrder.getReceiverCity(),
                    bizWaybillOrder.getReceiverCounty(),
                    bizWaybillOrder.getReceiverAddress(),
                    bizWaybillOrder.getReceiverName(),
                    bizWaybillOrder.getReceiverPhone(),
                    "receiver", userId);
        } catch (Exception e) {
            //记录日志但不影响主流程
            log.info("保存最近使用地址到Redis失败: ", e);
        }
    }

    /**
     * 保存单个地址到Redis
     * @param userId 用户ID
     */
    private void saveRecentAddressToRedis(String provinceName, String cityName, String countyName,
                                         String detailedAddress, String contactName, String contactPhone,
                                         String addressType, Long userId) {
        if (provinceName == null || cityName == null || contactName == null || contactPhone == null) {
            return; //基信息不完整，不保存
        }

        BizAddressBook bizAddressBook = new BizAddressBook();
        bizAddressBook.setUserId(userId);
        bizAddressBook.setContactName(contactName);
        bizAddressBook.setContactPhone(contactPhone);
        bizAddressBook.setProvinceName(provinceName);
        bizAddressBook.setCityName(cityName);
        bizAddressBook.setCountyName(countyName);
        bizAddressBook.setDetailedAddress(detailedAddress);

        List<BizAddressBook> bizAddressBooks = bizAddressBookMapper.selectBizAddressBookList(bizAddressBook);
        if (CollectionUtils.isEmpty(bizAddressBooks)) {
            bizAddressBookMapper.insertBizAddressBook(bizAddressBook);
        }
        
        //构造Redis key
        String redisKey = RedisCacheConstants.USER_RECENT_ADDRESS_CACHE_KEY + userId;
        
        // 创建地址对象
        RecentAddressDto addressDto = new RecentAddressDto();
        addressDto.setProvinceName(provinceName);
        addressDto.setCityName(cityName);
        addressDto.setCountyName(countyName);
        addressDto.setDetailedAddress(detailedAddress);
        addressDto.setContactName(contactName);
        addressDto.setContactPhone(contactPhone);

        // 获取当前列表
        List<RecentAddressDto> addressList = redisService.getCacheList(redisKey);
        if (addressList == null) {
            addressList = new ArrayList<>();
        }
        
        //移除相同的地址（如果已存在）
        addressList.removeIf(addr -> 
            addr.getProvinceName().equals(provinceName) &&
            addr.getCityName().equals(cityName) &&
            addr.getCountyName().equals(countyName) &&
            addr.getDetailedAddress().equals(detailedAddress) &&
            addr.getContactName().equals(contactName) &&
            addr.getContactPhone().equals(contactPhone)
        );
        
        //将新地址添加到列表开头
        addressList.add(0, addressDto);
        
        // 保持最多5个地址
        if (addressList.size() > 5) {
            addressList = addressList.subList(0, 5);
        }
        
        // 保存到Redis，设置过期时间30天
        redisService.deleteObject(redisKey);
        redisService.setCacheList(redisKey, addressList);
    }

    @Override
    public JSONObject queryOrderFeeInfo(Integer orderType, String waybillCode) {
        logisticsOrderService.queryOrderFeeInfoByWaybillCode(orderType, waybillCode);
        return null;
    }

    @Override
    public JSONObject queryWaybillPdf(BizWaybillOrder bizWaybillOrder) {
        JSONObject jsonObject = logisticsOrderService.queryWaybillPdf(bizWaybillOrder);
        if (jsonObject.getBoolean("success")) {
            if(1==bizWaybillOrder.getOrderType()) {
                bizWaybillOrder.setPdfUrl(jsonObject.getString("url"));
                bizWaybillOrderMapper.updateBizWaybillOrder(bizWaybillOrder);
            }
        }
        return jsonObject;
    }

    /**
     * 批量下单
     *
     * @param orderList 订单列表
     * @param orderType 订单类型 1-京东，2-顺丰
     * @return 结果数组，每个元素表示对应订单的结果 [0:成功数，1:失败数]
     */
    @Override
    public int batchInsertJDBizWaybillOrder(List<JDOrderDTO> orderList, Integer orderType) {
        int failCount = 0;
        List<String> errorMessages = new ArrayList<>();

        LoginUser loginUser = SecurityUtils.getLoginUser();

        SysDeptRate sysDeptRate = new SysDeptRate();
        sysDeptRate.setDeptId(loginUser.getSysUser().getDeptId());
        List<SysDeptRate> sysDeptRates = sysDeptRateService.selectSysDeptRateList(sysDeptRate);
        Set<String> collect = sysDeptRates.stream().map(SysDeptRate::getProductType).collect(Collectors.toSet());

        List<BizWaybillOrder> bizWaybillOrders = new ArrayList<>();
        for (int i = 0; i < orderList.size(); i++) {
            JDOrderDTO dto = orderList.get(i);
            int row = i + 2; // 行号从1开始
            try {
                preDataVerify(dto, collect);

                // 将 JDOrderDTO 转换为 BizWaybillOrder
                BizWaybillOrder bizWaybillOrder = convertToBizWaybillOrder(dto, loginUser);
                String orderId = redisIdGenerator.generateUniqueId("RJSD");
                bizWaybillOrder.setWaybillNo(orderId);
                bizWaybillOrder.setOrderStatus(OrderStatusEnum.ORDER_STATUS_1.getCode());

                // 前置校验
                String senderProvince = bizWaybillOrder.getSenderProvince();
                String senderCity = bizWaybillOrder.getSenderCity();
                String senderCounty = bizWaybillOrder.getSenderCounty();
                String receiverProvince = bizWaybillOrder.getReceiverProvince();
                String receiverCity = bizWaybillOrder.getReceiverCity();
                String receiverCounty = bizWaybillOrder.getReceiverCounty();

                bizWaybillOrder.setSenderProvince("");
                bizWaybillOrder.setSenderCity("");
                bizWaybillOrder.setSenderCounty("");
                bizWaybillOrder.setReceiverProvince("");
                bizWaybillOrder.setReceiverCity("");
                bizWaybillOrder.setReceiverCounty("");

                JSONObject jsonObject = logisticsOrderService.precheckOrder(bizWaybillOrder);
                if (!jsonObject.getBooleanValue("success")) {
                    log.warn("订单前置校验未通过！发件人:{}, 收件人:{}, 原因:{}",
                            dto.getSenderName(), dto.getReceiverName(), jsonObject.getString("msg"));
                    throw new ServiceException(jsonObject.getString("msg"));
                }

                bizWaybillOrder.setSenderProvince(senderProvince);
                bizWaybillOrder.setSenderCity(senderCity);
                bizWaybillOrder.setSenderCounty(senderCounty);
                bizWaybillOrder.setReceiverProvince(receiverProvince);
                bizWaybillOrder.setReceiverCity(receiverCity);
                bizWaybillOrder.setReceiverCounty(receiverCounty);

                // 设置默认值
                bizWaybillOrder.setPickupType(1);
                bizWaybillOrder.setCreateTime(DateUtils.getNowDate());
                bizWaybillOrder.setUserId(loginUser.getUserid());
                bizWaybillOrder.setDeptId(loginUser.getSysUser().getDeptId());

                bizWaybillOrders.add(bizWaybillOrder);
            } catch (Exception e) {
                log.error("批量下单异常！发件人:{}, 收件人:{}", 
                    dto.getSenderName(), dto.getReceiverName(), e);
                failCount++;
                errorMessages.add(String.format("第 %s 行订单 %s-%s 异常：%s",
                    row, dto.getSenderName(), dto.getReceiverName(), e.getMessage()));
            }
        }

        if (failCount > 0) {
            throw new ServiceException("批量下单失败！失败原因：" + StringUtils.join(errorMessages, "\n"));
        }

        jdOrderImport(bizWaybillOrders);
        return bizWaybillOrders.size();
    }

    @Async
    public  void jdOrderImport(List<BizWaybillOrder> bizWaybillOrders) {
        String batchNum = redisIdGenerator.generateUniqueId("JDPC");

        int successCount = 0;
        int failCount = 0;
        List<String> errorMessages = new ArrayList<>();
        for (BizWaybillOrder dto : bizWaybillOrders) {
            try {
                // 调用下单接口
                JSONObject orderObject = logisticsOrderService.createOrder(dto);
                if (!orderObject.getBooleanValue("success")) {
                    log.warn("下单失败！发件人:{}, 收件人:{}, 原因:{}",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg"));
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 下单失败：%s",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg")));
                    continue;
                }

                dto.setBatchNum(batchNum);
                // 保存到数据库
                int result = bizWaybillOrderMapper.insertBizWaybillOrder(dto);
                if (result > 0) {
                    successCount++;
                    // 保存最近使用地址
                    saveRecentAddresses(dto, dto.getUserId());
                } else {
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 保存失败",
                            dto.getSenderName(), dto.getReceiverName()));
                }
            } catch (Exception e) {
                log.error("批量下单异常！发件人:{}, 收件人:{}",
                        dto.getSenderName(), dto.getReceiverName(), e);
                failCount++;
                errorMessages.add(String.format("订单 %s-%s 异常：%s",
                        dto.getSenderName(), dto.getReceiverName(), e.getMessage()));
            }
        }
        log.info("批量下单完成！总数:{}, 成功:{}, 失败:{}", bizWaybillOrders.size(), successCount, failCount);
    }

    private void preDataVerify(JDOrderDTO dto, Set<String> collect) {
        StringBuilder errorMsg = new StringBuilder();
        if (dto == null) {
            errorMsg.append("订单数据不能为空");
            return;
        }

        // 校验寄件人信息
        if (StringUtils.isBlank(dto.getSenderName())) {
            errorMsg.append("寄件人姓名不能为空;");
        }
        if (StringUtils.isBlank(dto.getSenderPhone())) {
            errorMsg.append("寄件人电话不能为空;");
        }
        if (StringUtils.isBlank(dto.getSenderAddress())) {
            errorMsg.append("寄件详细地址不能为空;");
        }

        Map param = new HashMap();
        param.put("param", dto.getSenderAddress());
        try {
            Map result = kuaidi100Service.queryIcrExpres(param);
            Map<String, Object> receiverData = (Map<String, Object>) result.get("data");
            List<Map<String, Object>> receiverResultList = (List<Map<String, Object>>) receiverData.get("result");
            Map<String, Object> receiverResult = receiverResultList.get(0);
            Map<String, Object> receiverXzq = (Map<String, Object>) receiverResult.get("xzq");
            // 从 fullName 拆分 省,市,区
            String receiverFullName = (String) receiverXzq.get("fullName");
            String[] receiverSplit = receiverFullName.split(",");
            String receiverProvince = receiverSplit[0];
            String receiverCity = receiverSplit[1];
            String receiverDistrict = receiverSplit[2];
            dto.setSenderProvince(receiverProvince);
            dto.setSenderCity(receiverCity);
            dto.setSenderCounty(receiverDistrict);
        } catch (Exception e) {
            errorMsg.append("寄件详细地址识别有误;");
        }

        // 校验收件人信息
        if (StringUtils.isBlank(dto.getReceiverName())) {
            errorMsg.append("收件人姓名不能为空;");
        }
        if (StringUtils.isBlank(dto.getReceiverPhone())) {
            errorMsg.append("收件人电话不能为空;");
        }
        if (StringUtils.isBlank(dto.getReceiverAddress())) {
            errorMsg.append("收件详细地址不能为空;");
        }
        param.put("param", dto.getReceiverAddress());
        try {
            Map result = kuaidi100Service.queryIcrExpres(param);
            Map<String, Object> receiverData = (Map<String, Object>) result.get("data");
            List<Map<String, Object>> receiverResultList = (List<Map<String, Object>>) receiverData.get("result");
            Map<String, Object> receiverResult = receiverResultList.get(0);
            Map<String, Object> receiverXzq = (Map<String, Object>) receiverResult.get("xzq");
            // 从 fullName 拆分 省,市,区
            String receiverFullName = (String) receiverXzq.get("fullName");
            String[] receiverSplit = receiverFullName.split(",");
            String receiverProvince = receiverSplit[0];
            String receiverCity = receiverSplit[1];
            String receiverDistrict = receiverSplit[2];
            dto.setReceiverProvince(receiverProvince);
            dto.setReceiverCity(receiverCity);
            dto.setReceiverCounty(receiverDistrict);
        } catch (Exception e) {
            errorMsg.append("收件详细地址识别有误;");
        }

        // 校验货物信息
        if (StringUtils.isBlank(dto.getGoodsName())) {
            errorMsg.append("物品名称不能为空;");
        }
        if (dto.getGoodsWeight() == null) {
            errorMsg.append("物品重量不能为空;");
        }
        if (dto.getGoodsVolume() == null) {
            errorMsg.append("物品体积不能为空;");
        }
        if (dto.getGoodsQty() == null) {
            errorMsg.append("物品数量不能为空;");
        }

        // 校验取件时间
//        if (dto.getSendStartTime() == null || dto.getSendEndTime() == null) {
//            errorMsg.append("上门取件开始时间和结束时间不能为空;");
//        }
//        try {
//            dto.setPickupStartTime(DateUtils.parseDate(dto.getSendStartTime(), "yyyy-MM-dd HH:mm:ss"));
//        } catch (ParseException e) {
//            errorMsg.append("上门取件开始时间格式不正确");
//        }
//        try {
//            dto.setPickupEndTime(DateUtils.parseDate(dto.getSendEndTime(), "yyyy-MM-dd HH:mm:ss"));
//        } catch (ParseException e) {
//            errorMsg.append("上门取件开始时间格式不正确");
//        }
//        if (dto.getPickupStartTime().getTime() > dto.getPickupEndTime().getTime()) {
//            errorMsg.append("上门取件开始时间不能大于上门取件结束时间;");
//        }

        // 校验产品类型
        if (StringUtils.isBlank(dto.getProductCode())) {
            errorMsg.append("产品类型不能为空;");
        }
        dto.setProductCode(getProductCode(dto.getProductCode()));
        if (!collect.contains(dto.getProductCode())) {
            errorMsg.append("产品类型不存在;");
        }

        // 校验附加服务
        if (null != dto.getIsPack() && !"是".equals(dto.getIsPack()) && !"否".equals(dto.getIsPack())) {
            errorMsg.append("包装服务参数有误;");
        }
        if (null != dto.getIsReceiptCollect() && !"是".equals(dto.getIsReceiptCollect()) && !"否".equals(dto.getIsReceiptCollect())) {
            errorMsg.append("签单返还参数有误;");
        }
        if (null != dto.getGuaranteeMoney() && dto.getGuaranteeMoney().compareTo(new BigDecimal("0")) <= 0) {
            errorMsg.append("保价金额不能小于等于0;");
        }
        dto.setAddedService(getAddedService(dto));

        if (StringUtils.isNotBlank(errorMsg)) {
            throw new ServiceException(errorMsg.toString());
        }
    }
    @Async
    @Override
    public void asyncBatchInsert(List<BizWaybillOrder> orderList, Integer orderType) {
        String batchNum = redisIdGenerator.generateUniqueId("SFPC");

        int successCount = 0;
        int failCount = 0;
        List<String> errorMessages = new ArrayList<>();
        List<BizWaybillOrder> failList= new ArrayList<>();
        for (BizWaybillOrder dto : orderList) {
            try {
                //还需要校验一下收件地址寄件地址的省市区信息是否合规
                // ===================== 解析 发件地址 省市区 =====================
                Map<String, Object> senderParam = new HashMap<>();
                senderParam.put("param", dto.getSenderAddress());
                Map<String, Object> senderResultMap = kuaidi100Service.queryIcrExpres(senderParam);
                Map<String, Object> senderData = (Map<String, Object>) senderResultMap.get("data");
                List<Map<String, Object>> senderResultList = (List<Map<String, Object>>) senderData.get("result");
                Map<String, Object> senderResult = senderResultList.get(0);
                Map<String, Object> senderXzq = (Map<String, Object>) senderResult.get("xzq");
                // 从 fullName 拆分 省,市,区
                String senderFullName = (String) senderXzq.get("fullName");
                String[] senderSplit = senderFullName.split(",");
                String senderProvince = senderSplit[0];
                String senderCity = senderSplit[1];
                String senderDistrict = senderSplit[2];
                dto.setSenderProvince(senderProvince);
                dto.setSenderCity(senderCity);
                dto.setSenderCounty(senderDistrict);
                // ===================== 解析 收件地址 省市区 =====================
                Map<String, Object> receiverParam = new HashMap<>();
                receiverParam.put("param", dto.getReceiverAddress());
                Map<String, Object> receiverResultMap = kuaidi100Service.queryIcrExpres(receiverParam);
                Map<String, Object> receiverData = (Map<String, Object>) receiverResultMap.get("data");
                List<Map<String, Object>> receiverResultList = (List<Map<String, Object>>) receiverData.get("result");
                Map<String, Object> receiverResult = receiverResultList.get(0);
                Map<String, Object> receiverXzq = (Map<String, Object>) receiverResult.get("xzq");
                // 从 fullName 拆分 省,市,区
                String receiverFullName = (String) receiverXzq.get("fullName");
                String[] receiverSplit = receiverFullName.split(",");
                String receiverProvince = receiverSplit[0];
                String receiverCity = receiverSplit[1];
                String receiverDistrict = receiverSplit[2];
                dto.setReceiverProvince(receiverProvince);
                dto.setReceiverCity(receiverCity);
                dto.setReceiverCounty(receiverDistrict);

                // 调用下单接口
                JSONObject orderObject = logisticsOrderService.createOrder(dto);
                if (!orderObject.getBooleanValue("success")) {
                    log.warn("下单失败！发件人:{}, 收件人:{}, 原因:{}",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg"));
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 下单失败：%s",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg")));
                    failList.add(dto);
                    continue;
                }
                //顺丰物流返回的运单号
                JSONArray waybillNoArray=orderObject.getJSONArray("data");
                for (int i = 0; i < waybillNoArray.size(); i++) {
                    JSONObject waybillNoJSONObject = waybillNoArray.getJSONObject(i);
                    int waybillType = waybillNoJSONObject.getIntValue("waybillType");
                    String  waybillNo = waybillNoJSONObject.getString("waybillNo");
                    if(waybillType==1){
                        dto.setExternalWaybillNo(waybillNo) ;
                    }
                }
                // 设置默认值
                dto.setPickupType(1);
                dto.setCreateTime(DateUtils.getNowDate());
                dto.setBatchNum(batchNum);
                dto.setOrderStatus(OrderStatusEnum.ORDER_STATUS_1.getCode());
                // 保存到数据库
                int result = bizWaybillOrderMapper.insertBizWaybillOrder(dto);
                if (result > 0) {
                    successCount++;
                    // 保存最近使用地址
                    saveRecentAddresses(dto, dto.getUserId());
                } else {
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 保存失败",
                            dto.getSenderName(), dto.getReceiverName()));
                }
            } catch (Exception e) {
                log.error("批量下单异常！发件人:{}, 收件人:{}",
                        dto.getSenderName(), dto.getReceiverName(), e);
                failCount++;
                errorMessages.add(String.format("订单 %s-%s 异常：%s",
                        dto.getSenderName(), dto.getReceiverName(), e.getMessage()));
            }
        }
        log.info("批量下单完成！总数:{}, 成功:{}, 失败:{}", orderList.size(), successCount, failCount);

    }

    @Override
    public Map<String,Object> validateAndGetError(List<SfOrderImportDTO> orderList) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Map<String,Object> result= new HashMap<>();
        //先把类型拿出来
        Map productParam= new HashMap<>();
        productParam.put("dictType","sf_logistics_product_code");
        productParam.put("companyType","2");
        productParam.put("deptId",loginUser.getSysUser().getDeptId());
        List<SysDictData> allProductDictList = dictDataMapper.selectDictDataSfProductList(productParam);
       // 转成 Map：label -> value，方便快速查找
       Map<String, String> productMap = allProductDictList.stream()
                .collect(Collectors.toMap(
                        SysDictData::getDictLabel,
                        SysDictData::getDictValue,
                        (existing, replacement) -> existing // 重复 label 保留第一个
                ));

        // ===================== 并行校验（线程安全，行号正确） =====================
        List<Map<String, Object>> errorList = Collections.synchronizedList(new ArrayList<>());
        List<BizWaybillOrder> successList = Collections.synchronizedList(new ArrayList<>());


        IntStream.range(0, orderList.size()).parallel().forEach(i -> {
            SfOrderImportDTO vo = orderList.get(i);
            int row = i + 2; // 行号完全正确
            List<String> rowErrors = new ArrayList<>();
            try {
                if (StringUtils.isBlank(vo.getSenderPhone())) {
                    rowErrors.add("寄件人手机号不能为空");
                }
                if (StringUtils.isBlank(vo.getReceiverPhone())) {
                    rowErrors.add("收件人手机号不能为空");
                }
                if (StringUtils.isBlank(vo.getReceiverPhone()) || !vo.getReceiverPhone().matches("1[3-9]\\d{9}")) {
                    rowErrors.add("收件人手机号格式不正确");
                }
                if (StringUtils.isBlank(vo.getSenderPhone()) || !vo.getSenderPhone().matches("1[3-9]\\d{9}")) {
                    rowErrors.add("寄件人手机号格式不正确");
                }
                if (StringUtils.isBlank(vo.getReceiverAddress())) {
                    rowErrors.add("收件地址不能为空");
                }
                if (StringUtils.isBlank(vo.getSenderAddress())) {
                    rowErrors.add("寄件地址不能为空");
                }
                if (StringUtils.isBlank(vo.getGoodsName())) {
                    rowErrors.add("物品名称不能为空");
                }
                // 货物重量校验
                BigDecimal weight = vo.getGoodsWeight();
                if (weight == null||weight.compareTo(BigDecimal.ZERO) <= 0) {
                    rowErrors.add("货物重量不能为空，且必须输入大于0的有效数字");
                }
                // 货物体积
                BigDecimal volume = vo.getGoodsVolume();
                if (volume == null||volume.compareTo(BigDecimal.ZERO) <= 0) {
                    rowErrors.add("货物体积不能为空，且必须输入大于0的有效数字");
                }
                Long goodsQty = vo.getGoodsQty();
                if (goodsQty == null || goodsQty <= 0) {
                    rowErrors.add("货物数量不能为空，且必须输入大于0的有效数字");
                }
                String productLabel = vo.getProductCode();
                if (!StringUtils.hasText(productLabel)) {
                    rowErrors.add("产品类型不能为空");
                }

                String productCode = productMap.get(productLabel);
                if (productCode == null) {
                    rowErrors.add("产品类型【" + productLabel + "】不存在，请检查填写是否正确");
                }
                vo.setProductCode(productCode);
                if (!rowErrors.isEmpty()) {
                    Map<String, Object> errorMap = new HashMap<>();
                    errorMap.put("row", row);
                    errorMap.put("msg", String.join("，", rowErrors));
                    errorList.add(errorMap);
                    return;
                }

                //这里拿到生成的id进行前置校验用 如果全部通过的时候  这个还需要用到
                String orderId = redisIdGenerator.generateUniqueId("RJSD");
                vo.setWaybillNo(orderId);
                //全部校验完后在进行  下单前置校验
                BizWaybillOrder bizWaybillOrder = convertToSFBizWaybillOrder(vo, loginUser);
                JSONObject jsonObject = logisticsOrderService.precheckOrder(bizWaybillOrder);
                if (!jsonObject.getBooleanValue("success")) {
                    log.warn("订单前置校验未通过！发件人:{}, 收件人:{}, 原因:{}",
                            vo.getSenderName(), vo.getReceiverName(), jsonObject.getString("msg"));
                    Map<String, Object> errorMap = new HashMap<>();
                    errorMap.put("row", row);
                    errorMap.put("msg", "订单前置校验未通过 原因：" + jsonObject.getString("msg"));
                    errorList.add(errorMap);
                    return;
                }
                successList.add(bizWaybillOrder);
            } catch (Exception e) {
                Map<String, Object> errorMap = new HashMap<>();
                errorMap.put("row", row);
                errorMap.put("msg", "系统异常：" + e.getMessage());
                errorList.add(errorMap);
                log.error("第{}行校验异常", row, e);
            }



        });
        List<Map<String, Object>> sortedErrors = errorList.stream()
                .sorted(Comparator.comparingInt(m -> (Integer) m.get("row")))
                .collect(Collectors.toList());


        StringBuilder errorMsg = new StringBuilder();
        for (Map<String, Object> map : sortedErrors) {
            errorMsg.append("第").append(map.get("row")).append("行：")
                    .append(map.get("msg")).append("<br/>");
        }

        result.put("errorMsg", errorMsg.toString());
        result.put("orderList", successList); // 注意：你之前是 orederList 拼写错误
        return result;
    }

    @Override
    public Map<String, Object> validateAndGetErrorJd(List<JDOrderDTO> orderList) {
        {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            Map<String,Object> result= new HashMap<>();
            //先把类型拿出来
            Map productParam= new HashMap<>();
            productParam.put("dictType","jd_logistics_product_code");
            productParam.put("companyType","1");
            productParam.put("deptId",loginUser.getSysUser().getDeptId());
            List<SysDictData> allProductDictList = dictDataMapper.selectDictDataSfProductList(productParam);
            // 转成 Map：label -> value，方便快速查找
            Map<String, String> productMap = allProductDictList.stream()
                    .collect(Collectors.toMap(
                            SysDictData::getDictLabel,
                            SysDictData::getDictValue,
                            (existing, replacement) -> existing // 重复 label 保留第一个
                    ));

            // ===================== 并行校验（线程安全，行号正确） =====================
            List<Map<String, Object>> errorList = Collections.synchronizedList(new ArrayList<>());
            List<BizWaybillOrder> successList = Collections.synchronizedList(new ArrayList<>());


            IntStream.range(0, orderList.size()).parallel().forEach(i -> {
                JDOrderDTO vo = orderList.get(i);
                int row = i + 2; // 行号完全正确
                List<String> rowErrors = new ArrayList<>();
                try {

                    if (StringUtils.isBlank(vo.getReceiverPhone()) || !vo.getReceiverPhone().matches("1[3-9]\\d{9}")) {
                        rowErrors.add("收件人手机号为空或格式不正确");
                    }
                    if (StringUtils.isBlank(vo.getSenderPhone()) || !vo.getSenderPhone().matches("1[3-9]\\d{9}")) {
                        rowErrors.add("寄件人手机号为空或格式不正确");
                    }
                    if (StringUtils.isBlank(vo.getReceiverAddress())) {
                        rowErrors.add("收件地址不能为空");
                    }
                    if (StringUtils.isBlank(vo.getSenderAddress())) {
                        rowErrors.add("寄件地址不能为空");
                    }
                    if (StringUtils.isBlank(vo.getGoodsName())) {
                        rowErrors.add("物品名称不能为空");
                    }
                    // 货物重量校验
                    BigDecimal weight = vo.getGoodsWeight();
                    if (weight == null||weight.compareTo(BigDecimal.ZERO) <= 0) {
                        rowErrors.add("货物重量不能为空，且必须输入大于0的有效数字");
                    }
                    // 货物体积
                    BigDecimal volume = vo.getGoodsVolume();
                    if (volume == null||volume.compareTo(BigDecimal.ZERO) <= 0) {
                        rowErrors.add("货物体积不能为空，且必须输入大于0的有效数字");
                    }
                    Long goodsQty = vo.getGoodsQty();
                    if (goodsQty == null || goodsQty <= 0) {
                        rowErrors.add("货物数量不能为空，且必须输入大于0的有效数字");
                    }
                    String productLabel = vo.getProductCode();
                    if (!StringUtils.hasText(productLabel)) {
                        rowErrors.add("产品类型不能为空");
                    }

                    String productCode = productMap.get(productLabel);
                    if (productCode == null) {
                        rowErrors.add("产品类型【" + productLabel + "】不存在，请检查填写是否正确");
                    }

                    if (null != vo.getIsPack() && !"是".equals(vo.getIsPack()) && !"否".equals(vo.getIsPack())) {
                        rowErrors.add("包装服务参数有误;");
                    }
                    if (null != vo.getIsReceiptCollect() && !"是".equals(vo.getIsReceiptCollect()) && !"否".equals(vo.getIsReceiptCollect())) {
                        rowErrors.add("签单返还参数有误;");
                    }
                    if (null != vo.getGuaranteeMoney() && vo.getGuaranteeMoney().compareTo(new BigDecimal("0")) <= 0) {
                        rowErrors.add("保价金额不能小于等于0;");
                    }
                    vo.setAddedService(getAddedService(vo));
                    vo.setProductCode(productCode);
                    if (!rowErrors.isEmpty()) {
                        Map<String, Object> errorMap = new HashMap<>();
                        errorMap.put("row", row);
                        errorMap.put("msg", String.join("，", rowErrors));
                        errorList.add(errorMap);
                        return;
                    }

                    BizWaybillOrder bizWaybillOrder = convertToBizWaybillOrder(vo, loginUser);
                    String orderId = redisIdGenerator.generateUniqueId("RJSD");
                    bizWaybillOrder.setWaybillNo(orderId);
                    bizWaybillOrder.setOrderStatus(OrderStatusEnum.ORDER_STATUS_1.getCode());

                    // 前置校验
                    bizWaybillOrder.setSenderProvince("");
                    bizWaybillOrder.setSenderCity("");
                    bizWaybillOrder.setSenderCounty("");
                    bizWaybillOrder.setReceiverProvince("");
                    bizWaybillOrder.setReceiverCity("");
                    bizWaybillOrder.setReceiverCounty("");

                    JSONObject jsonObject = logisticsOrderService.precheckOrder(bizWaybillOrder);
                    if (!jsonObject.getBooleanValue("success")) { log.warn("订单前置校验未通过！发件人:{}, 收件人:{}, 原因:{}",
                            vo.getSenderName(), vo.getReceiverName(), jsonObject.getString("msg"));
                        Map<String, Object> errorMap = new HashMap<>();
                        errorMap.put("row", row);
                        errorMap.put("msg", "订单前置校验未通过 原因：" + jsonObject.getString("msg"));
                        errorList.add(errorMap);
                        return;
                    }
                    successList.add(bizWaybillOrder);
                } catch (Exception e) {
                    Map<String, Object> errorMap = new HashMap<>();
                    errorMap.put("row", row);
                    errorMap.put("msg", "系统异常：" + e.getMessage());
                    errorList.add(errorMap);
                    log.error("第{}行校验异常", row, e);
                }
            });
            List<Map<String, Object>> sortedErrors = errorList.stream()
                    .sorted(Comparator.comparingInt(m -> (Integer) m.get("row")))
                    .collect(Collectors.toList());


            StringBuilder errorMsg = new StringBuilder();
            for (Map<String, Object> map : sortedErrors) {
                errorMsg.append("第").append(map.get("row")).append("行：")
                        .append(map.get("msg")).append("<br/>");
            }

            result.put("errorMsg", errorMsg.toString());
            result.put("orderList", successList); // 注意：你之前是 orederList 拼写错误
            return result;
        }
    }

    @Async
    @Override
    public void asyncBatchInsertJd(List<BizWaybillOrder> orderList, Integer orderType) {
        String batchNum = redisIdGenerator.generateUniqueId("JDPC");

        int successCount = 0;
        int failCount = 0;
        List<String> errorMessages = new ArrayList<>();
        List<BizWaybillOrder> failList= new ArrayList<>();
        for (BizWaybillOrder dto : orderList) {
            try {
                //还需要校验一下收件地址寄件地址的省市区信息是否合规
                // ===================== 解析 发件地址 省市区 =====================
                Map<String, Object> senderParam = new HashMap<>();
                senderParam.put("param", dto.getSenderAddress());
                Map<String, Object> senderResultMap = kuaidi100Service.queryIcrExpres(senderParam);
                Map<String, Object> senderData = (Map<String, Object>) senderResultMap.get("data");
                List<Map<String, Object>> senderResultList = (List<Map<String, Object>>) senderData.get("result");
                Map<String, Object> senderResult = senderResultList.get(0);
                Map<String, Object> senderXzq = (Map<String, Object>) senderResult.get("xzq");
                // 从 fullName 拆分 省,市,区
                String senderFullName = (String) senderXzq.get("fullName");
                String[] senderSplit = senderFullName.split(",");
                String senderProvince = senderSplit[0];
                String senderCity = senderSplit[1];
                String senderDistrict = senderSplit[2];
                dto.setSenderProvince(senderProvince);
                dto.setSenderCity(senderCity);
                dto.setSenderCounty(senderDistrict);
                // ===================== 解析 收件地址 省市区 =====================
                Map<String, Object> receiverParam = new HashMap<>();
                receiverParam.put("param", dto.getReceiverAddress());
                Map<String, Object> receiverResultMap = kuaidi100Service.queryIcrExpres(receiverParam);
                Map<String, Object> receiverData = (Map<String, Object>) receiverResultMap.get("data");
                List<Map<String, Object>> receiverResultList = (List<Map<String, Object>>) receiverData.get("result");
                Map<String, Object> receiverResult = receiverResultList.get(0);
                Map<String, Object> receiverXzq = (Map<String, Object>) receiverResult.get("xzq");
                // 从 fullName 拆分 省,市,区
                String receiverFullName = (String) receiverXzq.get("fullName");
                String[] receiverSplit = receiverFullName.split(",");
                String receiverProvince = receiverSplit[0];
                String receiverCity = receiverSplit[1];
                String receiverDistrict = receiverSplit[2];
                dto.setReceiverProvince(receiverProvince);
                dto.setReceiverCity(receiverCity);
                dto.setReceiverCounty(receiverDistrict);

                // 调用下单接口
                JSONObject orderObject = logisticsOrderService.createOrder(dto);
                if (!orderObject.getBooleanValue("success")) {
                    log.warn("下单失败！发件人:{}, 收件人:{}, 原因:{}",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg"));
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 下单失败：%s",
                            dto.getSenderName(), dto.getReceiverName(), orderObject.getString("msg")));
                    failList.add(dto);
                    continue;
                }

                // 设置默认值
                dto.setPickupType(1);
                dto.setCreateTime(DateUtils.getNowDate());
                dto.setBatchNum(batchNum);
                dto.setOrderStatus(OrderStatusEnum.ORDER_STATUS_1.getCode());
                dto.setWaybillNo(redisIdGenerator.generateUniqueId("RJSD"));
                // 保存到数据库
                int result = bizWaybillOrderMapper.insertBizWaybillOrder(dto);
                if (result > 0) {
                    successCount++;
                    // 保存最近使用地址
                    saveRecentAddresses(dto, dto.getUserId());
                } else {
                    failCount++;
                    errorMessages.add(String.format("订单 %s-%s 保存失败",
                            dto.getSenderName(), dto.getReceiverName()));
                }
            } catch (Exception e) {
                log.error("批量下单异常！发件人:{}, 收件人:{}",
                        dto.getSenderName(), dto.getReceiverName(), e);
                failCount++;
                errorMessages.add(String.format("订单 %s-%s 异常：%s",
                        dto.getSenderName(), dto.getReceiverName(), e.getMessage()));
            }
        }
        log.info("批量下单完成！总数:{}, 成功:{}, 失败:{}", orderList.size(), successCount, failCount);


    }

    /**
     * 将 SfOrderImportDTO 转换为 BizWaybillOrder
     */

    private BizWaybillOrder convertToSFBizWaybillOrder(SfOrderImportDTO dto, LoginUser loginUser) {

        BizWaybillOrder bizWaybillOrder = new BizWaybillOrder();
        // 设置订单类型
        bizWaybillOrder.setOrderType(2);
        bizWaybillOrder.setWaybillNo(dto.getWaybillNo());
        // 寄件人信息
        bizWaybillOrder.setSenderName(dto.getSenderName());
        bizWaybillOrder.setSenderPhone(dto.getSenderPhone());
        bizWaybillOrder.setSenderProvince(dto.getSenderProvince());
        bizWaybillOrder.setSenderCity(dto.getSenderCity());
        bizWaybillOrder.setSenderCounty(dto.getSenderCounty());
        bizWaybillOrder.setSenderAddress(dto.getSenderAddress());
        //收件人信息
        bizWaybillOrder.setReceiverName(dto.getReceiverName());
        bizWaybillOrder.setReceiverPhone(dto.getReceiverPhone());
        bizWaybillOrder.setReceiverProvince(dto.getReceiverProvince());
        bizWaybillOrder.setReceiverCity(dto.getReceiverCity());
        bizWaybillOrder.setReceiverCounty(dto.getReceiverCounty());
        bizWaybillOrder.setReceiverAddress(dto.getReceiverAddress());
        // 货物信息
        bizWaybillOrder.setGoodsName(dto.getGoodsName());
        bizWaybillOrder.setGoodsWeight(dto.getGoodsWeight());
        bizWaybillOrder.setGoodsVolume(dto.getGoodsVolume());
        bizWaybillOrder.setGoodsQty(dto.getGoodsQty());
        // 取件时间
        bizWaybillOrder.setSendStartTime(dto.getSendStartTime());
        //结束时间需要计算出来

        LocalDateTime now = LocalDateTime.now();
       // 先整点归零
        LocalDateTime hourStart = now.withMinute(0).withSecond(0).withNano(0);
       // 下一个整点
        LocalDateTime nextHour = hourStart.plusHours(1);
        // 结束再+1
        LocalDateTime endHour = nextHour.plusHours(1);
        // 转Date给你原有字段用
        Date startTime = Date.from(nextHour.atZone(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(endHour.atZone(ZoneId.systemDefault()).toInstant());
        bizWaybillOrder.setSendStartTime(startTime);
        bizWaybillOrder.setSendEndTime(endTime);
        // 产品信息和增值服务
        bizWaybillOrder.setProductCode(dto.getProductCode());



        // 2. 构建保价 JSON 格式
        Map<String, Object> serviceMap = new HashMap<>();
        serviceMap.put("isPack", null);                // 固定 null 顺丰没有现在
        serviceMap.put("guaranteeMoney", dto.getProtecPrice()); // 赋值 Excel 里的报价金额
        serviceMap.put("isReceiptCollect", null);     // 固定 null   顺丰没有现在

        // 3. 转成 JSON 字符串（如果需要存库）
        String serviceJson = JSON.toJSONString(serviceMap);

        // 4. 赋值给你的实体（你自己对应字段）
        bizWaybillOrder.setAddedService(serviceJson);


        bizWaybillOrder.setDeptId(loginUser.getSysUser().getDeptId());
        bizWaybillOrder.setUserId(loginUser.getUserid());



        return bizWaybillOrder;

    }

    /**
     * 将 JDOrderDTO 转换为 BizWaybillOrder
     */
    private BizWaybillOrder convertToBizWaybillOrder(JDOrderDTO dto, LoginUser loginUser) {
        BizWaybillOrder bizWaybillOrder = new BizWaybillOrder();
        
        // 设置订单类型
        bizWaybillOrder.setOrderType(1);
        
        // 复制基本信息
        bizWaybillOrder.setSenderName(dto.getSenderName());
        bizWaybillOrder.setSenderPhone(dto.getSenderPhone());
        bizWaybillOrder.setSenderProvince(dto.getSenderProvince());
        bizWaybillOrder.setSenderCity(dto.getSenderCity());
        bizWaybillOrder.setSenderCounty(dto.getSenderCounty());
        bizWaybillOrder.setSenderAddress(dto.getSenderAddress());
        
        bizWaybillOrder.setReceiverName(dto.getReceiverName());
        bizWaybillOrder.setReceiverPhone(dto.getReceiverPhone());
        bizWaybillOrder.setReceiverProvince(dto.getReceiverProvince());
        bizWaybillOrder.setReceiverCity(dto.getReceiverCity());
        bizWaybillOrder.setReceiverCounty(dto.getReceiverCounty());
        bizWaybillOrder.setReceiverAddress(dto.getReceiverAddress());
        
        // 货物信息
        bizWaybillOrder.setGoodsName(dto.getGoodsName());
        bizWaybillOrder.setGoodsWeight(dto.getGoodsWeight());
        bizWaybillOrder.setGoodsVolume(dto.getGoodsVolume());
        bizWaybillOrder.setGoodsQty(dto.getGoodsQty());
        
        // 取件时间
        //结束时间需要计算出来
        LocalDateTime now = LocalDateTime.now();
        // 先整点归零
        LocalDateTime hourStart = now.withMinute(0).withSecond(0).withNano(0);
        // 下一个整点
        LocalDateTime nextHour = hourStart.plusHours(1);
        // 结束再+1
        LocalDateTime endHour = nextHour.plusHours(1);

        // 转Date给你原有字段用
        Date startTime = Date.from(nextHour.atZone(ZoneId.systemDefault()).toInstant());
        Date endTime = Date.from(endHour.atZone(ZoneId.systemDefault()).toInstant());
        bizWaybillOrder.setSendStartTime(startTime);
        bizWaybillOrder.setSendEndTime(endTime);
        
        // 产品信息和增值服务
        bizWaybillOrder.setProductCode(dto.getProductCode());
        bizWaybillOrder.setAddedService(dto.getAddedService());
        
        // 备注
        bizWaybillOrder.setRemark(dto.getRemark());


        bizWaybillOrder.setDeptId(loginUser.getSysUser().getDeptId());
        bizWaybillOrder.setUserId(loginUser.getUserid());


        return bizWaybillOrder;
    }

    private static String getProductCode(String productName) {
        if (productName == null) {
            return null;
        }
        if (productName.equals("京东标快")) {
            return JDDictConstants.PRODUCT_CODE_ED_M_0001;
        }
        if (productName.equals("京东特快")) {
            return JDDictConstants.PRODUCT_CODE_ED_M_0002;
        }
        if (productName.equals("特快重货")) {
            return JDDictConstants.PRODUCT_CODE_FR_M_0004;
        }
        return null;
    }

    private static String getAddedService(JDOrderDTO dto) {
        JSONObject addedService = new JSONObject();
        addedService.put("isPack", null);
        addedService.put("guaranteeMoney", null);
        addedService.put("isReceiptCollect", null);
        if ("是".equals(dto.getIsPack())) {
            addedService.put("isPack", true);
        }
        if (null != dto.getGuaranteeMoney()) {
            addedService.put("guaranteeMoney", dto.getGuaranteeMoney());
        }
        if ("是".equals(dto.getIsPack())) {
            addedService.put("isReceiptCollect", true);
        }
        return JSON.toJSONString(addedService, SerializerFeature.WriteMapNullValue);
    }
}
