package com.zbf.system.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zbf.common.annotation.DataScope;
import com.zbf.common.annotation.DataSource;
import com.zbf.common.annotation.Log;
import com.zbf.common.core.domain.AjaxResult;
import com.zbf.common.core.domain.entity.SysDept;
import com.zbf.common.core.domain.entity.SysUser;
import com.zbf.common.core.domain.model.LoginUser;
import com.zbf.common.enums.DataSourceType;
import com.zbf.common.enums.custom.*;
import com.zbf.common.exception.ServiceException;
import com.zbf.common.utils.DateUtils;
import com.zbf.common.utils.OrderCodeFactory;
import com.zbf.common.utils.SecurityUtils;
import com.zbf.common.utils.StringUtils;
import com.zbf.common.utils.uuid.IdUtils;
import com.zbf.system.config.CommonConfig;
import com.zbf.system.config.D_Service;
import com.zbf.system.domain.*;
import com.zbf.system.domain.vo.GoodsVo;
import com.zbf.system.domain.vo.TCkOrdersVo;
import com.zbf.system.mapper.*;
import com.zbf.system.service.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.zbf.common.utils.SecurityUtils.*;
import static com.zbf.common.utils.SecurityUtils.getUsername;

/**
 * 出库Service业务层处理
 *
 * @author tony
 * @date 2024-06-24
 */
@Service
public class TCkOrdersServiceImpl extends ServiceImpl<TCkOrdersMapper, TCkOrders> implements ITCkOrdersService //修改
{
    private static final Logger logger = LoggerFactory.getLogger(TCkOrdersServiceImpl.class);
    @Autowired
    private TCkOrdersMapper tCkOrdersMapper;
    @Autowired
    private TCkOrderdetailMapper tCkOrderdetailMapper;
    @Autowired
    private TMiStockMapper tMiStockMapper;
    @Autowired
    private TCkPickingwavegoodsMapper tCkPickingwavegoodsMapper;

    @Autowired
    private TRkWareNoticeMapper rkWareNoticeMapper;

    @Autowired
    private ITCallNoticeService tNoticeService;
    @Autowired
    private ITBaseStorageService baseStorageService;

    @Autowired
    private ITCallNoticeOrderService tNoticeOrderService;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    @Autowired
    private TCkOrderdetailMapper orderdetailMapper;

    @Autowired
    private TBasePalletMapper palletMapper;

    @Autowired
    private TCallNoticeMapper tCallNoticeMapper;
    @Resource
    private IOutBoundService outBoundService;

    @Autowired
    private SysUserPostMapper sysUserPostMapper;

    @Autowired
    private TBaseGoodsMapper goodsMapper;

    @Autowired
    private TBaseStorageMapper storageMapper;

    @Autowired
    private TRkWareNoticeTabMapper mapper;

    @Autowired

    private TransferOrderMapper transferOrderMapper;

    @Autowired
    private  SysDeptMapper sysDeptMapper;


    @Value("${deptmanager}")
    private String deptManager;
    @Value("${managerName}")
    private String managerName;

    @Autowired
    private D_Service dingTalkService;




    /**
     * 查询出库
     *
     * @param id 出库主键
     * @return 出库
     */
    @Override
    public TCkOrders selectTCkOrdersById(String id) {
        return tCkOrdersMapper.selectTCkOrdersById(id);
    }

    /**
     * 查询出库
     *
     * @param id 出库主键
     * @return 出库
     */
    @Override
    public TCkOrders selectTCkOrdersByOrderId(String id) {
        return tCkOrdersMapper.selectTCkOrdersByOrderId(id);
    }

    /**
     * 查询出库
     *
     * @param id 出库主键
     * @return 出库
     */
    @Override
    public TCkOrders selectTCkOrdersByDeliveryId(String id) {
        return tCkOrdersMapper.selectTCkOrdersByDeliveryId(id);
    }


    /**
     * 查询出库列表
     *
     * @param tCkOrders 出库
     * @return 出库
     */
    @Override
    @DataScope(deptAlias = "d")
    public List<TCkOrders> selectTCkOrdersList(TCkOrders tCkOrders) {
        List<TCkOrders> orders = tCkOrdersMapper.selectTCkOrdersList(tCkOrders);
        /*LoginUser loginUser = getLoginUser();
        SysUser user = loginUser.getUser();
        //岗位
        SysUserPost userPost = sysUserPostMapper.select(user.getUserId());
        if (userPost==null){
            return orders;
        }
        if (userPost.getPostId()==6){
            return orders;
        }
        List<TCkOrders> collect = orders.stream().filter(c -> c.getApplicant().equals(SecurityUtils.getUserNick())).collect(Collectors.toList());*/
        return orders;
    }

    /**
     * 新增出库
     *
     * @param tCkOrders 出库
     * @return 结果
     */
    @Transactional
    @Override
    public int insertTCkOrders(TCkOrders tCkOrders) {
        tCkOrders.setCreateTime(DateUtils.getNowDate());
        tCkOrders.setStatus(OutboundOrderStatus.CREATED.getCode());
        //根据通知单号查询是否存在
        String deliveryId = tCkOrders.getDeliveryId();
        LambdaQueryWrapper<TCkOrders> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TCkOrders::getDeliveryId, deliveryId);
        List<TCkOrders> existingOrders = tCkOrdersMapper.selectList(queryWrapper);
        if (existingOrders.size() > 0) {
            throw new RuntimeException("来源单号已存在，请修改后再提交！");
        }
        if(StringUtils.isEmpty(tCkOrders.getApplicant())){
            tCkOrders.setApplicant(SecurityUtils.getUserNick());
        }else{
            tCkOrders.setApplicant(tCkOrders.getApplicant());
        }
        SysDept sysDept = sysDeptMapper.selectDeptById(tCkOrders.getDeptId());
        String[] ancestorDeptIds = sysDept.getAncestors().split(",");
        if(ancestorDeptIds.length>3){
            SysDept businessDept = sysDeptMapper.selectDeptById(Long.valueOf(ancestorDeptIds[3]));
            tCkOrders.setDeptName(businessDept.getDeptName());
        }else{
            tCkOrders.setDeptName(sysDept.getDeptName());
        }


