package com.aps.service.Algorithm;

import com.aps.common.util.GlobalCacheUtil;
import com.aps.common.util.SnowFlackIdWorker;
import com.aps.common.util.redis.RedisUtils;
import com.aps.entity.*;
import com.aps.entity.Algorithm.BOMBuildResult;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.OrderMaterial;
import com.aps.entity.Algorithm.OrderMaterialRequirement;
import com.aps.entity.basic.*;
import com.aps.mapper.RoutingHeaderMapper;
import com.aps.mapper.RoutingSupportingReplaceMapper;
import com.aps.mapper.RoutingsupportingMapper;
import com.aps.service.*;
import com.aps.service.impl.LanuchServiceImpl;
import com.aps.service.plan.MachineSchedulerService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 作者：佟礼
 * 时间：2025-12-08
 */
@Service
public class MaterialRequirementServicebf {

    private List<Material> _materials;

    private List<Entry> _allOperations;

    private List<Machine> _Machines;

    private  List<GroupResult> _entryRel;

    private  List<RoutingHeader> headers;

    private  List<Routingsupporting> routingsupportings=new ArrayList<>();

    private  List<RoutingSupportingReplace> routingsupportingreplaces=new ArrayList<>();

    List<RoutingDetail> allRoutingDetails=new ArrayList<>();
    List<RoutingDetailEquip> allroutingDetailEquips=new ArrayList<>();
    List<RoutingDetailConnect> allroutingDetailconnections=new ArrayList<>();
    List<RoutingDiscreteParam> allroutingDiscreteParams=new ArrayList<>();

    @Autowired
    RoutingDetailConnectService routingDetailConnectService;

    @Autowired
    private RedisUtils redisUtils;

    private  List<Order> orders;

    @Autowired
    RoutingHeaderMapper routingHeaderMapper;

    @Autowired
    RoutingSupportingReplaceMapper routingSupportingReplaceMapper;

    @Autowired
    RoutingsupportingMapper routingsupportingMapper;

    @Autowired
    RoutingDataService _routingDataService;
    @Autowired
    private EquipinfoService equipinfoService;
    @Autowired
    private RoutingDiscreteParamService _routingDiscreteParamService;

    @Autowired
    private   LanuchService lanuchService;
    private  LocalDateTime baseTime ;

    private MachineSchedulerService machineScheduler;

    private GlobalParam globalParam;

    public void init(List<Material> materials,List<Order> _orders,List<Entry> allOperations,List<GroupResult> entryRel,MachineSchedulerService _machineScheduler,List<Machine> machines,GlobalParam _GlobalParam)
    {

        orders = _orders;
        _allOperations=allOperations;
        _materials=materials;
        _entryRel=entryRel;
        machineScheduler=_machineScheduler;
        _Machines=machines;
        globalParam=_GlobalParam;
    }

    private static final int cachetimeout  = 60;
    private String cacheKey="_MR_";
    private String routingHeaderCacheKey=cacheKey+ "RoutingHeader";
    private String routingsupportingCacheKey=cacheKey+ "Routingsupporting";
    private String routingSupportingReplaceCacheKey=cacheKey+ "RoutingSupportingReplace";

    private String routingDetailCacheKey=cacheKey+ "RoutingDetail";
    private String routingDetailEquipCacheKey=cacheKey+ "RoutingDetailEquip";

    private String routingDetailConnectCacheKey=cacheKey+ "RoutingDetailConnect";
    private String routingDiscreteParamCacheKey=cacheKey+ "RoutingDiscreteParam";


    public Map<Integer,Object> preloadRoutingCache(String sceneId,List<Order> _orders,List<Material> materials,boolean isIsCheckSf) {

        Map<Integer,Object> reslte=new HashMap<>(2);
        reslte.put(1,null);
        reslte.put(2,null);
        this._materials=materials;
        List<Integer> routingIds=  _orders.stream()
                .filter(t->t.getRoutingId()!=null)
                .map(Order::getRoutingId)
                .distinct()
                .collect(Collectors.toList());
        List<RoutingHeader> routingHeaders=null;

        LambdaQueryWrapper<RoutingHeader> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(RoutingHeader::getId, routingIds);
//                    .eq(RoutingHeader::getIsDeleted, 0)
//                    .eq(RoutingHeader::getApprovalStatus, 1);
        routingHeaders = routingHeaderMapper.selectList(wrapper);


        List<Routingsupporting> routingsupportings=null;
        //  查询并缓存Routingsupporting

        LambdaQueryWrapper<Routingsupporting> routingsupportingwrapper = new LambdaQueryWrapper<>();
        routingsupportingwrapper.in(Routingsupporting::getRoutingHeaderId, routingIds)
                .eq(Routingsupporting::getIsdeleted, 0);
        routingsupportings = routingsupportingMapper.selectList(routingsupportingwrapper);


        //  查询并缓存RoutingSupportingReplace
        List<RoutingSupportingReplace> replaces=null;
        if (routingsupportings != null && !routingsupportings.isEmpty()) {
            List<String> routingsupportingids = routingsupportings.stream()
                    .map(Routingsupporting::getStrId)
                    .distinct()
                    .collect(Collectors.toList());

            LambdaQueryWrapper<RoutingSupportingReplace> routingsupportingreplacewrapper = new LambdaQueryWrapper<>();
            routingsupportingreplacewrapper.in(RoutingSupportingReplace::getStrsupid, routingsupportingids)
                    .eq(RoutingSupportingReplace::getIsdeleted, 0);
            replaces = routingSupportingReplaceMapper.selectList(routingsupportingreplacewrapper);

        }
        List<Material> useMaterials=new ArrayList<>();
        Set<String> useMaterialids=new HashSet<>();
        if(routingsupportings!=null&&routingsupportings.size()>0)
        {
            List<String> materialIds=new ArrayList<>();
            for (Order order : _orders) {
                Integer routingid=order.getRoutingId();
                List<Routingsupporting> MaterialRequirements = routingsupportings.stream()
                        .filter(t -> t.getRoutingHeaderId().equals(routingid))
                        .collect(Collectors.toList());
                if(MaterialRequirements!=null)
                {
                    List<OrderMaterialRequirement> materialRequirementList=new ArrayList<>();
                    for (Routingsupporting component : MaterialRequirements) {
                        // 查找物料（流式处理替代First）
                        String materialId= component.getMaterialId();
                        Material material = materials.stream()
                                .filter(m -> m.getId().equals(materialId))
                                .findFirst()
                                .orElse(null);
                        if (material != null) {
                            if(!useMaterialids.contains(materialId)) {
                                useMaterials.add(material);
                                useMaterialids.add(materialId);
                            }
//                            OrderMaterialRequirement orderMaterial = new OrderMaterialRequirement();
//                            orderMaterial.setRoutingDetailId(component.getRoutingDetailId());
//                            orderMaterial.setMaterialCode(material.getCode());
//                            orderMaterial.setMaterialName(material.getName());
//                            orderMaterial.setMaterialTypeName(material.getMaterialTypeName());
//                            orderMaterial.setMaterialId(material.getId());
//                            materialRequirementList.add(orderMaterial);
                            if(!material.getMaterialTypeName().equals("MP")&&isIsCheckSf)
                            {
                                materialIds.add(materialId);
                            }
                        }
                        // order.setMaterialRequirementList(materialRequirementList);
                    }
                }
            }
            if(replaces!=null&&replaces.size()>0) {
                for (RoutingSupportingReplace routingSupportingReplace : replaces) {
                    String materialID1 = routingSupportingReplace.getMaterialid();
                    if (!useMaterialids.contains(materialID1)) {
                        Material material = _materials.stream()
                                .filter(m -> m.getId().equals(materialID1))
                                .findFirst()
                                .orElse(null);
                        if (material != null) {
                            useMaterials.add(material);
                            useMaterialids.add(materialID1);
                        }
                    }
                }
            }

            if(materialIds!=null&&materialIds.size()>0)
            {
                Map<Integer,Object> reslte1=preloadSfRoutingBomCache(materialIds, routingHeaders, routingsupportings, replaces);
                List<Long> routingIds1=(List<Long>) reslte1.get(1);
                if(routingIds1!=null)
                {
                    List<Long> equipids=  preloadSfRoutingCache(sceneId,routingIds1);
                    reslte.put(1,equipids);
                }
                List<Material> useMaterials1=(List<Material>) reslte1.get(2);
                if(useMaterials1!=null) {
                    for (Material m:useMaterials1) {
                        String materialID1= m.getId();
                        if(!useMaterialids.contains(materialID1)) {
                            useMaterials.add(m);
                            useMaterialids.add(materialID1);
                        }
                    }
                }
                reslte.put(2,useMaterials);

            }

        }

        SaveBomCache(sceneId, routingHeaders, routingsupportings, replaces);

        return reslte;
    }



    private  Map<Integer,Object> preloadSfRoutingBomCache(List<String> materialIDs,List<RoutingHeader> headers,List<Routingsupporting> routingsupportings,List<RoutingSupportingReplace> routingsupportingreplaces) {

        Map<Integer,Object> reslte=new HashMap<>(2);
        reslte.put(1,null);
        reslte.put(2,null);
        List<Material> useMaterials=new ArrayList<>();
        Set<String> useMaterialids=new HashSet<>();
        List<Long> routingIds=new ArrayList<>();
        List<Long> routingIds1=new ArrayList<>();
        Long routingId = 0l;
        List<Routingsupporting> routingsupportings1 = new ArrayList<>();
        List<RoutingSupportingReplace> routingsupportingreplaces1 = new ArrayList<>();

        for (String materialID:materialIDs) {
            RoutingHeader headers1 = headers.stream()
                    .filter(t -> t.getMaterialId().equals(materialID))
                    .findFirst().orElse(null);
            if (headers1 == null) {
                LambdaQueryWrapper<RoutingHeader> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(RoutingHeader::getMaterialId, materialID)
                        .eq(RoutingHeader::getIsDeleted, 0);
                // .eq(RoutingHeader::getApprovalStatus, 1); // 添加 is_deleted=0 过滤条件
                headers1 = routingHeaderMapper.selectList(wrapper).stream().findFirst().orElse(null);
                if (headers1 != null) {
                    headers.add(headers1);
                    routingId = headers1.getId().longValue();
                    routingIds.add(routingId);
                }
            }else {
                routingIds1.add(headers1.getId().longValue());
            }
        }


        if (routingIds != null&&routingIds.size()>0) {



            LambdaQueryWrapper<Routingsupporting> routingsupportingwrapper = new LambdaQueryWrapper<>();
            routingsupportingwrapper.in(Routingsupporting::getRoutingHeaderId, routingIds)
                    .eq(Routingsupporting::getIsdeleted, 0);

            routingsupportings1 = routingsupportingMapper.selectList(routingsupportingwrapper);
            routingsupportings.addAll(routingsupportings1);

            List<String> routingsupportingids = routingsupportings1.stream()
                    .map(Routingsupporting::getStrId)
                    .distinct()
                    .collect(Collectors.toList());

            LambdaQueryWrapper<RoutingSupportingReplace> routingsupportingreplacewrapper = new LambdaQueryWrapper<>();
            routingsupportingreplacewrapper.in(RoutingSupportingReplace::getStrsupid, routingsupportingids)
                    .eq(RoutingSupportingReplace::getIsdeleted, 0);

            routingsupportingreplaces1 = routingSupportingReplaceMapper.selectList(routingsupportingreplacewrapper);

            routingsupportingreplaces.addAll(routingsupportingreplaces1);

            List<String> materialIds=new ArrayList<>();
            for (Routingsupporting routingsupporting:routingsupportings1) {
                String materialID1= routingsupporting.getMaterialId();
                Material material = _materials.stream()
                        .filter(m -> m.getId().equals(materialID1))
                        .findFirst()
                        .orElse(null);
                if (material != null) {
                    if(!useMaterialids.contains(materialID1)) {
                        useMaterials.add(material);
                        useMaterialids.add(materialID1);
                    }
                    if(!material.getMaterialTypeName().equals("MP")) {
                        materialIds.add(materialID1);
                    }
                }
            }
            for (RoutingSupportingReplace routingSupportingReplace:routingsupportingreplaces1) {
                String materialID1= routingSupportingReplace.getMaterialid();
                if(!useMaterialids.contains(materialID1)) {
                    Material material = _materials.stream()
                            .filter(m -> m.getId().equals(materialID1))
                            .findFirst()
                            .orElse(null);
                    if (material != null) {
                        useMaterials.add(material);
                        useMaterialids.add(materialID1);
                    }
                }
            }

            Map<Integer,Object> r1=preloadSfRoutingBomCache(materialIds, headers, routingsupportings, routingsupportingreplaces);
            List<Long> routingIds2=(List<Long>) r1.get(1);
            List<Material> useMaterials2=( List<Material>) r1.get(2);
            if(routingIds2!=null)
            {
                routingIds.addAll(routingIds2);
            }
            if(useMaterials2!=null&&useMaterials2.size()>0) {
                for (Material m:useMaterials2) {
                    String materialID1= m.getId();
                    if(!useMaterialids.contains(materialID1)) {
                        useMaterials.add(m);
                        useMaterialids.add(materialID1);
                    }
                }
            }
        }
        if(routingIds1!=null)
        {
            routingIds.addAll(routingIds1);
        }
        reslte.put(1,routingIds);
        reslte.put(2,useMaterials);
        return reslte;
    }