        tCkOrders.setRecordPerson(SecurityUtils.getUserNick());
        int rows = tCkOrdersMapper.insertTCkOrders(tCkOrders);
//        insertTCkOrderdetail(tCkOrders);
        return rows;
    }

    /**
     * 修改出库
     *
     * @param tCkOrders 出库
     * @return 结果
     */
    @Transactional
    @Override
    public int updateTCkOrders(TCkOrders tCkOrders) {
        tCkOrders.setUpdateTime(DateUtils.getNowDate());
       LoginUser loginUser = SecurityUtils.getLoginUser();
        if(loginUser != null){
            SysUser user = loginUser.getUser();
            if(user != null){
                tCkOrders.setUpdateBy(user.getNickName());
            }
        }else{
            tCkOrders.setUpdateBy("callBack 更新");
        }

//        String orderId = tCkOrders.getOrderId();
//        LambdaQueryWrapper<TCkOrders> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(TCkOrders::getOrderId, orderId);
//        List<TCkOrders> tCkOrders1 = tCkOrdersMapper.selectList(queryWrapper);
//        if (tCkOrders1.size() > 1) {
//            throw new RuntimeException("来源单号已存在，请修改后再提交！");
//        }
//        if (tCkOrders1.size() == 1) {
//            TCkOrders tCkOrders2 = tCkOrders1.get(0);
//            if (!tCkOrders2.getId().equals(tCkOrders.getId())) {
//                throw new RuntimeException("来源单号已存在，请修改后再提交！");
//            }
//        }
//        tCkOrdersMapper.deleteTCkOrderdetailByOrderId(tCkOrders.getId());
//        insertTCkOrderdetail(tCkOrders);
        return tCkOrdersMapper.updateTCkOrders(tCkOrders);
    }

    /**
     * 批量删除出库
     *
     * @param ids 需要删除的出库主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteTCkOrdersByIds(String[] ids) {
        tCkOrdersMapper.deleteTCkOrderdetailByOrderIds(ids);
        return tCkOrdersMapper.deleteTCkOrdersByIds(ids);
    }

    /**
     * 删除出库信息
     *
     * @param id 出库主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteTCkOrdersById(String id) {
        tCkOrdersMapper.deleteTCkOrderdetailByOrderId(id);
        return tCkOrdersMapper.deleteTCkOrdersById(id);
    }


    /**
     * 批量禁用
     *
     */
    @Transactional
    @Override
    public int disabledTCkOrdersByIds(String[] ids) {
        return tCkOrdersMapper.disabledTCkOrdersByIds(ids);
    }

    /**
     * 批量启用
     *
     */
    @Transactional
    @Override
    public int enableTCkOrdersByIds(String[] ids) {
        return tCkOrdersMapper.enableTCkOrdersByIds(ids);
    }

    /**
     * 修改状态
     *
     * @param tCkOrders 工序管理主键
     * @return 结果
     */
    @Override
    @Transactional
    public int updateStatus(TCkOrders tCkOrders) {
        if (StringUtils.isNotBlank(tCkOrders.getIsAudit())) {
            if (StringUtils.isNotBlank(tCkOrders.getAuditPerson1())) {
                this.deptManager = tCkOrders.getAuditPerson1();
            }
            if (StringUtils.isNotBlank(tCkOrders.getAuditPerson2())) {
                this.managerName = tCkOrders.getAuditPerson2();
            }
            //tCkOrders.setAuditMan(deptManager);
            tCkOrders.setRejectReason("");
        }


        TCkOrders currentOrder = tCkOrdersMapper.get(tCkOrders.getId());
        OutBound outBound = new OutBound();
        outBound.setDeptmanager(deptManager); //第一审核人
        outBound.setManagerName(managerName); //第二审核人
        outBound.setDeliveryId(currentOrder.getDeliveryId());
        outBound.setCkType(currentOrder.getCkType());
        outBound.setApplyTime(DateUtils.getDate());
//        outBound.setApplyer(SecurityUtils.getUserNick());
        outBound.setApplyer(getUsername());
        if (StringUtils.isNotBlank(tCkOrders.getAuditPerson3())) {
            outBound.setCrossDeptManager(tCkOrders.getAuditPerson3());
        }

        List<GoodsVo> outboundGoodsList = new ArrayList<>();
        //查询明细
        TCkOrderdetail orderDetailQuery = new TCkOrderdetail();
        orderDetailQuery.setOrderId(tCkOrders.getId());
        List<TCkOrderdetail> orderDetailList = tCkOrderdetailMapper.selectTCkOrderdetailList(orderDetailQuery);
        if(orderDetailList.size() == 0){
            logger.error("没有获取到明细条数====");
            throw new RuntimeException("未获取到明细，请确认！");
        }
        String outboundStorageShortName = StringUtils.EMPTY;
        for (TCkOrderdetail orderDetail : orderDetailList) {
            GoodsVo goodsVo = new GoodsVo();
            goodsVo.setId(orderDetail.getId());
            goodsVo.setGoodsId(orderDetail.getGoodsId());
            goodsVo.setGoodsName(orderDetail.getGoodsName());
            goodsVo.setPrice(orderDetail.getPrice());
            goodsVo.setUnit(orderDetail.getUnit());
            goodsVo.setShelvesNum(orderDetail.getShelvesNum());
            goodsVo.setStorageId(orderDetail.getStorageId());
            goodsVo.setStorageShortName(orderDetail.getStorageShortName());
            if(StringUtils.isBlank(outboundStorageShortName)){
                outboundStorageShortName = orderDetail.getStorageShortName();
            }
            goodsVo.setTotal(orderDetail.getStockNum());
            goodsVo.setRemark(orderDetail.getRemark());
            //物资流向
            goodsVo.setGoodsTo(orderDetail.getGoodsTo());

            goodsVo.setLevelType(orderDetail.getLevelType());
            goodsVo.setSpecification(orderDetail.getSpecification());
            goodsVo.setRecoil(orderDetail.getRecoil());

            outboundGoodsList.add(goodsVo);
            //更新呼叫数量
            TCkOrderdetail orderDetailUpdate = new TCkOrderdetail();
            orderDetailUpdate.setId(orderDetail.getId());
            orderDetailUpdate.setCallShelvesNum(orderDetail.getShelvesNum());
            tCkOrderdetailMapper.updateTCkOrderdetail(orderDetailUpdate);
        }
        outBound.setStorageId(outboundStorageShortName);
        outBound.setItemList(JSONUtil.toJsonStr(outboundGoodsList));
        //查询token，创建实例
        String instanceId = dingTalkService.createInstance(outBound);
        logger.info("创建的实例ID：{}",instanceId);
        if(StringUtils.isBlank(instanceId)){
            logger.warn("创建实例ID异常,只能本地审批，无法通过钉钉审批了，流程继续，申请人：{}",getUsername());
            //throw new RuntimeException("创建钉钉实例异常===》》》》");
        }
        outBound.setInstanceId(instanceId);
        outBoundService.insertOutBound(outBound);
        //更新出库主表钉钉实例ID
        tCkOrders.setInstanceId(instanceId);
        int row = tCkOrdersMapper.updateTCkOrders(tCkOrders);
        return row;
    }

    @Transactional
    @Override
    public int auditCkOrdersTCkOrdersByIds(String[] ids) {
        return tCkOrdersMapper.auditTCkOrdersByIds(ids, SecurityUtils.getUserNick(), DateUtils.getNowDate());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertTCkOrdersDetails(List<TCkOrderdetail> orderDetails) {
        //根据goodsId判断是否有重复的 用lanmada表达式
        // 判断是否存在重复的GoodsId
        boolean hasDuplicate = orderDetails.stream()
                .collect(Collectors.groupingBy(TCkOrderdetail::getGoodsId))
                .values()
                .stream()
                .anyMatch(list -> list.size() > 1);
        if(hasDuplicate){
            throw new RuntimeException("请不要添加重复的物料");
        }

        for (TCkOrderdetail orderDetail : orderDetails) {
            //需求数量
            BigDecimal requiredShelvesNum = orderDetail.getShelvesNum();
            orderDetail.setGoodsNum(requiredShelvesNum);
//            if (StringUtils.isBlank(orderdetail.getBusinessId())) {
//                orderdetail.setBusinessId("RK"+generateReqCode());
//            }
            //物料id不能重复
            LambdaQueryWrapper<TCkOrderdetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TCkOrderdetail::getOrderId, orderDetail.getOrderId());
            queryWrapper.eq(TCkOrderdetail::getGoodsId, orderDetail.getGoodsId());
            List<TCkOrderdetail> existingOrderDetails = tCkOrderdetailMapper.selectList(queryWrapper);
            for (TCkOrderdetail currentOrderDetail : orderDetails) {
                LambdaQueryWrapper<TMiStock> stockQueryWrapper = new LambdaQueryWrapper<>();
                stockQueryWrapper.eq(TMiStock::getGoodsId, currentOrderDetail.getGoodsId());
                stockQueryWrapper.eq(TMiStock::getStatus, OutboundResourceLockStatus.LOCKED.getCode());
                List<TMiStock> lockedStocks = tMiStockMapper.selectList(stockQueryWrapper);
                if (!lockedStocks.isEmpty()) {
                    throw new RuntimeException(currentOrderDetail.getGoodsName() + "物料已被冻结");
                }
            }
            String goodsId = orderDetail.getGoodsId();
            LambdaQueryWrapper<TBaseGoods> goodsQueryWrapper = new LambdaQueryWrapper<>();
            goodsQueryWrapper.eq(TBaseGoods::getGoodsId, goodsId);
            TBaseGoods goodsInfo = goodsMapper.selectOne(goodsQueryWrapper);
            //原来仓库
            //总价
            BigDecimal price = goodsInfo.getPrice();
            // 设置默认值
            if (price == null || price.compareTo(BigDecimal.ZERO) == 0) {
                price = BigDecimal.ZERO; // 默认值为 1
            }
            orderDetail.setPrice(price);
            BigDecimal totalPrice = price.multiply(requiredShelvesNum);
            orderDetail.setToMoney(totalPrice);


            orderDetail.setUpdateTime(DateUtils.getNowDate());
            orderDetail.setCreateTime(DateUtils.getNowDate());
            orderDetail.setConfirmStatus(OutboundConfirmStatus.PENDING.getCode());
            if (StringUtils.isNotBlank(orderDetail.getId())) {
                if (existingOrderDetails.size() > 1) {
                    throw new RuntimeException("更新物料重复异常");
                }

                tCkOrderdetailMapper.update(orderDetail, queryWrapper);
            } else {
                if (existingOrderDetails.size() > 0) {
                    throw new RuntimeException("新增物料重复异常");
                }
                orderDetail.setId(OrderCodeFactory.getOrderCode("CKTM", ""));
                //todo 暂时通过remark记录物资流向
                if(StringUtils.isNotBlank(orderDetail.getRemark())) {
                    orderDetail.setGoodsTo(orderDetail.getRemark());
                }
                tCkOrderdetailMapper.insert(orderDetail);
            }
        }
        return 1;
    }

    @Override
    @Transactional
    public int deleteTCkOrderDetailsByIds(String[] ids) {
        tCkOrderdetailMapper.deleteBatchIds(Arrays.asList(ids));
        return 1;
    }

    @Override
    @Transactional
    public int confirmOut(TCkOrders tCkOrders) {
        List<TCkOrderdetail> orderDetails = tCkOrders.getTckOrderdetailList();
        if (orderDetails.size() == 0) {
            logger.error("出库明细条数必须大于0");
            throw new RuntimeException("出库明细条数必须大于0");
        }
        //1. 判断库存是否满足
//        String storageId = tCkOrders.getStorageId();
        //判断是否选中了仓库，如果没有选中，则从所有权限下仓库进行查询，如果选中了，则从指定仓库选择
        logger.info("出库请求解析开始：{}", orderDetails);
        //value: 以托盘号为key，该托盘出库该物料的出库数量为value的map
        Map<String, Map<String, BigDecimal>> goodsLocationQuantityMap = new HashMap<String, Map<String, BigDecimal>>();
        List<OutStockVo> selectedOutboundStocks = new ArrayList<>();

        // 所有仓库集合
        List<String> involvedStorageIds = new ArrayList<>();

        for (TCkOrderdetail orderDetail : orderDetails) {
            if (OutboundConfirmStatus.COMPLETED.getCode().equals(orderDetail.getConfirmStatus())) {
                logger.info("已出库完成的忽略：{}", orderDetail.getGoodsId());
                continue;
            }

            Map<String, BigDecimal> locationOutboundQuantityMap = new HashMap<>();
            TMiStock stockQuery = new TMiStock();
            stockQuery.setGoodsId(orderDetail.getGoodsId());
            stockQuery.setGoodsName(orderDetail.getGoodsName());

            if (StringUtils.isNotBlank(orderDetail.getStorageId())) {
                stockQuery.setStorageId(orderDetail.getStorageId());
            } else {
                TBaseStorage storageQuery = new TBaseStorage();
                storageQuery.setDeptId(tCkOrders.getDeptId());
                List<TBaseStorage> availableStorages = baseStorageService.selectTBaseStorageList(storageQuery);
                stockQuery.setStorageList(availableStorages.stream().map(TBaseStorage::getStorageId).collect(Collectors.toList()));
            }

            if(StringUtils.isNotBlank(orderDetail.getCtl())){
                stockQuery.setCtl(orderDetail.getCtl());
            }
            if(StringUtils.isNotBlank(orderDetail.getLocationId())){
                stockQuery.setLocationId(orderDetail.getLocationId());
            }

//            LambdaQueryWrapper<TMiStock> wrapper = new LambdaQueryWrapper<>();
//            wrapper.eq(TMiStock::getGoodsId, tMiStock.getGoodsId());
//            wrapper.eq(TMiStock::getGoodsName, tMiStock.getGoodsName());

            List<TMiStock> candidateStocks = tMiStockMapper.selectTMiStockList(stockQuery);

            if (candidateStocks.size() == 0) {
                logger.warn("未找到该物料库存或在冻结中：{}", orderDetail.getGoodsId());
                throw new RuntimeException("未找到该物料库存或在冻结中：" + orderDetail.getGoodsId());
            }

            // 分组逻辑：如果指定了 ctl，则只处理该 ctl 分组；否则按 locationId 分组，并只取每组的第一条
            String specifiedPalletCode = orderDetail.getCtl();
            Map<String, List<TMiStock>> groupedStockMap;
            if (StringUtils.isNotBlank(specifiedPalletCode)) {
                groupedStockMap = candidateStocks.stream()
                        .collect(Collectors.groupingBy(TMiStock::getCtl));
            } else {
                groupedStockMap = candidateStocks.stream()
                        .collect(Collectors.groupingBy(TMiStock::getLocationId));
            }

            BigDecimal requiredGoodsNum = orderDetail.getGoodsNum();
            BigDecimal accumulatedAvailableQuantity = BigDecimal.ZERO;

            // 处理分组
            StringBuilder salesOrderNumbersBuilder = new StringBuilder();
            for (List<TMiStock> stockGroup : groupedStockMap.values()) {
                TMiStock stockSnapshot = stockGroup.get(0); // 取每组的第一条记录
                accumulatedAvailableQuantity = accumulatedAvailableQuantity.add(stockSnapshot.getShelvesNum());
                if (orderDetail.getPickNum() == null) {
                    orderDetail.setPickNum(BigDecimal.ZERO);
                }
                OutStockVo outboundStock = new OutStockVo();
                outboundStock.setId(stockSnapshot.getId());
                outboundStock.setLocationId(stockSnapshot.getLocationId());

                if (requiredGoodsNum.compareTo(accumulatedAvailableQuantity) == 0) {
                    locationOutboundQuantityMap.put(stockSnapshot.getLocationId(), stockSnapshot.getShelvesNum());
                    outboundStock.setShelvesNum(stockSnapshot.getShelvesNum());
                    selectedOutboundStocks.add(outboundStock);
                    orderDetail.setPickNum(orderDetail.getPickNum().add(stockSnapshot.getShelvesNum()));
                    salesOrderNumbersBuilder.append(stockSnapshot.getSalesOrderNumber()).append(",");
                    involvedStorageIds.add(stockSnapshot.getStorageId());
                    break;
                } else if (requiredGoodsNum.compareTo(accumulatedAvailableQuantity) > 0) {
                    locationOutboundQuantityMap.put(stockSnapshot.getLocationId(), stockSnapshot.getShelvesNum());
                    outboundStock.setShelvesNum(stockSnapshot.getShelvesNum());
                    selectedOutboundStocks.add(outboundStock);
                    orderDetail.setPickNum(orderDetail.getPickNum().add(stockSnapshot.getShelvesNum()));
                    salesOrderNumbersBuilder.append(stockSnapshot.getSalesOrderNumber()).append(",");
                    involvedStorageIds.add(stockSnapshot.getStorageId());
                } else {
                    BigDecimal excessQuantity = accumulatedAvailableQuantity.subtract(requiredGoodsNum);
                    BigDecimal actualOutboundQuantity = stockSnapshot.getShelvesNum().subtract(excessQuantity);
                    locationOutboundQuantityMap.put(stockSnapshot.getLocationId(), actualOutboundQuantity);
                    outboundStock.setShelvesNum(actualOutboundQuantity);
                    selectedOutboundStocks.add(outboundStock);
                    orderDetail.setPickNum(orderDetail.getPickNum().add(actualOutboundQuantity));
                    salesOrderNumbersBuilder.append(stockSnapshot.getSalesOrderNumber()).append(",");
                    involvedStorageIds.add(stockSnapshot.getStorageId());
                    break;
                }
            }
            if(salesOrderNumbersBuilder.toString().length()>1){
                String salesOrderNumbers = salesOrderNumbersBuilder.substring(0, salesOrderNumbersBuilder.length()-1);
                orderDetail.setBusinessId(salesOrderNumbers);
            }
            goodsLocationQuantityMap.put(orderDetail.getGoodsId(), locationOutboundQuantityMap);
            logger.info("更新累计出库数量：{}", orderDetail);
            orderDetail.setConfirmStatus(OutboundConfirmStatus.PENDING.getCode());
            tCkOrderdetailMapper.updateTCkOrderdetail(orderDetail);
        }

        if (goodsLocationQuantityMap.isEmpty()) {
            logger.warn("未找到出库物料");
            throw new RuntimeException("未找到出库物料,请确认！");
        }

        //设置主表status为锁定
        TCkOrders lockedOrder = new TCkOrders();
        lockedOrder.setStatus(OutboundOrderStatus.LOCKED.getCode());
        lockedOrder.setId(tCkOrders.getId());
        lockedOrder.setUpdateBy(SecurityUtils.getUserNick());
        lockedOrder.setUpdateTime(new Date());
        tCkOrdersMapper.updateById(lockedOrder);

        //创建出库任务
        /**
         * 假如 物料A 需要出库的托盘为1 ，3 ，8
         * 物料B 需要出库的托盘为1，5
         * 则本次出库的总的任务为4个，1，3，5，8
         * 根据这个逻辑进行开发
         */

        //lambda表达式遍历
        //蒋map进行转换，转换为以托盘为大key，以物料和数量为小map的map
        Map<String, Map<String, BigDecimal>> locationGoodsQuantityMap = new HashMap<>();
        goodsLocationQuantityMap.forEach((goodsId, locationQuantityMap) -> {
            locationQuantityMap.forEach((locationId, shelvesNum) -> {
                AtomicBoolean locationExists = new AtomicBoolean(false);
                locationGoodsQuantityMap.forEach((existingLocationId, goodsQuantityMap) -> {
                    if (locationId.equals(existingLocationId)) {
                        locationExists.set(true);
                        goodsQuantityMap.put(goodsId, shelvesNum);
                    }
                });

                if (!locationExists.get()) {
                    Map<String, BigDecimal> goodsQuantityMap = new HashMap<>();
                    goodsQuantityMap.put(goodsId, shelvesNum);
                    locationGoodsQuantityMap.put(locationId, goodsQuantityMap);
                }

            });
        });

        logger.info("生成以库位编号为主键的map：{}", locationGoodsQuantityMap);

        // 发送呼叫任务
        TCallNotice callNotice = new TCallNotice();
        callNotice.setId(IdUtils.randomUUID());

        //根据每个托盘创建出库任务
        //1. 判断出库任务是否已产生该托盘的任务

        locationGoodsQuantityMap.forEach((locationId, goodsQuantityMap) -> {
            TCkPickingwavegoods pickingTaskQuery = new TCkPickingwavegoods();
            pickingTaskQuery.setLocationId(locationId);
            pickingTaskQuery.setGoodsIdList(new ArrayList<>(goodsQuantityMap.keySet()));
            pickingTaskQuery.setOutId(tCkOrders.getId());
            //判断该库位编号是否产生出库任务
            List<TCkPickingwavegoods> existingPickingTasks = tCkPickingwavegoodsMapper.selectTCkPickingwavegoodsList(pickingTaskQuery);
            if (existingPickingTasks.size() > 0) {
                logger.error("该库位已产生出库任务：{}", locationId);
                throw new RuntimeException("该库位已产生出库任务：" + locationId);
            }

            //出库  添加呼叫任务号
            createLocationOutboundTasks(locationId, tCkOrders.getId(), tCkOrders.getOrderId(), tCkOrders.getCkType(),
                    selectedOutboundStocks.stream().filter(stock -> stock.getLocationId().equals(locationId)).collect(Collectors.toList()),
                    callNotice.getId());

        });

        // 仓库ID去重
        involvedStorageIds = involvedStorageIds.stream().distinct().collect(Collectors.toList());

        involvedStorageIds.forEach((storageId) -> {
            // 仓库id
            callNotice.setStorageId(storageId);
            // 托盘号
            // tCallNotice.setCtl("");
            // pLCID
            // tCallNotice.setPlcid("");
            // 任务类型 1:出库任务
            callNotice.setTaskType(NoticeTaskType.OUTBOUND.getCode());
            // 物料编码
            // tCallNotice.setGoodsId(tCkPickingwavegoods.getGoodsId());
            // 物料名称
            // tCallNotice.setGoodsName(tCkPickingwavegoods.getGoodsName());
            // 出库任务ID
            // tCallNotice.setChukuId(tCkPickingwavegoods.getId());
            // 创建者
            callNotice.setCreateBy(SecurityUtils.getUserNick());
            // 时间
            callNotice.setCreateTime(new Date());
            // 状态 0：未处理
            callNotice.setStatus(NoticeTaskStatus.PENDING.getCode());
            // 出库通知单号
            callNotice.setTaskId(tCkOrders.getOrderId());
            // 虚拟入库标识 0:非虚拟
            callNotice.setFictitious(TaskFictitiousFlag.REAL.getCode());

            tNoticeService.sendNotice(callNotice);
        });

        return 1;
    }

    //主页统计出库通知单
    @DataSource(DataSourceType.MASTER)
    @Override
    @DataScope(deptAlias = "d")
    public int homeOutCount(TCkOrders tCkOrders) {
        return tCkOrdersMapper.homeCount(tCkOrders);
    }

    //主页统计入库通知单
    @DataSource(DataSourceType.MASTER)
    @Override
    @DataScope(deptAlias = "d")
    public int homeInCount(TRkWareNotice tRkWareNotice) {
        return rkWareNoticeMapper.homeCount(tRkWareNotice);
    }

    /**
     * 新增出库物料明细信息
     *
     * @param tCkOrders 出库对象
     */
    public void insertTCkOrderdetail(TCkOrders tCkOrders) {
        List<TCkOrderdetail> tCkOrderdetailList = tCkOrders.getTckOrderdetailList();
        String id = tCkOrders.getId();
        if (StringUtils.isNotNull(tCkOrderdetailList)) {
            List<TCkOrderdetail> list = new ArrayList<TCkOrderdetail>();
            for (TCkOrderdetail tCkOrderdetail : tCkOrderdetailList) {
                tCkOrderdetail.setOrderId(id);
                list.add(tCkOrderdetail);
            }
            if (list.size() > 0) {
                tCkOrdersMapper.batchTCkOrderdetail(list);
            }
        }
    }

    private void createLocationOutboundTasks(String locationId, String outboundOrderId, String outboundNoticeId,
                                             String outboundType, List<OutStockVo> outboundStocks, String callNoticeId) {
        if (outboundStocks.size() == 0) {
            throw new RuntimeException("没有获取到该物料库存明细");
        }
//        TMiStock tMiStock = new TMiStock();
//        tMiStock.setLocationId(locationId);
//        List<TMiStock> tMiStocks = tMiStockMapper.selectTMiStockList(tMiStock);

        //设置库存里面的出库数量
//        for (TMiStock tMiStock1 : tMiStocks) {
//            for (String key : map.keySet()) {
//                BigDecimal value = map.get(key);
//                if (tMiStock1.getGoodsId().equals(key)) {
//                    //出库数量
//                    tMiStock1.setPackingNum(value);
//                    break;
//                }
//            }
//        }
        //
//        boolean isExist = false;
//        for (TMiStock tMiStock1 : tMiStocks) {
//            if (tMiStock1.getPackingNum() == null) {
//                isExist = true;
//                break;
//            }
//            if (tMiStock1.getShelvesNum().compareTo(tMiStock1.getPackingNum()) > 0) {
//                isExist = true;
//                break;
//            }
//        }
        //CkType ： 1.零捡 2：全量 3移库
        //boxtype：1：不需要出库 2：零捡 3：全出
//        if (isExist) {
//            tMiStocks.forEach(e -> {
//                if (e.getPackingNum() == null) {
//                    //不需要出库的
//                    e.setBoxType("1");
//                } else {
//                    //零检
//                    e.setBoxType("2");
//                }
//                e.setCkType("1");
//            });
//        } else {
//            tMiStocks.forEach(e -> {
//                e.setCkType("2");
//                e.setBoxType("3");
//            });
//        }
        //是否需要冻结库存
        //出哪条，锁定哪条
        for (OutStockVo outboundStock : outboundStocks) {
            TMiStock stockOccupancyUpdate = new TMiStock();
            stockOccupancyUpdate.setId(outboundStock.getId());
            stockOccupancyUpdate.setUpdateTime(DateUtils.getNowDate());
            stockOccupancyUpdate.setUpdateBy(SecurityUtils.getUserNick());
            stockOccupancyUpdate.setOccupyNum(outboundStock.getShelvesNum());
            stockOccupancyUpdate.setStatus(OutboundResourceLockStatus.LOCKED.getCode());
            tMiStockMapper.updateById(stockOccupancyUpdate);
        }
//        TMiStock tMiStock3 = new TMiStock();
//        tMiStock3.setLocationId(locationId);
//        tMiStock3.setStatus("1");
//        tMiStock3.setUpdateBy(SecurityUtils.getUserNick());
//        tMiStock3.setUpdateTime(DateUtils.getNowDate());
//        tMiStockMapper.updateSts(tMiStock3);

        //创建出库任务
        for (OutStockVo outboundStock : outboundStocks) {
            String pickingTaskId = OrderCodeFactory.getOrderCode("CK", "");
            TCkPickingwavegoods pickingTask = new TCkPickingwavegoods();
            TMiStock lockedStock = tMiStockMapper.selectById(outboundStock.getId());
            pickingTask.setGoodsId(lockedStock.getGoodsId());
            //图号
            pickingTask.setRecoil(lockedStock.getOriBill());
            pickingTask.setCtl(lockedStock.getCtl());
//                tCkPickingwavegoods.setDecid(tMiStock1.getDecid());
            pickingTask.setGoodsName(lockedStock.getGoodsName());
            pickingTask.setMistockNum(lockedStock.getShelvesNum());
            //出库数量
            pickingTask.setGoodsNum(outboundStock.getShelvesNum());
            pickingTask.setRecNum(BigDecimal.ZERO);
            pickingTask.setLocationId(lockedStock.getLocationId());
            pickingTask.setLocId(lockedStock.getLocationId());
            pickingTask.setId(pickingTaskId);
            pickingTask.setPutinId(lockedStock.getBatchNo());
            //来源单号
            pickingTask.setPickingId(outboundNoticeId);
            pickingTask.setUnit(lockedStock.getUnit());
            //出库类型
            pickingTask.setCkType(outboundType);
            pickingTask.setTypests(lockedStock.getBoxType());
            //待拣选
            pickingTask.setConfirmStatus(OutboundConfirmStatus.PENDING.getCode());
            pickingTask.setWgh(lockedStock.getWgh());
            //库存主键
            pickingTask.setDoctNumber(lockedStock.getId());
            pickingTask.setSpecification(lockedStock.getSpecification());
            //销售单号
            pickingTask.setSalesOrderNo(lockedStock.getSalesOrderNo());
            pickingTask.setWareDate(lockedStock.getWareDate());
            pickingTask.setSalesOrderNumber(lockedStock.getSalesOrderNumber());
            pickingTask.setOutstand(lockedStock.getStandard());
            pickingTask.setSpecification(lockedStock.getSpecification());
            pickingTask.setProductionDate(lockedStock.getProductionDate());
            pickingTask.setProviderId(lockedStock.getProviderId());
            //出库单号
            pickingTask.setOutId(outboundOrderId);
            pickingTask.setStorageId(lockedStock.getStorageId());
            pickingTask.setStorageShortName(lockedStock.getStorageShortName());
            pickingTask.setStorageAreaId(lockedStock.getStorageAreaId());
            //收货组织
            pickingTask.setProduclotId(lockedStock.getProduclotId());
            pickingTask.setOperatorId(lockedStock.getOperatorId());
            pickingTask.setSupplier(lockedStock.getSupplier());
            pickingTask.setCustomerId(lockedStock.getCustomerId());
            pickingTask.setBrand(lockedStock.getBrand());
            pickingTask.setGoodsTypeId(lockedStock.getGoodsTypeId());
            pickingTask.setCreateTime(DateUtils.getNowDate());
            pickingTask.setCreateBy(SecurityUtils.getUserNick());
            pickingTask.setDeptId(getLoginUser().getDeptId());
            // 呼叫任务号
            pickingTask.setCallNoticeId(callNoticeId);
            logger.info("根据出库单创建出库任务：{}", pickingTask);
            tCkPickingwavegoodsMapper.insertTCkPickingwavegoods(pickingTask);
        }
    }

    /**
     * 导入出库通知单数据
     *
     * @param dataList        用户数据列表
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName        操作用户
     * @return 结果
     */
    @Override
    @Transactional
    public String importData(List<TCkOrderdetail> dataList, boolean isUpdateSupport, String operName) {
        if (StringUtils.isNull(dataList) || dataList.size() == 0) {
            throw new ServiceException("导入入库通知单数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        TCkOrderdetail firstImportedDetail = dataList.get(0);

        firstImportedDetail.setDeliveryId(generateRandomHexCode(8));
        TCkOrders importedOrder = new TCkOrders();
        importedOrder.setDeliveryId(firstImportedDetail.getDeliveryId());
        List<TCkOrders> existingImportedOrders = tCkOrdersMapper.selectTCkOrdersList(importedOrder);
        if (existingImportedOrders.size() == 0) {
            initializeImportedOrder(importedOrder, firstImportedDetail, operName);
            tCkOrdersMapper.insertTCkOrders(importedOrder);
        } else if (isUpdateSupport) {
            List<String> collect = existingImportedOrders.stream().map(TCkOrders::getId).collect(Collectors.toList());
            tCkOrdersMapper.deleteTCkOrdersByIds(collect.toArray(new String[collect.size()]));
            initializeImportedOrder(importedOrder, firstImportedDetail, operName);
            tCkOrdersMapper.insertTCkOrders(importedOrder);

        } else {
            throw new ServiceException("来源单号 " + firstImportedDetail.getDeliveryId() + " 重复导入异常！");
        }


        for (int i = 0; i < dataList.size(); i++) {
            try {
                //校验必输字段
                TCkOrderdetail importedDetail = dataList.get(i);
                checkData(i, importedDetail);
                // 验证是否存在该明细
                TCkOrderdetail detailQuery = new TCkOrderdetail();
                detailQuery.setDeliveryId(importedDetail.getDeliveryId());
                detailQuery.setGoodsId(importedDetail.getGoodsId());
                detailQuery.setLevelType(InboundLevelType.LEVEL_TWO.getCode());

                List<TCkOrderdetail> existingDetailList = tCkOrderdetailMapper.selectTCkOrderdetailList(detailQuery);
                LambdaQueryWrapper<TMiStock> stockQueryWrapper = new LambdaQueryWrapper<>();
                stockQueryWrapper.eq(TMiStock::getGoodsId, importedDetail.getGoodsId());
                TMiStock stockRecord = tMiStockMapper.selectOne(stockQueryWrapper);
                if (stockRecord.getStatus().equals(OutboundResourceLockStatus.LOCKED.getCode())) {
                    successNum++;
                    failureMsg.append("<br/>" + stockRecord.getGoodsId() + "、物料编号 " + importedDetail.getGoodsNum() + " 已锁定");
                }
                if (existingDetailList.size() == 0) {
                    initializeImportedOrderDetail(importedDetail, importedOrder.getId(), operName);
                    tCkOrderdetailMapper.insertTCkOrderdetail(importedDetail);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、物料编号 " + importedDetail.getGoodsId() + " 导入成功");
                } else if (isUpdateSupport) {
                    List<String> collect = existingDetailList.stream().map(TCkOrderdetail::getId).collect(Collectors.toList());
                    tCkOrderdetailMapper.deleteTCkOrderdetailByIds(collect.toArray(new String[collect.size()]));
                    initializeImportedOrderDetail(importedDetail, importedOrder.getId(), operName);
                    tCkOrderdetailMapper.insertTCkOrderdetail(importedDetail);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、物料编号 " + importedDetail.getGoodsId() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、物料编号 " + importedDetail.getGoodsId() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、来源单号 " + firstImportedDetail.getDeliveryId() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    private static Random random = new Random();

    private String generateRandomHexCode(int length) {
        // 生成一个以"rfid"开头的12位数字字符串
        String prefix = "LY";
        int numberLength = length; // 需要生成的数字长度
        StringBuilder numberBuilder = new StringBuilder();
        for (int i = 0; i < numberLength; i++) {
            numberBuilder.append(random.nextInt(10)); // 生成一个0到9的随机数
        }
        String rfid = prefix + numberBuilder.toString();
        return rfid;
    }

    private void initializeImportedOrderDetail(TCkOrderdetail orderDetail, String orderId, String operatorName) {
        orderDetail.setId(OrderCodeFactory.getOrderCode("", ""));
        orderDetail.setOrderId(orderId);
        orderDetail.setCreateBy(operatorName);
        orderDetail.setCreateTime(DateUtils.getNowDate());
        //二级入库
        orderDetail.setLevelType(InboundLevelType.LEVEL_TWO.getCode());
        orderDetail.setPickNum(BigDecimal.ZERO);
    }

    private void initializeImportedOrder(TCkOrders importedOrder, TCkOrderdetail sourceDetail, String operatorName) {
        importedOrder.setId(OrderCodeFactory.getOrderCode("", ""));
        importedOrder.setOrderId(OrderCodeFactory.getOrderCode("TWO", ""));
        importedOrder.setDeliveryId(sourceDetail.getDeliveryId());
        importedOrder.setDeptId(getLoginUser().getDeptId());
        importedOrder.setCkType(sourceDetail.getCkType());
        importedOrder.setOrderType(sourceDetail.getOrderType());
        importedOrder.setCreateBy(operatorName);
        importedOrder.setCreateTime(DateUtils.getNowDate());
    }

    private void checkData(int index, TCkOrderdetail trdata) {
        //来源单号
        if (StringUtils.isBlank(trdata.getDeliveryId())) {
            throw new RuntimeException("导入明细第" + (index + 1) + "条来源单号为空");
        }
        if (StringUtils.isBlank(trdata.getGoodsId())) {
            throw new RuntimeException("导入明细第" + (index + 1) + "条物料编码为空");
        }
        if (StringUtils.isBlank(trdata.getGoodsName())) {
            throw new RuntimeException("导入明细第" + (index + 1) + "条物料名称为空");
        }
        if (StringUtils.isBlank(trdata.getUnit())) {
            throw new RuntimeException("导入明细第" + (index + 1) + "条物料单位为空");
        }

        if (trdata.getShelvesNum() == null) {
            throw new RuntimeException("导入明细第" + (index + 1) + "条出库数量为空");
        }

    }

    @Override
    @DataScope(deptAlias = "a")
    public List<TCkOrders> exportTCkOrdersList(TCkOrders tCkOrders) {
        return tCkOrdersMapper.exportTCkOrdersList(tCkOrders);
    }

    @Override
    public Map<String, String> sendOrderNotice(TCkOrders update) {

        Map<String, String> resultMap = new HashMap<>();

        // 获取通知单信息
        TCkOrders currentOrder = tCkOrdersMapper.selectTCkOrdersById(update.getId());

        if (ObjectUtils.isEmpty(currentOrder)) {
            resultMap.put("error", "待发送消息的出库通知单不存在");
            return resultMap;
        }

        if (currentOrder.getTckOrderdetailList() == null || currentOrder.getTckOrderdetailList().isEmpty()) {
            resultMap.put("error", "待发送消息的出库通知单没有物料明细数据");
            return resultMap;
        }

        if (!OutboundAuditStatus.APPROVED.getCode().equals(currentOrder.getIsAudit())) {
            resultMap.put("error", "出库通知单未审核完成,不能发送到手持设备");
            return resultMap;
        }

        // 发送呼叫任务
        TCallNoticeOrder noticeOrder = new TCallNoticeOrder();
        // 通知单编号
        noticeOrder.setTaskId(currentOrder.getOrderId());
        // 任务类型 1:通知单出库
        noticeOrder.setTaskType(NoticeTaskType.OUTBOUND.getCode());
        // 状态
        noticeOrder.setStatus(NoticeTaskStatus.PENDING.getCode());
        // 创建者
        noticeOrder.setCreateBy(update.getCreateBy());
        noticeOrder.setCreateTime(new Date());
        noticeOrder.setUpdateBy(update.getCreateBy());
        noticeOrder.setUpdateTime(new Date());

        // 0:正常任务
        noticeOrder.setFictitious(TaskFictitiousFlag.REAL.getCode());
        // 来源单号
        noticeOrder.setDeliveryId(currentOrder.getDeliveryId());
        // 部门ID
        noticeOrder.setDeptId(update.getDeptId());
        // 订单类型
        String outboundTypeLabel = sysDictDataMapper.selectDictLabel("outbound_type", currentOrder.getCkType());
        noticeOrder.setOrderType(outboundTypeLabel);
        tNoticeOrderService.sendNotice(noticeOrder);

        resultMap.put("success", "消息发送成功");
        resultMap.put("error", "");
        return resultMap;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, String> handAddGoodsTab(TCkOrders manualOutboundOrder) {
        Map<String, String> resultMap = new HashMap<>();

        /*//托盘校验
        LambdaQueryWrapper<TBasePallet> eq = new LambdaQueryWrapper<>();
        eq.eq(TBasePallet::getPalletId, orders.getCtl());
        List<TBasePallet> plcs = palletMapper.selectList(eq);
        if (plcs.isEmpty()) {
            resultMap.put("error", "托盘不存在");
            return resultMap;
        }*/

        // 获取订单明细
        List<TCkOrderdetail> requestedOrderDetails = manualOutboundOrder.getTckOrderdetailList();
        // 设置订单基本信息
        manualOutboundOrder.setId(OrderCodeFactory.getOrderCode("CK", ""));
        manualOutboundOrder.setOrderId(generateBarcode());
        manualOutboundOrder.setCkType(OutboundType.STANDARD.getCode());
        manualOutboundOrder.setIsAudit(OutboundAuditStatus.APPROVED.getCode());
        manualOutboundOrder.setAuditDate(new Date());
        manualOutboundOrder.setConfirmStatus(OutboundConfirmStatus.PENDING.getCode());
        manualOutboundOrder.setDeptId(getDeptId());
        manualOutboundOrder.setCreateTime(new Date());

        // 更新出库单
        int insertedRows = insertTCkOrders(manualOutboundOrder);

        if (insertedRows > 0) {
            List<TCkOrderdetail> preparedOrderDetails = new ArrayList<>();  // 移动到循环外部，以便收集所有明细
            for (TCkOrderdetail orderDetail : requestedOrderDetails) {
                LambdaQueryWrapper<TMiStock> stockQueryWrapper = new LambdaQueryWrapper<>();
                // 获取库存信息
                if (orderDetail.getCtl() != null && !orderDetail.getCtl().isEmpty()) {
                    stockQueryWrapper.eq(TMiStock::getGoodsId, orderDetail.getGoodsId());
                    stockQueryWrapper.eq(TMiStock::getStorageId, manualOutboundOrder.getStorageId());
                    stockQueryWrapper.eq(TMiStock::getCtl, manualOutboundOrder.getCtl());
                    stockQueryWrapper.eq(TMiStock::getStatus, OutboundResourceLockStatus.UNLOCKED.getCode());
                    stockQueryWrapper.eq(TMiStock::getIsFreeze, StockFreezeStatus.UNFROZEN.getCode());
                } else {
                    stockQueryWrapper.eq(TMiStock::getGoodsId, orderDetail.getGoodsId());
                    stockQueryWrapper.eq(TMiStock::getStorageId, manualOutboundOrder.getStorageId());
                }

                List<TMiStock> matchedStocks = tMiStockMapper.selectList(stockQueryWrapper);


                if (matchedStocks.isEmpty()) {
                    resultMap.put("error", "当前仓库该物料" + orderDetail.getGoodsName() + "暂无库存");
                    return resultMap;
                }


                TMiStock mergedStock = matchedStocks.get(0);
                BigDecimal totalShelvesNum = mergedStock.getShelvesNum();

                for (int i = 1; i < matchedStocks.size(); i++) {
                    totalShelvesNum = totalShelvesNum.add(matchedStocks.get(i).getShelvesNum());

                }
                mergedStock.setShelvesNum(totalShelvesNum);
                // 设置明细表基本信息
                orderDetail.setOrderId(manualOutboundOrder.getId());
                orderDetail.setId(OrderCodeFactory.getOrderCode("CK", ""));
                orderDetail.setStockNum(mergedStock.getShelvesNum());
                orderDetail.setStorageId(mergedStock.getStorageId());
                orderDetail.setStorageShortName(mergedStock.getStorageShortName());
                orderDetail.setLocationId(mergedStock.getLocationId());
                orderDetail.setShelvesNum(manualOutboundOrder.getSum());
                orderDetail.setGoodsNum(manualOutboundOrder.getSum());
                orderDetail.setPickNum(BigDecimal.ZERO);

                preparedOrderDetails.add(orderDetail);  // 添加到列表中
                manualOutboundOrder.setTckOrderdetailList(preparedOrderDetails);

            }
            List<TCkOrderdetail> preparedDetailList = manualOutboundOrder.getTckOrderdetailList();
            int totalInserted = 0;
            for (TCkOrderdetail preparedDetail : preparedDetailList) {
                preparedDetail.setPickNum(BigDecimal.ZERO);
                int insertedDetailRows = tCkOrderdetailMapper.insert(preparedDetail);
/*
                int insert1 = tCkOrderdetailMapper.inserts(tCkOrderdetail);
*/
                totalInserted += insertedDetailRows;
            }

            if (totalInserted == preparedDetailList.size()) {
                // 出库任务创建，移动到循环外部
                int confirmResult = confirmOut(manualOutboundOrder);
                if (confirmResult < 1) {
                    resultMap.put("error", "出库失败请联系管理员");
                    return resultMap;
                }
            }
        }
        resultMap.put("success", "出库任务成功");
        return resultMap;
    }


    HashSet<String> usedBarcodes = new HashSet<>(); // 存储已生成的条形码以避免重复

    public String generateBarcode() {
        Random random = new Random();
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String numbers = "0123456789";
        StringBuilder barcode;

        do {
            barcode = new StringBuilder();
            // 添加两个随机字母
            for (int i = 0; i < 2; i++) {
                barcode.append(chars.charAt(random.nextInt(chars.length())));
            }
            // 添加四个随机数字
            for (int i = 0; i < 4; i++) {
                barcode.append(numbers.charAt(random.nextInt(numbers.length())));
            }
        } while (usedBarcodes.contains(barcode.toString())); // 确保不重复

        usedBarcodes.add(barcode.toString()); // 添加到已使用集合
        return barcode.toString();
    }

    /**
     * 任务分配
     *
     */

    @Override
    public AjaxResult send(TCkOrders outboundOrder) {
        List<TCkOrderdetail> orderDetails = outboundOrder.getTckOrderdetailList();

        // 过滤出符合条件的订单详情
        List<TCkOrderdetail> agvOrderDetails = orderDetails.stream()
                .filter(orderdetail -> {
                    String isAgv = baseStorageService.getIsAgvByStorageId(orderdetail.getStorageId());
                    return StorageAgvFlag.AGV.getCode().equals(isAgv);
                })
                .collect(Collectors.toList());

        TCkOrders agvOutboundOrder = new TCkOrders();
        BeanUtils.copyProperties(outboundOrder, agvOutboundOrder);
        agvOutboundOrder.setTckOrderdetailList(agvOrderDetails);

        for (TCkOrderdetail orderDetail : agvOrderDetails) {
            LambdaQueryWrapper<TMiStock> stockQueryWrapper = new LambdaQueryWrapper<>();
            stockQueryWrapper.eq(TMiStock::getGoodsId, orderDetail.getGoodsId());
            stockQueryWrapper.eq(TMiStock::getStorageId, orderDetail.getStorageId());
            stockQueryWrapper.eq(TMiStock::getCtl, orderDetail.getCtl());
            stockQueryWrapper.eq(TMiStock::getStatus, OutboundResourceLockStatus.UNLOCKED.getCode());
            stockQueryWrapper.eq(TMiStock::getIsFreeze, StockFreezeStatus.UNFROZEN.getCode());
            List<TMiStock> availableStocks = tMiStockMapper.selectList(stockQueryWrapper);
            if (availableStocks.isEmpty()) {
                return AjaxResult.error(orderDetail.getGoodsName() + "已冻结不能出库,请检查物料列表数据状态为非冻结状态");
            }
        }

        Map<String, String> iwmsResult = sendIwms(agvOutboundOrder);

        if (agvOrderDetails.size() == outboundOrder.getTckOrderdetailList().size()) {
            if (iwmsResult.containsKey("error")) {
                return AjaxResult.error(iwmsResult.get("error"));
            } else {
                return AjaxResult.success("推送成功");
            }
        }

        List<TCkOrderdetail> manualOrderDetails = orderDetails.stream()
                .filter(orderdetail -> {
                    String isAgv = baseStorageService.getIsAgvByStorageId(orderdetail.getStorageId());
                    return !StorageAgvFlag.AGV.getCode().equals(isAgv);
                })
                .collect(Collectors.toList());

        outboundOrder.setTckOrderdetailList(manualOrderDetails);
        confirmOut(outboundOrder);

        return AjaxResult.success("成功");
    }


    /**
     * 创建调拨单据
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int install(TCkOrdersVo transferOrderRequest) {
        String transferOutboundOrderId = OrderCodeFactory.getOrderCode("", "");
        // 1. 创建并验证出库单
        TCkOrders transferOutboundOrder = Optional.of(new TCkOrders())
                .map(order -> {
                    order.setId(transferOutboundOrderId);
                    order.setOrderId(OrderCodeFactory.getOrderCode("CK", ""));
                    order.setApplicant(SecurityUtils.getUserNick());
                    order.setRecordPerson(SecurityUtils.getUserNick());
                    order.setDeptId(getDeptId());
                    order.setRecordDate(new Date());
                    order.setOrderType(OutboundType.TRANSFER.getCode());
                    order.setCkType(OutboundType.TRANSFER.getCode());
                    order.setDeliveryId(generateUniqueId());
                    return order;
                })
                .filter(order -> {
                    boolean deliveryIdAvailable = tCkOrdersMapper.selectList(
                            new LambdaQueryWrapper<TCkOrders>()
                                    .eq(TCkOrders::getDeliveryId, order.getDeliveryId())
                    ).isEmpty();
                    if (!deliveryIdAvailable) {
                        throw new RuntimeException("来源单号已存在，请修改后再提交！");
                    }
                    return true;
                })
                .filter(order -> {
                    int rows = tCkOrdersMapper.insertTCkOrders(order);
                    if (rows < 0) {
                        throw new RuntimeException("入库通知单新增失败");
                    }
                    return true;
                })
                .orElseThrow(() -> new RuntimeException("创建出库单失败"));

        // 2. 处理订单明细
        transferOrderRequest.getData().stream()
                .map(transferItem -> {
                    TCkOrderdetail detail = new TCkOrderdetail();
                    detail.setId(OrderCodeFactory.getOrderCode("CKTM", ""));
                    detail.setOrderId(transferOutboundOrder.getId());
                    detail.setBusinessId("RK" + generateReqCode());
                    detail.setGoodsId(transferItem.getGoodsId());
                    detail.setGoodsName(transferItem.getGoodsName());
                    detail.setSpecification(transferItem.getSpecification());
                    detail.setUnit(transferItem.getUnit());
                    detail.setStorageId(transferItem.getStorageId());
                    detail.setCtl(transferItem.getCtl());
                    detail.setGoodsNum(transferItem.getTransferQuantity());
                    detail.setPrice(new BigDecimal(transferItem.getPrice()).setScale(2, RoundingMode.HALF_UP));
                    detail.setShelvesNum(transferItem.getTransferQuantity());
                    detail.setConfirmStatus(OutboundConfirmStatus.PENDING.getCode());
                    detail.setStockNum(transferItem.getShelvesNum());
                    detail.setStorageShortName(Optional.ofNullable(storageMapper.getName(transferItem.getStorageId()))
                            .map(TBaseStorage::getStorageName)
                            .orElse(""));
                    detail.setCreateBy(SecurityUtils.getUserNick());
                    detail.setLocationId(transferItem.getLocationId());
                    detail.setUpdateTime(DateUtils.getNowDate());
                    detail.setCreateTime(DateUtils.getNowDate());
                    return detail;
                })
                .forEach(tCkOrderdetailMapper::insert);

        // 3. 创建入库通知单
        String transferInboundNoticeId = OrderCodeFactory.getOrderCode("", "");
        Optional.of(new TRkWareNotice())
                .map(notice -> {
                    notice.setDeliveryId(generateUniqueId());
                    notice.setReceivingStatus(InboundNoticeReceivingStatus.CREATED.getCode());
                    notice.setStatus(InboundNoticeReceivingStatus.CREATED.getCode());
                    notice.setStorageMode(InboundStorageMode.TRANSFER.getCode());
                    notice.setApplicant(SecurityUtils.getUserNick());
                    notice.setDeptId(getDeptId());
                    notice.setId(transferInboundNoticeId);
                    notice.setNoticeId(OrderCodeFactory.getOrderCode("TWO", ""));
                    notice.setCreateBy(getUsername());
                    notice.setCreateTime(DateUtils.getNowDate());
                    return notice;
                })
                .filter(notice -> {
                    int cnt = rkWareNoticeMapper.selectTRkWareNoticeByOrginalId(notice.getDeliveryId());
                    if (cnt > 0) {
                        throw new RuntimeException("来源单号重复");
                    }
                    return true;
                })
                .filter(notice -> {
                    int row = rkWareNoticeMapper.insertTRkWareNotice(notice);
                    if (row <= 0) {
                        throw new RuntimeException("入库通知单创建失败");
                    }
                    return true;
                })
                .orElseThrow(() -> new RuntimeException("创建入库通知单失败"));

        // 4. 处理通知单明细
        List<TRkWareNoticeTab> transferInboundNoticeTabs = new ArrayList<TRkWareNoticeTab>();
        transferOrderRequest.getData().stream()
                .map(transferItem -> {
                    TRkWareNoticeTab tab = new TRkWareNoticeTab();
                    tab.setNoticeId(transferInboundNoticeId);
                    tab.setId(OrderCodeFactory.getOrderCode("TRMX", ""));
                    tab.setSalesOrderNumber(OrderCodeFactory.getOrderCode("DBRK", ""));
                    tab.setGoodsId(transferItem.getGoodsId());
                    tab.setGoodsName(transferItem.getGoodsName());
                    tab.setUnit(transferItem.getUnit());
                    tab.setStorageId(transferOrderRequest.getTargetStorageId());
                    tab.setSpecification(transferItem.getSpecification());
                    tab.setPrice(new BigDecimal(transferItem.getPrice()).setScale(2, RoundingMode.HALF_UP));
                    tab.setArraMount(transferItem.getTransferQuantity());
                    tab.setReceiver(InboundReceiverPlaceholder.UNASSIGNED.getCode());
                    tab.setInStatus(InboundNoticeTabInStatus.INITIAL.getCode());
                    tab.setCtl(transferItem.getCtl());
                    tab.setCreateBy(SecurityUtils.getUserNick());
                    tab.setUpdateBy(SecurityUtils.getUserNick());
                    tab.setCreateTime(DateUtils.getNowDate());
                    tab.setUpdateTime(DateUtils.getNowDate());
                    tab.setLevelType(transferItem.getLevelType());
                    tab.setStorageShortName(Optional.ofNullable(storageMapper.getName(transferItem.getStorageId()))
                            .map(TBaseStorage::getStorageName)
                            .orElse(""));
                    transferInboundNoticeTabs.add(tab);
                    return tab;
                }).collect(Collectors.toList());
        rkWareNoticeMapper.batchTRkWareNoticeTab(transferInboundNoticeTabs);

        TransferOrder transferOrder = new TransferOrder();
        transferOrder.setCreator(SecurityUtils.getUserNick());
        transferOrder.setCreationTime(DateUtils.getNowDate());
        StringBuilder transferContentBuilder = new StringBuilder();

        transferOrderRequest.getData().forEach(transferItem -> {
            if (transferContentBuilder.length() > 0) {
                transferContentBuilder.append("; ");
            }

            TBaseStorage sourceStorage = storageMapper.getName(transferItem.getStorageId());
            TBaseStorage targetStorage = storageMapper.getName(transferOrderRequest.getTargetStorageId());
            transferContentBuilder.append("从-->")
                    .append(sourceStorage.getStorageName())
                    .append("调拨物料'")
                    .append(transferItem.getGoodsName())
                    .append("'数量有")
                    .append(transferItem.getTransferQuantity())
                    .append("个调拨到-->")
                    .append(targetStorage.getStorageName());
        });
        transferOrder.setRkId(transferInboundNoticeId);
        transferOrder.setOrderId(transferOutboundOrderId);

        transferOrder.setTransferContent(transferContentBuilder.toString());
        transferOrder.setTransferStatus("创建完成");
        transferOrderMapper.insertTransferOrder(transferOrder);



        return 1;
    }

    @Override
    public Long statisticCallShelvesNum(TCkOrderdetail tCkOrderdetail) {
        //1. 首先查询已审核
        Long aLong = tCkOrdersMapper.queryTotalCallShelvesNum(tCkOrderdetail);
        if(aLong == null){
            aLong = 0L;
        }
        return aLong;
    }


    public static String generateUniqueId() {
        String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        long currentTimeMillis = System.currentTimeMillis();
        String uniqueId = Long.toString(currentTimeMillis, 36).toUpperCase();

        // 获取当前时间
        java.util.Date date = new java.util.Date();
        String hours = String.format("%02d", date.getHours());
        String minutes = String.format("%02d", date.getMinutes());
        String seconds = String.format("%02d", date.getSeconds());

        String timeString = hours + minutes + seconds;

        // 生成随机字母
        Random random = new Random();
        char randomLetter = letters.charAt(random.nextInt(letters.length()));

        return uniqueId + timeString + randomLetter;
    }


    /**
     * 推出库数据
     *
     */
//    @Log(title = "推送数据出库")
    public Map<String, String> sendIwms(TCkOrders outboundOrder) {
        logger.info("推送数据出库====》》》》》");
        Map<String, String> resultMap = new HashMap<>();
        TCkOrders currentOrder = tCkOrdersMapper.selectTCkOrdersById(outboundOrder.getId());
        if (currentOrder != null) {
            BeanUtils.copyProperties(currentOrder, outboundOrder);
        }
        List<TCkOrderdetail> orderDetails = outboundOrder.getTckOrderdetailList();

        List<TCkOrderdetail> agvOrderDetails = orderDetails.stream()
                .filter(orderdetail -> {
                    String isAgv = baseStorageService.getIsAgvByStorageId(orderdetail.getStorageId());
                    return StorageAgvFlag.AGV.getCode().equals(isAgv);
                })
                .collect(Collectors.toList());

        if (agvOrderDetails.isEmpty()) {
            resultMap.put("error", "暂无数据推送");
        }

        List<Map<String, Object>> allDataObjects = new ArrayList<>();
        String reqCode = generateReqCode();
        BigDecimal latestGoodsNum = null;
        for (TCkOrderdetail orderDetail : agvOrderDetails) {
            latestGoodsNum = orderDetail.getGoodsNum();
            LambdaQueryWrapper<TMiStock> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TMiStock::getGoodsId, orderDetail.getGoodsId());
            queryWrapper.eq(TMiStock::getShelvesNum, orderDetail.getStockNum());
            queryWrapper.eq(TMiStock::getGoodsName, orderDetail.getGoodsName());
            queryWrapper.eq(TMiStock::getCtl, orderDetail.getCtl());
            queryWrapper.eq(TMiStock::getStorageId, orderDetail.getStorageId());
            List<TMiStock> matchedStocks = tMiStockMapper.selectList(queryWrapper);
            if (CollectionUtils.isEmpty(matchedStocks)) {
                resultMap.put("error", "库存不存在");
                continue; // Skip this iteration and continue with the next
            }
            TMiStock matchedStock = matchedStocks.get(0);
            Map<String, Object> dataObject = createDataObject(orderDetail, matchedStock, outboundOrder);
            allDataObjects.add(dataObject);
        }

        if (!allDataObjects.isEmpty()) {
            sendAllDataObjects(allDataObjects, reqCode, resultMap, outboundOrder, latestGoodsNum);
        } else {
            resultMap.put("error", "没有有效的订单明细数据发送");
        }
        return resultMap;
    }


    private Map<String, Object> createDataObject(TCkOrderdetail orderDetail, TMiStock stockRecord, TCkOrders outboundOrder) {
        Map<String, Object> requestLine = new HashMap<>();
        requestLine.put("operType", "A");
        requestLine.put("orderType", IwmsOutboundOrderType.OUTBOUND.getCode());
        requestLine.put("orderNum", outboundOrder.getId());
        requestLine.put("orderItem", orderDetail.getId());
        requestLine.put("orderKeyThird", orderDetail.getBusinessId());
        if (stockRecord.getStorageId().startsWith("FJQR")) {
            requestLine.put("whCode", "RZ01");
        } else {
            requestLine.put("whCode", stockRecord.getStorageId());
        }
        requestLine.put("ownerCode", IwmsOwnerCode.DEFAULT_OWNER.getCode());
        BigDecimal outboundQuantity = orderDetail.getGoodsNum();
        requestLine.put("matCode", orderDetail.getGoodsId());
        requestLine.put("matQty", outboundQuantity);
        requestLine.put("traceCode", stockRecord.getCtl());
        requestLine.put("createUser", orderDetail.getApplicant());
        if (stockRecord.getCtl().startsWith("A1")) {
            requestLine.put("outOrderStr2", "KQTRAY");
            requestLine.put("batchAttr07", IwmsBatchAttr07Type.TRAY.getCode());
        } else {
            requestLine.put("outOrderStr2", "KQ2LBOX");
            requestLine.put("batchAttr07", IwmsBatchAttr07Type.BOX.getCode());
        }
        return requestLine;
    }


    private void sendAllDataObjects(List<Map<String, Object>> allDataObjects, String reqCode, Map<String, String> resultMap, TCkOrders outboundOrder, BigDecimal pickQuantity) {
        final String url = "https://172.18.29.101/wms/api/RestJsonService/pushOutOrder";
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("reqCode", reqCode);
        requestData.put("data", allDataObjects);
        String requestBody = "";
        //正式注释
        try {
            requestBody = objectMapper.writeValueAsString(requestData);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        try (CloseableHttpClient httpClient = createHttpClient()) {

            //测试注释
            /*if ("成功".equals("成功")) {
                resultMap.put("success", "消息发送成功");
                List<TCkOrderdetail> list = update.getTckOrderdetailList();
                for (TCkOrderdetail ckOrderdetail : list) {
                    ckOrderdetail.setTrNum(ckOrderdetail.getGoodsNum());
                    //修改订单明细
                    ckOrderdetail.setPickNum(bigDecimal);
                    ckOrderdetail.setCkType("1");
                    tCkOrderdetailMapper.updateById(ckOrderdetail);
                }
            } else {
                resultMap.put("error", "测试");
            }*/
            //测试注释下面的用上面的
            HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("Accept", "application/json");
            httpPost.setHeader("Content-type", "application/json");
            httpPost.setEntity(new StringEntity(requestBody));
            HttpResponse response = httpClient.execute(httpPost);
            String responseString = EntityUtils.toString(response.getEntity(), "UTF-8");
            JsonNode responseJson = objectMapper.readTree(responseString);
            String message = responseJson.get("message").asText();
            if ("成功".equals(message)) {
                resultMap.put("success", "消息发送成功");
                List<TCkOrderdetail> orderDetails = outboundOrder.getTckOrderdetailList();
                for (TCkOrderdetail orderDetail : orderDetails) {
                    orderDetail.setTrNum(orderDetail.getGoodsNum());
                    //修改订单明细
                    orderDetail.setPickNum(pickQuantity);
                    orderDetail.setCkType(OutboundType.STANDARD.getCode());
                    tCkOrderdetailMapper.updateById(orderDetail);
                }
            } else {
                resultMap.put("error", message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String generateReqCode() {
        String hexChars = "0123456789abcdef";
        int len = 20;
        StringBuilder sb = new StringBuilder(len);
        SecureRandom random = new SecureRandom();
        for (int i = 0; i < len; i++) {
            int index = random.nextInt(hexChars.length());
            sb.append(hexChars.charAt(index));
        }
        return sb.toString();
    }

    private SSLContext createTrustAllSslContext() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }

                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }


                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
        };

        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, trustAllCerts, new SecureRandom());
        return sslContext;
    }


    private CloseableHttpClient createHttpClient() throws Exception {
        return HttpClients.custom()
                .setSslcontext(createTrustAllSslContext())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
    }


}