    private  List<Long> preloadSfRoutingCache(String sceneId,List<Long> routingIds) {


        List<RoutingDetail> RoutingDetails = null;
        List<RoutingDetailEquip> routingDetailEquips = null;
        List<RoutingDetailConnect> connections = null;
        List<RoutingDiscreteParam> routingDiscreteParams=null;
        if (routingIds != null || routingIds.size() > 0) {

            RoutingDetails = lanuchService.getRoutingDetails(routingIds);

            if (RoutingDetails == null && RoutingDetails.size() == 0) {
                return null;
            }

            routingDetailEquips = lanuchService.getRoutingDetailEquip(routingIds);


            LambdaQueryWrapper<RoutingDetailConnect> routingDetailConnectwrapper = new LambdaQueryWrapper<>();
            routingDetailConnectwrapper.in(RoutingDetailConnect::getRoutingHeaderId, routingIds)
                    .eq(RoutingDetailConnect::getIsdeleted, 0); // 添加 isdeleted=0 过滤条件

            connections = routingDetailConnectService.list(routingDetailConnectwrapper);


            List<Long> routingDetailIds = RoutingDetails.stream()
                    .map(RoutingDetail::getId)
                    .distinct()
                    .collect(Collectors.toList());

            routingDiscreteParams = _routingDiscreteParamService.lambdaQuery()
                    .in(RoutingDiscreteParam::getRoutingDetailId, routingDetailIds)
                    .eq(RoutingDiscreteParam::getIsDeleted, 0)
                    .list();


            SaveDetailCache(sceneId,RoutingDetails,routingDetailEquips,connections,routingDiscreteParams);

            if (routingDetailEquips != null && routingDetailEquips.size() > 0) {

                List<Long> equipIds = routingDetailEquips.stream()
                        .map(RoutingDetailEquip::getEquipId)
                        .distinct() // 提取Exec_ID
                        .collect(Collectors.toList());
                return equipIds;
            }
        }
        return null;
    }


    /**
     * 构建多级BOM需求网络
     * @return 所有物料需求列表
     */
    public List<OrderMaterialRequirement> buildMultiLevelRequirementNetwork(String sceneId,LocalDateTime _baseTime) {
        baseTime=_baseTime;
        List<OrderMaterialRequirement> allRequirements = new ArrayList<>();
        List<Order> childorders = new ArrayList<>();
        List<Entry> _newEntrys = new ArrayList<>();
        List<Machine> _newMachines = new ArrayList<>();
        List<Integer> routingIds = _allOperations.stream()
                .filter(t->t.getRoutingId()!=null)
                .map(Entry::getRoutingId)
                .distinct()
                .collect(Collectors.toList());
        if(routingIds.size()==0)
        {
            return  null;
        }


        for (Order demand : orders) {
            // 跳过已有父订单的需求
            if (demand.getFinishOrderId() != null && !demand.getFinishOrderId().isEmpty()) {
                continue;
            }

            // 递归展开BOM层级（通过结果对象接收out参数数据）
            BOMBuildResult result = buildOrderBOM(demand.getRoutingId(),"", demand.getOrderId(), demand.getOrderId(),
                    demand.getQuantity(), 0,demand,0);
            allRequirements.addAll(result.getMaterialRequirements());
            childorders.addAll(result.getChildOrders());
            _newEntrys.addAll(result.getNewEntrys());
            _newMachines.addAll(result.getNewMachines());


        }

        // 将子订单添加到全局订单列表
        if (orders != null) {
            orders.addAll(childorders);
            // _allOperations.addAll(_newEntrys);

            _Machines.addAll(_newMachines);

        }

        return allRequirements;
    }

    /**
     * 构建订单BOM
     * @param parent 父项ID
     * @param materialID 物料ID
     * @param mainorderId 主订单ID
     * @param childorderId 子订单ID
     * @param parentQuantity 父项数量（Java中用double替代decimal，若需高精度可用BigDecimal）
     * @param level 层级
     * @return 包含物料需求列表和子订单列表的结果对象（替代C#的out参数）
     */
    public BOMBuildResult buildOrderBOM(int parent, String materialID, String mainorderId,
                                        String childorderId, double parentQuantity, int level,Order forder,int finishOpertionID) {
        forder.setCreateBom(true);

        RoutingHeader routingHeaders=  headers.stream()
                .filter(t->t.getId()==parent|| t.getMaterialId().equals(materialID))
                .findFirst()
                .orElse(null);
        List<RoutingHeader>  headers1;
        // 若未找到产品，返回空结果（根据业务可调整为抛出异常）
        if (routingHeaders==null) {

            return null;
        }

        List<OrderMaterialRequirement> materialRequirements = new ArrayList<>();
        List<Order> childorders2 = new ArrayList<>();
        List<Entry> _newEntrys = new ArrayList<>();
        List<Machine> _newMachines = new ArrayList<>();
        // 遍历产品的工序，递归构建工序BOM

        List<Entry> Operations= _allOperations.stream()
                .filter(t->t.getOrderId().equals(childorderId))
                .collect(Collectors.toList());




        if (Operations != null) {
            for (Entry operation : Operations) {
                if(finishOpertionID!=0)
                {
                    if(operation.getTargetFinishedOperationId()==null)
                    {
                        operation.setTargetFinishedOperationId(new ArrayList<>());
                    }
                    operation.getTargetFinishedOperationId().add(finishOpertionID);
                }
                // 调用BuildOperationBOM方法（返回结果对象替代out参数）
                BOMBuildResult operationResult = buildOperationBOM(mainorderId, childorderId,
                        parentQuantity, operation, level,forder);
//                // 合并物料需求和子订单
                if(operationResult!=null) {
                    materialRequirements.addAll(operationResult.getMaterialRequirements());
                    childorders2.addAll(operationResult.getChildOrders());
                    _newEntrys.addAll(operationResult.getNewEntrys());
                    _newMachines.addAll(operationResult.getNewMachines());
                }
            }
        }

        return new BOMBuildResult(materialRequirements, childorders2,_newEntrys);

    }

    private  Map<Integer, Object> CreateChild(Order order,String materialID,int finishOpertionID)
    {
        String sceneId="";
        Long  routingIds=0l;
        List<Routingsupporting> routingsupportings1=new ArrayList<>();
        List<RoutingSupportingReplace> routingsupportingreplaces1 =new ArrayList<>();
        RoutingHeader headers1=  headers.stream()
                .filter(t->t.getMaterialId().equals(materialID))
                .findFirst().orElse(null);
        if(headers1==null) {
            LambdaQueryWrapper<RoutingHeader> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(RoutingHeader::getMaterialId, materialID)
                    .eq(RoutingHeader::getIsDeleted, 0);
            // .eq(RoutingHeader::getApprovalStatus, 1); // 添加 is_deleted=0 过滤条件
            headers1 = routingHeaderMapper.selectList(wrapper).stream().findFirst().orElse(null);
            if(headers1!=null) {
                headers.add(headers1);
                routingIds=headers1.getId().longValue();

                LambdaQueryWrapper<Routingsupporting> routingsupportingwrapper = new LambdaQueryWrapper<>();
                routingsupportingwrapper.in(Routingsupporting::getRoutingHeaderId, routingIds)
                        .eq(Routingsupporting::getIsdeleted, 0);

                routingsupportings1 = routingsupportingMapper.selectList(routingsupportingwrapper);
                routingsupportings.addAll(routingsupportings1);

                List<String> routingsupportingids = routingsupportings1.stream()
                        .filter(t->t.getStrId()!=null)
                        .map(Routingsupporting::getStrId)
                        .distinct()
                        .collect(Collectors.toList());

                if(routingsupportingids.size()>0)
                {
                    LambdaQueryWrapper<RoutingSupportingReplace> routingsupportingreplacewrapper = new LambdaQueryWrapper<>();
                    routingsupportingreplacewrapper.in(RoutingSupportingReplace::getStrsupid, routingsupportingids)
                            .eq(RoutingSupportingReplace::getIsdeleted, 0);

                    routingsupportingreplaces1 = routingSupportingReplaceMapper.selectList(routingsupportingreplacewrapper);

                    routingsupportingreplaces.addAll(routingsupportingreplaces1);
                }

            }
        }
        else {
            routingIds=headers1.getId().longValue();
        }
        if(headers1==null)
        {
            return null;
        }
        Long headersid=routingIds;
        List<RoutingDetail> RoutingDetails=  allRoutingDetails.stream()
                .filter(t->t.getRoutingHeaderId()==headersid)
                .collect(Collectors.toList());
        List<RoutingDetailEquip> routingDetailEquips=null;
        List<RoutingDetailConnect> connections=null;
        if(RoutingDetails==null||RoutingDetails.size()==0) {
            RoutingDetails = lanuchService.getRoutingDetails(headers1.getId());
            allRoutingDetails.addAll(RoutingDetails);
            routingDetailEquips = lanuchService.getRoutingDetailEquip(headers1.getId(), headers1.getCode());
            allroutingDetailEquips.addAll(routingDetailEquips);

            LambdaQueryWrapper<RoutingDetailConnect> routingDetailConnectwrapper = new LambdaQueryWrapper<>();
            routingDetailConnectwrapper.eq(RoutingDetailConnect::getRoutingHeaderId, routingIds)
                    .eq(RoutingDetailConnect::getIsdeleted, 0); // 添加 isdeleted=0 过滤条件

            connections = routingDetailConnectService.list(routingDetailConnectwrapper);
            allroutingDetailconnections.addAll(connections);
        }
        if(routingDetailEquips==null)
        {
            routingDetailEquips=  allroutingDetailEquips.stream()
                    .filter(t->t.getRoutingHeaderId()==headersid)
                    .collect(Collectors.toList());
        }


        order.setRoutingId(headers1.getId());
        order.setRoutingCode(headers1.getCode());
        ProdLaunchOrder prodOrderMain= convertToLaunchOrder(order,"");

        List<RoutingDetailEquip> finalRoutingDetailEquips = routingDetailEquips;
        RoutingHeader finalHeaders = headers1;
        List<ProdProcessExec> processExecList = RoutingDetails.stream()
                .map(detail -> lanuchService.createProcessExec(prodOrderMain, detail, sceneId, finalRoutingDetailEquips, finalHeaders))
                .collect(Collectors.toList());
        List<Equipinfo> equipinfoList = equipinfoService.lambdaQuery().eq(Equipinfo::getIsdeleted, 0).list();
        List<ProdEquipment> ProdEquipmentList=  lanuchService.batchInsertEquipMent(routingDetailEquips, sceneId,processExecList,false,equipinfoList);



        Map<String, String> routingDetailIdToExecIdMap = processExecList.stream()
                .collect(Collectors.toMap(
                        exec -> exec.getRoutingDetailId() + "_" + exec.getOrderId(), // 复合键：工序ID_订单ID
                        ProdProcessExec::getExecId,
                        (existing, replacement) -> existing)); // 处理重复key的情况

        if(connections==null)
        {
            connections=  allroutingDetailconnections.stream()
                    .filter(t->t.getRoutingHeaderId()==headersid)
                    .collect(Collectors.toList());
        }

        List<ProdOrderProcess>  ProdOrderProcesslist=  connections.stream()
                .map(connection -> lanuchService.createProcessRelation(prodOrderMain, connection, sceneId, routingDetailIdToExecIdMap))
                .collect(Collectors.toList());

        List<Long> routingDetailIds = RoutingDetails.stream()
                .map(RoutingDetail::getId)
                .distinct()
                .collect(Collectors.toList());

        List<RoutingDiscreteParam> routingDiscreteParams=  allroutingDiscreteParams.stream()
                .filter(t->routingDetailIds.contains(t.getRoutingDetailId()))
                .collect(Collectors.toList());
        if(routingDiscreteParams==null||routingDiscreteParams.size()==0) {
            routingDiscreteParams = _routingDiscreteParamService.lambdaQuery()
                    .in(RoutingDiscreteParam::getRoutingDetailId, routingDetailIds)
                    .eq(RoutingDiscreteParam::getIsDeleted, 0)
                    .list();
            allroutingDiscreteParams.addAll(routingDiscreteParams);
        }



        List<Order> ProdLaunchOrders=new ArrayList<>();
        ProdLaunchOrders.add(order);

        Map<Integer, Object> list=_routingDataService.CreateEntry( sceneId,  ProdEquipmentList,  ProdLaunchOrders, routingDiscreteParams, ProdOrderProcesslist, processExecList,_entryRel,finishOpertionID );
        List<Machine> machines=new ArrayList<>();
        List<Machine> allmachines = (List<Machine>) GlobalCacheUtil.get("machines");
        if (allmachines == null || allmachines.size() == 0) {


            allmachines = (List<Machine>) redisUtils.get("machines");
            if (allmachines == null || allmachines.size() == 0) {
                List<Long> equipIds = ProdEquipmentList.stream()
                        .map(ProdEquipment::getEquipId)
                        .distinct() // 提取Exec_ID
                        .collect(Collectors.toList());
                machines=allmachines.stream().filter(t->equipIds.contains(t.getId())).collect(Collectors.toList());
            }

        }
        if (machines == null || machines.size() == 0) {
            machines=  _routingDataService.InitCalendarToAllMachines(sceneId,ProdEquipmentList,machineScheduler, globalParam.isIsUseCalendar());

        }

        if(list.get(1)!=null)
        {
            _allOperations.addAll((List<Entry>)list.get(1));
            _entryRel=(List<GroupResult>)list.get(2);
        }
        Map<Integer, Object> rest=new HashMap<>();
        rest.put(1,list.get(1));
        rest.put(2,machines);
        return rest;
    }

    private ProdLaunchOrder convertToLaunchOrder(Order order, String sceneId) {
        try {
            ProdLaunchOrder launchOrder = new ProdLaunchOrder();
            launchOrder.setOrderId(order.getOrderId());
            launchOrder.setSceneId(sceneId);
            launchOrder.setSerie(order.getSerie());
            launchOrder.setCreateUser("GA");
            launchOrder.setMaterialCode(order.getMaterialCode());
            launchOrder.setMaterialName(order.getMaterialName());
//            launchOrder.setStartDate(order.get);
            launchOrder.setEndDate(order.getDueDate());
//            launchOrder.setOrderPriority(order.getPrioritry());
            launchOrder.setOrderPriority(order.getPriority());
            launchOrder.setQuantity(order.getQuantity());
            launchOrder.setMaterialId(order.getMaterialId());


            launchOrder.setRoutingId(order.getRoutingId());
            launchOrder.setRoutingCode("");


            return launchOrder;
        } catch (Exception e) {

            return null;
        }
    }



    /**
     * 构建工序BOM需求
     * @param orderId 主订单ID
     * @param childorderId 子订单ID
     * @param parentQuantity 父项数量
     * @param operation 工序对象
     * @param level 层级
     * @return 包含物料需求列表和子订单列表的结果对象（替代C#的out参数）
     */
    public BOMBuildResult buildOperationBOM(String orderId, String childorderId, double parentQuantity,
                                            Entry operation, int level,Order forder) {
        List<OrderMaterialRequirement> materialRequirements = new ArrayList<>();
        List<Order> _childorders = new ArrayList<>();
        List<Entry> _newEntrys = new ArrayList<>();
        List<Machine> _newMachines = new ArrayList<>();

        List<Routingsupporting> MaterialRequirements=  routingsupportings.stream()
                .filter(t->t.getRoutingDetailId().equals(operation.getRoutingDetailId()))
                .collect(Collectors.toList());

        if (MaterialRequirements != null&&MaterialRequirements.size()>0) {
            for (Routingsupporting component : MaterialRequirements) {

                double allneeded = parentQuantity * component.getMainQty().doubleValue();

                double needed = allneeded;

                // 查找物料（流式处理替代First）
                Material material = _materials.stream()
                        .filter(m -> m.getId().equals(component.getMaterialId()))
                        .findFirst()
                        .orElse(null);
                if (material == null) {
                    return null;
                }

                OrderMaterialRequirement orderMaterial= MaterialStock(material,"",orderId,childorderId,operation,allneeded,needed);
                double useStock=0;
                if(orderMaterial!=null) {
                    useStock = orderMaterial.getUseStock();
                    materialRequirements.add(orderMaterial);
                    orderMaterial.setLevel(level);
                }
                orderMaterial.setMaterialCode(component.getMaterialNumber());
                orderMaterial.setMaterialName(component.getMaterialName());
                needed -= useStock;
                if (needed <= 0) {
                    orderMaterial.setYpQty(allneeded - needed);
                    orderMaterial.setQjQty(needed);
                    continue;
                }

                List<RoutingSupportingReplace> routingsupportingreplaces2 = routingsupportingreplaces.stream().filter(t->t.getStrsupid().equals(component.getStrId())&&t.getMaterialid()!=component.getMaterialId()).collect(Collectors.toList());
                if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 1)
                {
                    for (RoutingSupportingReplace rsr:routingsupportingreplaces2) {
                        OrderMaterialRequirement orderMaterial1= MaterialStock(null,rsr.getMaterialid(),orderId,childorderId,operation,allneeded,needed);
                        if(orderMaterial1!=null) {
                            useStock = orderMaterial1.getUseStock();
                            needed -= useStock;
                            orderMaterial.setUseStock(orderMaterial.getUseStock()+useStock);
                            orderMaterial.getReplaceMaterial().add(orderMaterial1);
                            if (needed <= 0) {
                                break;
                            }
                        }
                    }
                }
                if (needed <= 0) {
                    orderMaterial.setYpQty(allneeded - needed);
                    orderMaterial.setQjQty(needed);
                    continue;
                }
                MaterialInTransit(material,"",orderMaterial,needed);

                needed -= orderMaterial.getUseTransit();

                if (routingsupportingreplaces2 != null && routingsupportingreplaces2.size() > 1)
                {
                    for (RoutingSupportingReplace rsr:routingsupportingreplaces2) {

                        OrderMaterialRequirement  orderMaterial1=    orderMaterial.getReplaceMaterial().stream()
                                .filter(t->t.getMaterialId().equals(rsr.getMaterialid()))
                                .findFirst()
                                .orElse(null);

                        MaterialInTransit(null,rsr.getMaterialid(),orderMaterial1,needed);


                        needed -= orderMaterial1.getUseTransit();
                        LocalDateTime earliestTime= orderMaterial.getArrivalTime().compareTo(orderMaterial1.getArrivalTime())>0?orderMaterial.getArrivalTime():orderMaterial1.getArrivalTime();
                        orderMaterial.setArrivalTime(earliestTime);
                        orderMaterial.setUseTransit(orderMaterial.getUseTransit()+orderMaterial1.getUseTransit());
                        if (needed <= 0) {
                            break;
                        }
                    }
                }

                if (needed <= 0) {
                    orderMaterial.setYpQty(allneeded - needed);
                    orderMaterial.setQjQty(needed);
                    continue;
                }
                if (needed > 0) {
                    orderMaterial.setYpQty(allneeded - needed);
                    orderMaterial.setQjQty(needed);

                    if (material.getMaterialTypeName().equals("MP") ) {
                        // 处理原材料采购时间
                        orderMaterial.setPurchaseStartTime(baseTime);
                        // 采购结束时间 = 采购开始时间 + 采购提前期（天）
                        LocalDateTime purchaseEndTime = baseTime.plusDays(material.getPurchaseLeadTime());
                        orderMaterial.setPurchaseEndTime(purchaseEndTime);
                    } else {
                        // 处理半成品/成品的现有订单


                        List<Order> orders2 = orders.stream()
                                .filter(t -> t.getMaterialId().equals(material.getId())  && t.getSYQuantity() > 0)
                                .sorted(Comparator.comparing(Order::getDueDate))
                                .collect(Collectors.toList());

                        if (!orders2.isEmpty()) {
                            for (Order order : orders2) {
                                if (order.getFinishOrderId() == null) {
                                    order.setFinishOrderId(new ArrayList<>());
                                    order.setTargetFinishedOperationId(new ArrayList<>());
                                }
                                order.getFinishOrderId().add(forder.getId());
                                order.getTargetFinishedOperationId().add(operation.getId());

                                orderMaterial.getProductOrderID().add(order.getId());

                                double useq = Math.min(needed, order.getSYQuantity());
                                needed -= useq;
                                order.setSYQuantity(order.getSYQuantity() - useq);

                                //防止已经生成过一次
                                if (!order.isCreateBom()) {
                                    // 递归构建BOM
                                    int l = level + 1;

                                    BOMBuildResult childResult = buildOrderBOM(0, material.getId(),
                                            orderId, order.getOrderId(),
                                            order.getQuantity(), l,order,operation.getId());
                                    materialRequirements.addAll(childResult.getMaterialRequirements());
                                    _childorders.addAll(childResult.getChildOrders());
                                    _newEntrys.addAll(childResult.getNewEntrys());
                                    _newMachines.addAll(childResult.getNewMachines());
                                    operation.getDependentOnOrderIds().add(order.getId());
                                }

                                if (needed <= 0) {
                                    break;
                                }
                            }
                        }

                        // 更新已配和缺件数量
                        orderMaterial.setYpQty(allneeded - needed);
                        orderMaterial.setQjQty(needed);

                        if (needed > 0&&globalParam.isIsCheckSf()) {
                            // 创建新的子订单
                            Order childorder = new Order();
                            String OrderId = UUID.randomUUID().toString().replace("-", "");

                            childorder.setOrderId(OrderId);
                            childorder.setMaterialId(material.getId());
                            childorder.setMaterialCode(material.getCode());
                            childorder.setMaterialName(material.getName());
                            childorder.setOrderCode(material.getCode());
                            childorder.setQuantity((int) orderMaterial.getQjQty());
                            childorder.setFinishOrderId(new ArrayList<>());
                            childorder.getFinishOrderId().add(forder.getId());
                            childorder.setNewSfCreate(true);
                            childorder.setTargetFinishedOperationId(new ArrayList<>());
                            childorder.getTargetFinishedOperationId().add(operation.getId());
                            childorder.setSerie(forder.getSerie());

                            childorder.setStartDate(forder.getStartDate());
                            childorder.setDueDate(forder.getDueDate());
                            childorder.setPriority(forder.getPriority());
                            childorder.setActualPriority(forder.getActualPriority());


                            Map<Integer, Object> list= CreateChild(childorder,material.getId(), operation.getId());
                            if(list==null)
                            {
                                continue;
                            }
                            _childorders.add(childorder);
                            List<Entry>  newentrys=(List<Entry>)list.get(1);
                            _newEntrys.addAll(newentrys);
                            _newMachines.addAll((List<Machine>)list.get(2));
                            orderMaterial.getProductOrderID().add(childorder.getId());
                            operation.getDependentOnOrderIds().add(childorder.getId());
                            // 递归构建BOM
                            int l = level + 1;
                            BOMBuildResult childResult = buildOrderBOM(0, material.getId(),
                                    orderId, childorder.getOrderId(),
                                    childorder.getQuantity(), l,childorder,0);
                            materialRequirements.addAll(childResult.getMaterialRequirements());
                            _childorders.addAll(childResult.getChildOrders());
                            _newEntrys.addAll(childResult.getNewEntrys());
                            _newMachines.addAll(childResult.getNewMachines());
                        }
                    }
                }

                // 计算预计可用时间
                LocalDateTime arrivalTime = orderMaterial.getArrivalTime();
                LocalDateTime purchaseEndTime = orderMaterial.getPurchaseEndTime();
                LocalDateTime useTime = null;

                if (arrivalTime == null) {
                    useTime = purchaseEndTime;
                } else {
                    if (purchaseEndTime != null && purchaseEndTime.isAfter(arrivalTime)) {
                        useTime = purchaseEndTime;
                    } else {
                        useTime = arrivalTime;
                    }
                }
                orderMaterial.setUseTime(useTime);
            }
        }

        return new BOMBuildResult(materialRequirements, _childorders,_newEntrys);
    }

    private OrderMaterialRequirement MaterialStock(Material material,String materialId,String orderId, String childorderId, Entry operation,double allneeded, double needed ) {

        OrderMaterialRequirement orderMaterial = new OrderMaterialRequirement();
        orderMaterial.setOrderId(orderId);
        orderMaterial.setOperationId(operation.getId());
        orderMaterial.setChildOrderId(StringUtils.isBlank(childorderId) ? orderId : childorderId);
        orderMaterial.setRequiredQuantity(allneeded);

        double availableNow = material.getCurrentStock();
        orderMaterial.setMaterialCode(material.getCode());
        orderMaterial.setMaterialName(material.getName());
        orderMaterial.setMaterialTypeName(material.getMaterialTypeName());
        orderMaterial.setMaterialId(material.getId());
      //  orderMaterial.setCheckLeadTime(material.getCkeckLeadTime());

        // 扣减现有库存


        double useStock = Math.min(needed, availableNow);

        material.setCurrentStock(material.getCurrentStock() - useStock);
        orderMaterial.setUseStock(useStock);

        return orderMaterial;
    }
    private void MaterialInTransit(Material material,String materialId, OrderMaterialRequirement orderMaterial, double needed ){

        // 处理在途物料
        double accumulated = 0;
        LocalDateTime earliestTime = LocalDateTime.of(2000,1,1,0,0,0);
        double useTransit = 0;
        if (material == null) {
            material = _materials.stream()
                    .filter(m -> m.getId().equals(materialId))
                    .findFirst()
                    .orElse(null);
            if (material == null) {
                return ;
            }

        }
        // 按到货时间排序在途物料
        List<MaterialSupply> sortedInTransit = material.getInTransit().stream()
                .filter(t -> t.getQuantity() > 0)
                .sorted(Comparator.comparing(MaterialSupply::getArrivalTime))
                .collect(Collectors.toList());

        for (MaterialSupply supply : sortedInTransit) {
            double useq = Math.min(needed, supply.getQuantity());
            useTransit += useq;
            needed -= useq;
            supply.setQuantity(supply.getQuantity() - useq);
            earliestTime=earliestTime.compareTo(supply.getArrivalTime())>0?earliestTime:supply.getArrivalTime();
            if (needed <= 0) {
                break;
            }
        }

        orderMaterial.setUseTransit(useTransit);
        orderMaterial.setArrivalTime(earliestTime);

    }
    private void  SaveBomCache(String sceneId,List<RoutingHeader> routingHeaders,List<Routingsupporting> routingsupportings,List<RoutingSupportingReplace> replaces)
    {
        redisUtils.set(sceneId+routingHeaderCacheKey,routingHeaders);
        GlobalCacheUtil.put(sceneId+routingHeaderCacheKey,routingHeaders, cachetimeout, TimeUnit.MINUTES);

        redisUtils.set(sceneId+routingsupportingCacheKey,routingsupportings);
        GlobalCacheUtil.put(sceneId+routingsupportingCacheKey,routingsupportings, cachetimeout, TimeUnit.MINUTES);

        redisUtils.set(sceneId+routingSupportingReplaceCacheKey,replaces);
        GlobalCacheUtil.put(sceneId+routingSupportingReplaceCacheKey,replaces, cachetimeout, TimeUnit.MINUTES);

    }
    private void  SaveDetailCache(String sceneId,List<RoutingDetail> RoutingDetails,List<RoutingDetailEquip> routingDetailEquips,List<RoutingDetailConnect> connections,List<RoutingDiscreteParam> routingDiscreteParams)
    {

        redisUtils.set(sceneId+routingDetailCacheKey,RoutingDetails);
        GlobalCacheUtil.put(sceneId+routingDetailCacheKey,RoutingDetails, cachetimeout, TimeUnit.MINUTES);

        redisUtils.set(sceneId+routingDetailEquipCacheKey,routingDetailEquips);
        GlobalCacheUtil.put(sceneId+routingDetailEquipCacheKey,routingDetailEquips, cachetimeout, TimeUnit.MINUTES);

        redisUtils.set(sceneId+routingDetailConnectCacheKey,connections);
        GlobalCacheUtil.put(sceneId+routingDetailConnectCacheKey,connections, cachetimeout, TimeUnit.MINUTES);

        redisUtils.set(sceneId+routingDiscreteParamCacheKey,routingDiscreteParams);
        GlobalCacheUtil.put(sceneId+routingDiscreteParamCacheKey,routingDiscreteParams, cachetimeout, TimeUnit.MINUTES);


    }

    private List<RoutingHeader>  GetRoutingHeader(String sceneId) {
        List<RoutingHeader> RoutingHeaders=(List<RoutingHeader>)GlobalCacheUtil.get(sceneId+routingHeaderCacheKey);
        if(RoutingHeaders==null)
        {
            RoutingHeaders=(List<RoutingHeader>)redisUtils.get(sceneId+routingHeaderCacheKey);
            if(RoutingHeaders!=null)
            {
                GlobalCacheUtil.put(sceneId+routingHeaderCacheKey,RoutingHeaders, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingHeaders;
    }
    private List<Routingsupporting>  GetRoutingsupportings(String sceneId) {
        List<Routingsupporting> Routingsupportings=(List<Routingsupporting>)GlobalCacheUtil.get(sceneId+routingsupportingCacheKey);
        if(Routingsupportings==null)
        {
            Routingsupportings=(List<Routingsupporting>)redisUtils.get(sceneId+routingsupportingCacheKey);
            if(Routingsupportings!=null)
            {
                GlobalCacheUtil.put(sceneId+routingsupportingCacheKey,Routingsupportings, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return Routingsupportings;
    }
    private List<RoutingSupportingReplace>  GetRoutingSupportingReplaces(String sceneId) {
        List<RoutingSupportingReplace> RoutingSupportingReplaces=(List<RoutingSupportingReplace>)GlobalCacheUtil.get(sceneId+routingSupportingReplaceCacheKey);
        if(RoutingSupportingReplaces==null)
        {
            RoutingSupportingReplaces=(List<RoutingSupportingReplace>)redisUtils.get(sceneId+routingSupportingReplaceCacheKey);
            if(RoutingSupportingReplaces!=null)
            {
                GlobalCacheUtil.put(sceneId+routingSupportingReplaceCacheKey,RoutingSupportingReplaces, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingSupportingReplaces;
    }

    private List<RoutingDetail>  GetRoutingDetails(String sceneId) {
        List<RoutingDetail> RoutingDetails=(List<RoutingDetail>)GlobalCacheUtil.get(sceneId+routingDetailCacheKey);
        if(RoutingDetails==null)
        {
            RoutingDetails=(List<RoutingDetail>)redisUtils.get(sceneId+routingDetailCacheKey);
            if(RoutingDetails!=null)
            {
                GlobalCacheUtil.put(sceneId+routingDetailCacheKey,RoutingDetails, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingDetails;
    }

    private List<RoutingDetailEquip>  GetRoutingDetailEquips(String sceneId) {
        List<RoutingDetailEquip> RoutingDetailEquips=(List<RoutingDetailEquip>)GlobalCacheUtil.get(sceneId+routingDetailEquipCacheKey);
        if(RoutingDetailEquips==null)
        {
            RoutingDetailEquips=(List<RoutingDetailEquip>)redisUtils.get(sceneId+routingDetailEquipCacheKey);
            if(RoutingDetailEquips!=null)
            {
                GlobalCacheUtil.put(sceneId+routingDetailEquipCacheKey,RoutingDetailEquips, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingDetailEquips;
    }

    private List<RoutingDetailConnect>  GetRoutingDetailConnect(String sceneId) {
        List<RoutingDetailConnect> RoutingDetailConnects=(List<RoutingDetailConnect>)GlobalCacheUtil.get(sceneId+routingDetailConnectCacheKey);
        if(RoutingDetailConnects==null)
        {
            RoutingDetailConnects=(List<RoutingDetailConnect>)redisUtils.get(sceneId+routingDetailConnectCacheKey);
            if(RoutingDetailConnects!=null)
            {
                GlobalCacheUtil.put(sceneId+routingDetailConnectCacheKey,RoutingDetailConnects, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingDetailConnects;
    }

    private List<RoutingDiscreteParam>  GetRoutingDiscreteParam(String sceneId) {
        List<RoutingDiscreteParam> RoutingDiscreteParams=(List<RoutingDiscreteParam>)GlobalCacheUtil.get(sceneId+routingDiscreteParamCacheKey);
        if(RoutingDiscreteParams==null)
        {
            RoutingDiscreteParams=(List<RoutingDiscreteParam>)redisUtils.get(sceneId+routingDiscreteParamCacheKey);
            if(RoutingDiscreteParams!=null)
            {
                GlobalCacheUtil.put(sceneId+routingDiscreteParamCacheKey,RoutingDiscreteParams, cachetimeout, TimeUnit.MINUTES);
            }
        }
        return RoutingDiscreteParams;
    }
    public void clearCache(String sceneId) {


        redisUtils.del(sceneId+routingHeaderCacheKey);
        GlobalCacheUtil.remove(sceneId+routingHeaderCacheKey);

        redisUtils.del(sceneId+routingsupportingCacheKey);
        GlobalCacheUtil.remove(sceneId+routingsupportingCacheKey);

        redisUtils.del(sceneId+routingSupportingReplaceCacheKey);
        GlobalCacheUtil.remove(sceneId+routingSupportingReplaceCacheKey);

        redisUtils.del(sceneId+routingDetailCacheKey);
        GlobalCacheUtil.remove(sceneId+routingDetailCacheKey);

        redisUtils.del(sceneId+routingDetailEquipCacheKey);
        GlobalCacheUtil.remove(sceneId+routingDetailEquipCacheKey);

        redisUtils.del(sceneId+routingDetailConnectCacheKey);
        GlobalCacheUtil.remove(sceneId+routingDetailConnectCacheKey);

        redisUtils.del(sceneId+routingDiscreteParamCacheKey);
        GlobalCacheUtil.remove(sceneId+routingDiscreteParamCacheKey);


    }
}
