package com.rongwei.bscommon.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.rongwei.bscommon.sys.dao.ApsBlankOrderDao;
import com.rongwei.bscommon.sys.fegin.RwApsServer;
import com.rongwei.bscommon.sys.service.*;
import com.rongwei.bsentity.domain.*;
import com.rongwei.bsentity.vo.*;
import com.rongwei.commonservice.service.RedisService;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.exception.CustomException;
import com.rongwei.rwcommon.utils.DateUtils;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.safecommon.utils.SaveConstans;
import org.apache.commons.math3.stat.descriptive.summary.Product;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

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

import static com.rongwei.safecommon.utils.SaveConstans.LockmarkType.LOCKMARK_Y;

@Service
public class ApsServiceImpl implements ApsService {

    private static final Logger logger = LoggerFactory.getLogger(ApsServiceImpl.class);
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ApsBlankOrderService apsBlankOrderService;
    @Autowired
    private ApsBlankOrderDao apsBlankOrderDao;
    @Autowired
    private RwApsServer rwApsServer;
    @Autowired
    private ApsScheduleConfigService apsScheduleConfigService;
    @Autowired
    private AspCheckItemsService aspCheckItemsService;
    @Autowired
    private ApsProcessOperationService apsProcessOperationService;
    @Autowired
    private ApsProcessOperationProcessEquServiceImpl processOperationProcessEquService;
    @Autowired
    private ApsEquipmentCalendarService apsEquipmentCalendarService;
    @Autowired
    private ApsProcessOperationOutMaterService apsProcessOperationOutMaterService;
    @Autowired
    private ApsFurnaceInstallationService apsFurnaceInstallationService;
    @Autowired
    private ApsMergeFurnaceService apsMergeFurnaceService;
    @Autowired
    private ApsProductionOrderService apsProductionOrderService;
    @Autowired
    private ApsAnnealingDifferenceService apsAnnealingDifferenceService;

    /**
     * Aps排程
     * @param apsBlankOrders
     * @param apsType cd：插单
     */
    @Override
    public void apsSchedule(List<ApsBlankOrderVo> apsBlankOrders,String apsType,SysUserVo currentUser) {
        // 当前等路人所属工厂
        if(currentUser == null){
            currentUser = CXCommonUtils.getCurrentUser();
        }
        String tenantId = CXCommonUtils.getCurrentUserFactoryId(currentUser);
        if (StringUtils.isBlank(tenantId)) {
            throw new CustomException("所属工厂不能为空");
        }
        assert apsBlankOrders != null : "排程订单不能为空";
        // 按照所属工厂加锁
        RLock rLock = redissonClient.getLock(tenantId);
        boolean isLocked = rLock.isLocked();
        // 锁是否被占用
        if(isLocked){
            throw new CustomException("正在排程、请稍等一会！");
        }else{
            try {
                // 加锁最大1小时
                rLock.lock(24, TimeUnit.HOURS);
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
                // 合并待发布未锁定的订单一起排程
                String idStrs = null;
                if(apsBlankOrders != null && apsBlankOrders.size()>0){
                    List<String> hasIds = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
                    idStrs = CollUtil.join(hasIds, "','");
                    idStrs = "'" + idStrs + "'";
                }
                // 查询存在未锁定的作业坯料计划
                // 插单重排会优先排插单再排程其它的订单
                if("cd".equals(apsType) && apsBlankOrders != null && apsBlankOrders.size()>0){
                    for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
                        apsBlankOrder.setCdbs(1);
                    }
                }else{
                    for (ApsBlankOrderVo apsBlankOrder : apsBlankOrders) {
                        apsBlankOrder.setCdbs(2);
                    }
                }
                List<ApsBlankOrderVo> fbNotLock = apsBlankOrderDao.getOrdersHasNotLockProcess(idStrs,tenantId);
                if (fbNotLock != null && fbNotLock.size() > 0) {
                    for (ApsBlankOrderVo apsBlankOrderVo : fbNotLock) {
                        apsBlankOrderVo.setCdbs(2);
                    }
                    apsBlankOrders.addAll(fbNotLock);
                }
                apsOrderSchedule(apsBlankOrders);


                // 1卷排程
                /*if(singleApsList != null && singleApsList.size()>0){
                    // 模型转换
                    ProductionScheduleVo productionScheduleVo = apsProductionScheduleInit(singleApsList);
                    // 排程计划设备集合
                    List<String> blankids = singleApsList.stream().map(ApsBlankOrderVo::getId).collect(Collectors.toList());
                    List<Equipment> equipmentList1 = new ArrayList<>();
                    List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                            .in(ApsProcessOperationDo::getBlankid, blankids));
                    for (ApsProcessOperationDo operationDo : operationDos1) {
                        List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,blankids,null,productionScheduleVo,apsConfigs.get(0));
                    }
                    productionScheduleVo.setEquipmentList(equipmentList1);

                    System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                    logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                    // APS平台排程接口调用
                    ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
                    if (!"200".equals(productionScheduleRetVo.getCode())) {
                        throw new CustomException(productionScheduleRetVo.getMsg());
                    }
                    // 获取坯料计划
                    apsBlankOrderService.apsAfter(productionScheduleRetVo,singleApsList);
                }*/

                /*if(productionScheduleVos != null && productionScheduleVos.size()>0){
                    // 提前退火排程
                    *//*ProductionScheduleVo productionScheduleThVo = new ProductionScheduleVo();
                    productionScheduleThVo.setProductionScheduleId("提前退火排程-"+SecurityUtil.getUUID());
                    productionScheduleThVo.setApsPlanStartDate(productionScheduleVos.get(0).getApsPlanStartDate());
                    productionScheduleThVo.setPlanSeconds(productionScheduleVos.get(0).getPlanSeconds());
                    productionScheduleThVo.setRoamTime(productionScheduleVos.get(0).getRoamTime());
                    productionScheduleThVo.setEnvironmentMode(productionScheduleVos.get(0).getEnvironmentMode());
                    productionScheduleThVo.setWashingtime(productionScheduleVos.get(0).getWashingtime());
                    productionScheduleThVo.setStandingtime(productionScheduleVos.get(0).getStandingtime());
                    productionScheduleThVo.setLooseness(productionScheduleVos.get(0).getLooseness());
                    productionScheduleThVo.setPcspeed(productionScheduleVos.get(0).getPcspeed());
                    List<ProductionProcesses> pros = new ArrayList<>();
                    List<String> thBlankIds = new ArrayList<>();
                    Map<String,List<String>> blankProcessIds = new HashMap<>();
                    List<WashingMetal> closealloynames = new ArrayList<>();
                    for (ProductionScheduleVo productionScheduleVo : productionScheduleVos) {
                        pros.addAll(productionScheduleVo.getProcesses());
                        for (ProductionProcesses pross : productionScheduleVo.getProcesses()) {
                            for (ProduceOrder produceOrder : pross.getProduceOrder()) {
                                thBlankIds.add(produceOrder.getId());
                            }
                        }
                        blankProcessIds.putAll(productionScheduleVo.getBlankProcessIds());
                        closealloynames.addAll(productionScheduleVo.getClosealloynames());
                    }
                    productionScheduleThVo.setProcesses(pros);
                    productionScheduleThVo.setBlankProcessIds(blankProcessIds);
                    productionScheduleThVo.setClosealloynames(closealloynames);
                    // 退火设备列表
                    thBlankIds = thBlankIds.stream().distinct().collect(Collectors.toList());
                    // 排程计划设备集合
                    List<Equipment> equipmentList = new ArrayList<>();
                    List<ApsProcessOperationDo> operationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                            .in(ApsProcessOperationDo::getBlankid, thBlankIds));
                    for (ApsProcessOperationDo operationDo : operationDos) {
                        List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList,eqMaps,thBlankIds,null,productionScheduleThVo,apsConfigs.get(0));
                    }
                    productionScheduleThVo.setEquipmentList(equipmentList);

                    // 退火排程
                    System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleThVo, jsonConfig));
                    logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleThVo, jsonConfig));
                    // APS平台排程接口调用
                    ProductionScheduleRetVo productionScheduleRetThVo = rwApsServer.productionThSchedule(productionScheduleThVo);
                    if (!"200".equals(productionScheduleRetThVo.getCode())) {
                        throw new CustomException(productionScheduleRetThVo.getMsg());
                    }*//*

                    // 全部排程，每4个一组
                    Map<String,ProductionProcesses> allProcesses = new HashMap<>();
                    List<ProductionProcesses> rootProcesses = new ArrayList<>();
                    for (ProductionScheduleVo productionScheduleVo : productionScheduleVos) {
                        for (ProductionProcesses process : productionScheduleVo.getProcesses()) {
                            allProcesses.put(process.getId(),process);
                            if(process.getPreviousProcessesIds() == null || process.getPreviousProcessesIds().size() == 0){
                                rootProcesses.add(process);
                            }
                        }
                    }

                    for (ProductionScheduleVo productionScheduleVo : productionScheduleVos) {
                        for (ProductionProcesses process : productionScheduleVo.getProcesses()) {
                            allProcesses.put(process.getId(),process);
                            if(process.getPreviousProcessesIds() == null || process.getPreviousProcessesIds().size() == 0){
                                rootProcesses.add(process);
                            }
                        }
                    }

                    // 坯料计划排序
                    Collections.sort(rootProcesses,(v1,v2)->{
                        // 合金
                        String alloy1 = v1.getVolumeMetal();
                        String alloy2 = v2.getVolumeMetal();
                        // 合金状态
                        String alloystatus1 = v1.getVolumeMetalstate();
                        String alloystatus2 = v2.getVolumeMetalstate();
                        // 产品类型
                        String producttype1 = v1.getProducttype();
                        String producttype2 = v2.getProducttype();
                        // 宽度
                        BigDecimal prowidth1 = v1.getVolumeWidth();
                        BigDecimal prowidth2 = v2.getVolumeWidth();
                        // 厚度
                        BigDecimal thickness1 = v1.getVolumeThickness();
                        BigDecimal thickness2 = v2.getVolumeThickness();
                        // 重量
                        BigDecimal singlerollweight1 = v1.getSinglerollweight();
                        BigDecimal singlerollweight2 = v2.getSinglerollweight();

                        int a = 0;
                        // 宽度
                        if(prowidth1.compareTo(prowidth2) == 0){
                            // 合金
                            if(alloy1.compareTo(alloy2) == 0){
                                // 产品类型
                                if(producttype1 == null || producttype2 == null || producttype1.compareTo(producttype2) == 0){
                                    // 厚度
                                    if(thickness1.compareTo(thickness2) == 0){
                                        // 合金状态
                                        if(alloystatus1 == null || alloystatus2 == null || alloystatus1.compareTo(alloystatus2) == 0){
                                            // 重量
                                            if(singlerollweight1.compareTo(singlerollweight2) == 0){
                                                a = 0;
                                            }else if(singlerollweight1.compareTo(singlerollweight2) > 0){
                                                a = -1;
                                            }else{
                                                a = 1;
                                            }
                                        }else{
                                            a = alloystatus1.compareTo(alloystatus2);
                                        }
                                    }else{
                                        if(thickness1.compareTo(thickness2) > 0){
                                            a = -1;
                                        }else{
                                            a = 1;
                                        }
                                    }
                                }else{
                                    a = producttype1.compareTo(producttype2);
                                }
                            }else{
                                a = alloy1.compareTo(alloy2);
                            }
                        }else{
                            if(prowidth1.compareTo(prowidth2) > 0){
                                a = -1;
                            }else{
                                a = 1;
                            }
                        }
                        return a;
                    });
                    List<List<ProductionProcesses>> chunks = new ArrayList<>();
                    int listSize = rootProcesses.size();
                    for (int i = 0; i < listSize; i += 4) {
                        chunks.add(rootProcesses.subList(i, Math.min(i + 4, listSize)));
                    }

                    // 全部排程，每4个一组
                    for (List<ProductionProcesses> rootpros : chunks) {
                        ProductionScheduleVo productionScheduleVo = productionScheduleVoInit();
                        // 工序作业ID
                        Set<String> opId = new LinkedHashSet<>();
                        Set<String> orderIds = new LinkedHashSet<>();
                        List<ProductionProcesses> pssall = new ArrayList<>();
                        for (ProductionProcesses processes : rootpros) {
                            pssall.add(processes);
                            for (String s : processes.getBsProcessesId()) {
                                opId.add(s);
                            }
                            for (ProduceOrder produceOrder : processes.getProduceOrder()) {
                                orderIds.add(produceOrder.getId());
                            }
                            getAllNextPross(processes,allProcesses,pssall,opId);
                        }
                        // 退火工序锁定
                        *//*if(productionScheduleRetThVo.getProcesses() != null && productionScheduleRetThVo.getProcesses().size()>0){
                            for (ProductionProcesses process : pssall) {
                                for (ProductionProcesses productionScheduleRetThVoProcess : productionScheduleRetThVo.getProcesses()) {
                                    if(productionScheduleRetThVoProcess.getId().equals(process.getId())){
                                        process.setEquipmentId(productionScheduleRetThVoProcess.getEquipmentId());
                                        List<String> opeqs = new ArrayList<>();
                                        opeqs.add(productionScheduleRetThVoProcess.getEquipmentId());
                                        process.setOptionalEquipments(opeqs);
                                        process.setDelay(0);
                                        process.setStartTime(productionScheduleRetThVoProcess.getStartTime());
                                        process.setEndTime(productionScheduleRetThVoProcess.getEndTime());
                                        process.setIfLock(true);
                                    }
                                }
                            }
                        }*//*
                        // 排程计划设备集合
                        List<Equipment> equipmentList1 = new ArrayList<>();
                        List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                                .in(ApsProcessOperationDo::getId, opId));
                        for (ApsProcessOperationDo operationDo : operationDos1) {
                            List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,null,opId,productionScheduleVo,apsConfigs.get(0));
                        }
                        productionScheduleVo.setEquipmentList(equipmentList1);
                        productionScheduleVo.setProcesses(pssall);

                        System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                        logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                        // APS平台排程接口调用
                        ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
                        if (!"200".equals(productionScheduleRetVo.getCode())) {
                            throw new CustomException(productionScheduleRetVo.getMsg());
                        }
                        // 获取坯料计划
                        List<ApsBlankOrderVo> apsBlankOrderss = new ArrayList<>();
                        for (String orderId : orderIds) {
                            ApsBlankOrderVo apsBlankOrderVo = dataMapOrder.get(orderId);
                            if(apsBlankOrderVo != null){
                                apsBlankOrderss.add(apsBlankOrderVo);
                            }
                        }

                        apsBlankOrderService.apsAfter(productionScheduleRetVo,apsBlankOrderss);
                    }

                    *//*for (ProductionScheduleVo productionScheduleVo : productionScheduleVos) {
                        // 退火工序锁定
                        if(productionScheduleRetThVo.getProcesses() != null && productionScheduleRetThVo.getProcesses().size()>0){
                            for (ProductionProcesses process : productionScheduleVo.getProcesses()) {
                                for (ProductionProcesses productionScheduleRetThVoProcess : productionScheduleRetThVo.getProcesses()) {
                                    if(productionScheduleRetThVoProcess.getId().equals(process.getId())){
                                        process.setEquipmentId(productionScheduleRetThVoProcess.getEquipmentId());
                                        List<String> opeqs = new ArrayList<>();
                                        opeqs.add(productionScheduleRetThVoProcess.getEquipmentId());
                                        process.setOptionalEquipments(opeqs);
                                        process.setDelay(0);
                                        process.setStartTime(productionScheduleRetThVoProcess.getStartTime());
                                        process.setEndTime(productionScheduleRetThVoProcess.getEndTime());
                                        process.setIfLock(true);
                                    }
                                }
                            }
                        }
                        // 设备列表赋值
                        List<String> blankIds = new ArrayList<>();
                        for (ProductionProcesses pross : productionScheduleVo.getProcesses()) {
                            for (ProduceOrder produceOrder : pross.getProduceOrder()) {
                                blankIds.add(produceOrder.getId());
                            }
                        }
                        blankIds = blankIds.stream().distinct().collect(Collectors.toList());
                        // 排程计划设备集合
                        List<Equipment> equipmentList1 = new ArrayList<>();
                        List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                                .in(ApsProcessOperationDo::getBlankid, blankIds));
                        for (ApsProcessOperationDo operationDo : operationDos1) {
                            List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,blankIds,null,productionScheduleVo,apsConfigs.get(0));
                        }
                        productionScheduleVo.setEquipmentList(equipmentList1);

                        System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                        logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
                        // APS平台排程接口调用
                        ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
                        if (!"200".equals(productionScheduleRetVo.getCode())) {
                            throw new CustomException(productionScheduleRetVo.getMsg());
                        }
                        apsBlankOrderService.apsAfter(productionScheduleRetVo,dataMap.get(productionScheduleVo.getProductionScheduleId()));
                    }*//*
                }*/
            } catch (Exception e) {
                e.printStackTrace();
                logger.info("排程异常" + e);
                String msg = "排程服务异常";
                if(e instanceof CustomException){
                    msg = e.getMessage();
                }
                currentUser.setRoption(msg);
                redisService.redisCatchInit("apsUser-"+tenantId,currentUser,3600*24);
                throw e;
            } finally {
                rLock.forceUnlock();
                System.out.println("解锁....");
                logger.info("解锁....");
            }
        }
    }

    private void apsOrderSchedule(List<ApsBlankOrderVo> apsBlankOrders){
        // 坯料计划排序
        Collections.sort(apsBlankOrders,(v1,v2)->{
            // 合金
            String alloy1 = v1.getAlloy();
            String alloy2 = v2.getAlloy();
            // 合金状态
            String alloystatus1 = v1.getAlloystatus();
            String alloystatus2 = v2.getAlloystatus();
            // 产品类型
            String producttype1 = v1.getProducttype();
            String producttype2 = v2.getProducttype();
            // 宽度
            BigDecimal prowidth1 = v1.getProwidth();
            BigDecimal prowidth2 = v2.getProwidth();
            // 厚度
            BigDecimal thickness1 = v1.getThickness();
            BigDecimal thickness2 = v2.getThickness();
            // 重量
            BigDecimal singlerollweight1 = v1.getSinglerollweight();
            BigDecimal singlerollweight2 = v2.getSinglerollweight();

            int a = 0;
            // 插单优先
            if(v1.getCdbs().compareTo(v2.getCdbs()) == 0){
                // 合金
                if(alloy1.compareTo(alloy2) == 0){
                    // 产品类型
                    if(producttype1 == null || producttype2 == null || producttype1.compareTo(producttype2) == 0){
                        // 宽度
                        if(prowidth1.compareTo(prowidth2) == 0){
                            // 厚度
                            if(thickness1.compareTo(thickness2) == 0){
                                // 合金状态
                                if(alloystatus1 == null || alloystatus2 == null || alloystatus1.compareTo(alloystatus2) == 0){
                                    // 重量
                                    if(singlerollweight1.compareTo(singlerollweight2) == 0){
                                        // 按照订单排序
                                        if(v1.getProductionorderid().compareTo(v2.getProductionorderid()) == 0){
                                            // 卷数从大到小
                                            a = v2.getRollnum().compareTo(v1.getRollnum());
                                        }else{
                                            a = v1.getProductionorderid().compareTo(v2.getProductionorderid());
                                        }
                                    }else if(singlerollweight1.compareTo(singlerollweight2) > 0){
                                        a = -1;
                                    }else{
                                        a = 1;
                                    }
                                }else{
                                    a = alloystatus1.compareTo(alloystatus2);
                                }
                            }else{
                                if(thickness1.compareTo(thickness2) > 0){
                                    a = -1;
                                }else{
                                    a = 1;
                                }
                            }
                        }else{
                            if(prowidth1.compareTo(prowidth2) > 0){
                                a = -1;
                            }else{
                                a = 1;
                            }
                        }
                    }else{
                        a = producttype1.compareTo(producttype2);
                    }
                }else{
                    a = alloy1.compareTo(alloy2);
                }
            }else{
                a = v1.getCdbs().compareTo(v2.getCdbs());
            }
            return a;
        });
        // 排程前解锁所有待排程订单
        List<String> blankOrderIds = new ArrayList<>();
        apsBlankOrders.forEach((bo)->{
            blankOrderIds.add(bo.getId());
        });
        // 更新待排程的锁定的作业
        if(blankOrderIds != null && blankOrderIds.size()>0){
            String blankidStrs = CollUtil.join(blankOrderIds, "','");
            blankidStrs = "'" + blankidStrs + "'";
            apsBlankOrderDao.setLockMarkNullByToAps(blankidStrs);

            // 更新排程明细数据锁定状态为否
            /*processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"n")
                    .in(ApsProcessOperationProcessEquDo::getBlankid,blankOrderIds));*/
            apsBlankOrderDao.setProDetailLockMark(blankidStrs);
        }
        // 排程
        List<ProductionScheduleVo> productionScheduleVos = new ArrayList<>();
        Map<String,List<ApsBlankOrderVo>> dataMap = new HashMap<>();
        Map<String,ApsBlankOrderVo> dataMapOrder = new HashMap<>();
        JSONConfig jsonConfig = JSONConfig.create();
        jsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        // 所有设备
        List<AspCheckItemsDo> eqs = aspCheckItemsService.list(new LambdaQueryWrapper<>());
        Map<String, AspCheckItemsDo> eqMaps = new HashMap<>();
        for (AspCheckItemsDo eq : eqs) {
            eqMaps.put(eq.getId(), eq);
        }
        // 1卷一起排
        List<ApsBlankOrderVo> singleApsList = new ArrayList<>();
        // 多卷先排
        apsBlankOrders.forEach((bo)->{
            List<ApsBlankOrderVo> v = new ArrayList<>();
            v.add(bo);
            dataMapOrder.put(bo.getId(),bo);

            // 模型转换
            ProductionScheduleVo productionScheduleVo = apsProductionScheduleInit(v);
            productionScheduleVos.add(productionScheduleVo);
            dataMap.put(productionScheduleVo.getProductionScheduleId(),v);
//                        int mergeThNum = mergeThNum(bo, productionScheduleVo);
            // 排程计划设备集合
            List<Equipment> equipmentList1 = new ArrayList<>();
            List<ApsProcessOperationDo> operationDos1 = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                    .in(ApsProcessOperationDo::getBlankid, bo.getId()));
            List<String> blankids = new ArrayList<>();
            blankids.add(bo.getId());
            for (ApsProcessOperationDo operationDo : operationDos1) {
                List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList1,eqMaps,blankids,null,productionScheduleVo,apsConfigs.get(0));
            }
            productionScheduleVo.setEquipmentList(equipmentList1);

            System.out.println("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
            logger.info("排程数据：" + JSONUtil.toJsonStr(productionScheduleVo, jsonConfig));
            // APS平台排程接口调用
            ProductionScheduleRetVo productionScheduleRetVo = rwApsServer.productionSchedule(productionScheduleVo);
            if (!"200".equals(productionScheduleRetVo.getCode())) {
                logger.info("排程异常，坯料计划ID：" + bo.getId());
                // 排程异常后恢复历史排程结果为锁定状态
                processOperationProcessEquService.update(new LambdaUpdateWrapper<ApsProcessOperationProcessEquDo>().set(ApsProcessOperationProcessEquDo::getLockmark,"y")
                        .eq(ApsProcessOperationProcessEquDo::getBlankid,bo.getId()));
                // 没有可排程工序的订单跳过
                if("没有可排程的工序".equals(productionScheduleRetVo.getMsg())){
                    logger.info("排程异常：没有可排程的工序，坯料计划编号：" + bo.getBlanknumber());
                }else{
                    throw new CustomException(productionScheduleRetVo.getMsg());
                }
            }else{
                // 获取坯料计划
                List<ApsBlankOrderVo> apsBlankOrderss = new ArrayList<>();
                apsBlankOrderss.add(bo);
                apsBlankOrderService.apsAfter(productionScheduleRetVo,apsBlankOrderss);
            }
        });
    }

    /**
     * 计算合并退火的个数
     * @return
     */
    private int mergeThNum(ApsBlankOrderVo apsBlankOrderVo,ProductionScheduleVo productionScheduleVo){
        int a = 4;
        List<ProductionProcesses> thpros = productionScheduleVo.getProcesses().stream().filter(v ->
                v.getProcessType().equals("成退") || v.getProcessType().equals("小卷成退") || v.getProcessType().equals("中退")
        ).collect(Collectors.toList());
        if(thpros != null && thpros.size()>0){
            String eqid = thpros.get(0).getOptionalEquipments().get(0);
            AspCheckItemsDo checkItemsDo = aspCheckItemsService.getById(eqid);
            if(checkItemsDo != null && checkItemsDo.getEquipmentbearing() != null){
                a = checkItemsDo.getEquipmentbearing().divide(apsBlankOrderVo.getSinglerollweight(), 2, RoundingMode.HALF_UP).intValue();
            }
        }
        return a;
    }

    private void getAllNextPross(ProductionProcesses rootProcesses,Map<String,ProductionProcesses> allProcesses,List<ProductionProcesses> pss,Set<String> opId){
        if(rootProcesses.getNextProcessesIds() != null && rootProcesses.getNextProcessesIds().size()>0){
            for (String nextProcessesId : rootProcesses.getNextProcessesIds()) {
                ProductionProcesses processes = allProcesses.get(nextProcessesId);
                if(processes != null){
                    pss.add(processes);
                    for (String s : processes.getBsProcessesId()) {
                        opId.add(s);
                    }
                    getAllNextPross(processes,allProcesses,pss,opId);
                }
            }
        }
    }

    private ProductionScheduleVo productionScheduleVoInit(){
        ProductionScheduleVo productionScheduleVo = new ProductionScheduleVo();
        productionScheduleVo.setProductionScheduleId("批量排程-"+SecurityUtil.getUUID());
        List<ApsScheduleConfigDo> apsConfigs = apsScheduleConfigService.list();
        ApsScheduleConfigDo apsScheduleConfig = null;
        // 松散度
        if (apsConfigs != null && apsConfigs.size() > 0) {
            apsScheduleConfig = apsConfigs.get(0);
            productionScheduleVo.setLooseness(apsScheduleConfig.getLooseness());
            productionScheduleVo.setPlanSeconds(apsScheduleConfig.getScheduleruntime());
            productionScheduleVo.setPcspeed(apsScheduleConfig.getPcspeed());
            Map<String, Integer> roamTime = new HashMap<>();
            Integer workshopin = apsScheduleConfig.getWorkshopin();
            Integer workshopcross = apsScheduleConfig.getWorkshopcross();
            roamTime.put("WORKSHOP_IN", workshopin);
            roamTime.put("WORKSHOP_CROSS", workshopcross);
            productionScheduleVo.setRoamTime(roamTime);
            // 排程计划开始时间
            int a = 8;
            if (apsScheduleConfig.getStartschedulerun() != null) {
                a = apsScheduleConfig.getStartschedulerun();
            }
            if (apsScheduleConfig.getApsplanstartdate() != null) {
                productionScheduleVo.setApsPlanStartDate(apsScheduleConfig.getApsplanstartdate());
            } else {
                productionScheduleVo.setApsPlanStartDate(DateUtil.parseDate(DateUtils.format(DateUtil.date(),"yyyy-MM-dd HH:mm")).offset(DateField.HOUR, a));
            }
            productionScheduleVo.setWashingtime(apsScheduleConfig.getWashingtime());
            productionScheduleVo.setStandingtime(apsScheduleConfig.getStandingtime());
            productionScheduleVo.setStandingyield(apsScheduleConfig.getStandingyield());
            productionScheduleVo.setExpecteddays(apsScheduleConfig.getExpecteddays());
            if(productionScheduleVo.getStandingyield() == null){
                productionScheduleVo.setStandingyield(60);
            }
            productionScheduleVo.setMiddifference(apsScheduleConfig.getMiddifference());
            productionScheduleVo.setFurnacedifference(apsScheduleConfig.getFurnacedifference());
        } else {
            throw new CustomException("排程参数缺失");
        }
        // 洗炉合金配置数据设置
        List<WashingMetal> washingMetalConfig = apsBlankOrderDao.getWashingMetalConfig();
        productionScheduleVo.setClosealloynames(washingMetalConfig);
        // 小卷退火合并
        List<ApsFurnaceInstallationDo> furnaceInstallationDos = apsFurnaceInstallationService.list();
        productionScheduleVo.setFurnaceInstallations(furnaceInstallationDos);
        // 小卷退火兼容
        List<ApsMergeFurnaceDo> mergeFurnaceDos = apsMergeFurnaceService.list();
        productionScheduleVo.setMergeFurnaces(mergeFurnaceDos);
        // 退火合并厚差配置数据
        List<ApsAnnealingDifferenceDo> apsAnnealingDifferenceDos = apsAnnealingDifferenceService.list();
        productionScheduleVo.setApsAnnealingDifferences(apsAnnealingDifferenceDos);
        return productionScheduleVo;
    }

    /**
     * 原始订单表数据转换APS平台模型数据
     *
     * @param apsBlankOrders
     * @return
     */
    @Override
    public ProductionScheduleVo apsProductionScheduleInit(List<ApsBlankOrderVo> apsBlankOrders) {
        // 待排程坯料计划ID集合
        List<String> blankids = apsBlankOrders.stream().map(v -> v.getId()).collect(Collectors.toList());
        ProductionScheduleVo productionScheduleVo = productionScheduleVoInit();
        // 排程计划工序任务集合
        List<ProductionProcesses> processesList = new ArrayList<>();
        // 坯料计划ID和所属工序作业ID对应关系
        Map<String, List<String>> blankProcessIds = new HashMap<>();
        // 待合并生产的订单工序
        List<ApsProcessOperationVo> processOperationMs = new ArrayList<>();
        if (apsBlankOrders != null && apsBlankOrders.size() > 0) {
            for (ApsBlankOrderVo apsBlankOrderVo : apsBlankOrders) {
                // 当前坯料计划作业集合
                List<ProductionProcesses> blankProcessesList = new ArrayList<>();
                // 父子ID对应关系处理
                List<String> processIdss = new ArrayList<>();
                // 坯料计划订单
                ProduceOrder produceOrder = new ProduceOrder(apsBlankOrderVo.getId(), apsBlankOrderVo.getMaterialname(), apsBlankOrderVo.getDeliverydate() == null ? null : DateUtil.offsetHour(apsBlankOrderVo.getDeliverydate(), apsBlankOrderVo.getDeliverytime() == null ? 0 : -apsBlankOrderVo.getDeliverytime()));
                produceOrder.setMaxheatroll(apsBlankOrderVo.getMaxheatroll());
                produceOrder.setOrderNo(apsBlankOrderVo.getBlanknumber());
                // 期望交货天数
                produceOrder.setExpecteddays(productionScheduleVo.getExpecteddays());
                if(apsBlankOrderVo.getExpecteddays() != null && apsBlankOrderVo.getExpecteddays()>0){
                    produceOrder.setExpecteddays(apsBlankOrderVo.getExpecteddays());
                }
                // 获取所有订单工序
                List<ApsProcessOperationDo> operationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                        .eq(ApsProcessOperationDo::getBlankid, apsBlankOrderVo.getId()));
                // 起始节点
                ApsProcessOperationDo rootOperationDo = null;
                // 作业维度缓存
                Map<String,List<ProductionProcesses>> operationProductionProcesses = new HashMap<>();
                Map<String,ApsProcessOperationDo> operationMaps = new HashMap<>();
                // 锁定的合并工序缓存
                Map<String, ProductionProcesses> lockHbPp = new HashMap<>();
                // 转换工序模型数据
                for (ApsProcessOperationDo operationDo : operationDos) {
                    processIdss.add(operationDo.getId());
                    ProductionProcesses processes = new ProductionProcesses();
                    // 工序所属订单
                    processes.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder}));
                    // 判断是否合并生产工序,加工方式是“合并加工”
                    String productprocess = operationDo.getProcessway();
                    // 根节点判断
                    if(StringUtils.isBlank(operationDo.getPreviousprocessid())){
                        rootOperationDo = operationDo;
                    }
                    operationMaps.put(operationDo.getId(),operationDo);
                    // 设备列表初始化
//                    List<String> optionalEquipments = equipmentListInit(operationDo,equipmentList,eqMaps,blankids,productionScheduleVo,apsScheduleConfig);
                    // 工序作业相关数据初始化
                    productionProcessesInit(operationDo,produceOrder,processesList,operationProductionProcesses,apsBlankOrderVo,productionScheduleVo);
                }
                // 前后关联关系初始化
                processesRelationInit(rootOperationDo,operationProductionProcesses,operationMaps,apsBlankOrderVo);

                blankProcessIds.put(apsBlankOrderVo.getId(), processIdss);
            }
        }
        // 合并生产工序
        productionScheduleVo.setProcesses(processesList);
//        productionScheduleVo.setEquipmentList(equipmentList);
        productionScheduleVo.setBlankProcessIds(blankProcessIds);
        return productionScheduleVo;
    }

    private void thMergePs(List<ApsProcessOperationDo> operationDos){

    }

    private List<String> equipmentListInit(ApsProcessOperationDo operationDo,List<Equipment> equipmentList,Map<String, AspCheckItemsDo> eqMaps
            ,List<String> blankids,Set<String> opId,ProductionScheduleVo productionScheduleVo,ApsScheduleConfigDo apsScheduleConfig){
        // 当前工序排程开始时间
        Date apsPlanStartDate = productionScheduleVo.getApsPlanStartDate();
        if(productionScheduleVo.getProcesses() != null && productionScheduleVo.getProcesses().size()>0){
            List<ProductionProcesses> bsProcess = productionScheduleVo.getProcesses().stream().filter(v -> v.getBsProcessesId().get(0).equals(operationDo.getId())).collect(Collectors.toList());
            if(bsProcess != null && bsProcess.size()>0){
                if(bsProcess.get(0).getApsOverallConfig() != null && bsProcess.get(0).getApsOverallConfig().getStartTime() != null){
                    apsPlanStartDate = Date.from(bsProcess.get(0).getApsOverallConfig().getStartTime().atZone(ZoneId.systemDefault()).toInstant());
                }
            }
        }
        // 设备列表
        List<String> optionalEquipments = new ArrayList<>();
        if (StringUtils.isNotBlank(operationDo.getCanchoosedeviceid())) {
            String[] sbIds = operationDo.getCanchoosedeviceid().split(",");
            for (String equIds : sbIds) {
                if(equIds.equals("0001be252874536843730b100052")){
                    System.out.println(equIds);
                }
                AspCheckItemsDo checkItemsD = eqMaps.get(equIds);
                if (checkItemsD != null) {
                    optionalEquipments.add(equIds);
                    List<Equipment> eqpts = equipmentList.stream().filter(v -> v.getId().equals(equIds)).collect(Collectors.toList());
                    // 设备集合里不存在时新增
                    if (eqpts == null || eqpts.size() == 0) {
                        Equipment equipment = new Equipment();
                        equipment.setBsEquipmentId(equIds);
                        equipment.setId(equIds);
                        equipment.setEquipmentName(checkItemsD.getCheckitemname());
                        equipment.setWorkshopid(checkItemsD.getUsedeptid());
                        equipment.setWorkshopname(checkItemsD.getUsedeptname());
                        equipment.setFactoryid(checkItemsD.getTenantid());
                        equipment.setFactory(checkItemsD.getOwnedfactory());
                        equipment.setEquassociated(checkItemsD.getEquassociated());
                        // 设备参数
                        EquipmentParameter ep = new EquipmentParameter();
                        ep.setEquipmentWidth(checkItemsD.getEquipmentlength());
                        ep.setEquipmentBearing(checkItemsD.getEquipmentbearing());
                        ep.setFurnace(apsScheduleConfig.getFurnace());
                        ep.setMaxfurance(checkItemsD.getMaxfurance());
                        equipment.setEquipmentParameter(ep);
                        // 查询设备锁定的已排程的时间段
                        List<ApsProcessOperationProcessEquDo> processEqus = null;
                        if(blankids != null && blankids.size()>0){
                            processEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getBlankid, blankids)
                                    .ge(ApsProcessOperationProcessEquDo::getPlanenddate, apsPlanStartDate)
                                    .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                            );
                        }else if(opId != null && opId.size()>0){
                            processEqus = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getProcessid, opId)
                                    .ge(ApsProcessOperationProcessEquDo::getPlanenddate, apsPlanStartDate)
                                    .orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate)
                            );
                        }

                        // 查询当前设备最后一个生产任务、连续生产需要考虑使用
                        List<ApsProcessOperationProcessEquDo> lastpros = null;
                        if(blankids != null && blankids.size()>0){
                            lastpros = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getBlankid, blankids)
                                    .lt(ApsProcessOperationProcessEquDo::getPlanstartdate, apsPlanStartDate)
                                    .orderByDesc(ApsProcessOperationProcessEquDo::getPlanstartdate).last(" limit 100")
                            );
                        }else if(opId != null && opId.size()>0){
                            lastpros = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                                    .eq(ApsProcessOperationProcessEquDo::getProcessdeviceid, equIds)
                                    .eq(ApsProcessOperationProcessEquDo::getLockmark, "y")
//                                    .notIn(ApsProcessOperationProcessEquDo::getProcessid, opId)
                                    .lt(ApsProcessOperationProcessEquDo::getPlanstartdate, apsPlanStartDate)
                                    .orderByDesc(ApsProcessOperationProcessEquDo::getPlanstartdate).last(" limit 100")
                            );
                        }

                        BigDecimal hasLbs = null;
                        if (lastpros != null && lastpros.size() > 0) {
                            boolean hasLast = true;
                            ApsProcessOperationProcessEquDo lastpro = lastpros.get(0);
                            if(processEqus != null && processEqus.size()>0){
                                List<ApsProcessOperationProcessEquDo> hasLasts = processEqus.stream().filter(v -> v.getId().equals(lastpro.getId())).collect(Collectors.toList());
                                if(hasLasts != null && hasLasts.size() > 0){
                                    hasLast = false;
                                }
                            }
                            // 获取加工设备当前开始时间第一道工序的立板周期
                            Set<String> prosids = new HashSet<>();
                            lastpros.forEach(v->{
                                prosids.add(v.getProcessid());
                            });
                            // 查询所有作业详情信息
                            List<ApsProcessOperationDo> lastops = (List<ApsProcessOperationDo>)apsProcessOperationService.listByIds(prosids);
                            Map<String,ApsProcessOperationDo> lastopsMap = new HashMap<>();
                            for (ApsProcessOperationDo lastop : lastops) {
                                lastopsMap.put(lastop.getId(),lastop);
                            }

                            // 遍历找到最近一个立板周期
                            String lbtj = null;
                            for (int i = 0; i < lastpros.size(); i++) {
                                ApsProcessOperationDo apo = lastopsMap.get(lastpros.get(i).getProcessid());
                                if(apo == null){
//                                    int aaa = 1;
                                    continue;
                                }
                                String thislbtj = apo.getMetal() + "^_^" + apo.getProducttype() + "^_^" + apo.getProwidth();
                                if(hasLbs == null){
                                    hasLbs = apo.getSinglerollweight();
                                    lbtj = thislbtj;
                                }else{
                                    if(lbtj.equals(thislbtj)){
                                        hasLbs = hasLbs.add(apo.getSinglerollweight());
                                    }else{
                                        break;
                                    }
                                }
                            }

                            if(hasLast){
                                ApsProcessOperationDo lastop = apsProcessOperationService.getById(lastpro.getProcessid());
                                // 输出物料
                                List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                                        .eq(ApsProcessOperationOutMaterDo::getMainid, lastpro.getProcessid()));
                                equipment.setLastProcessType(lastop.getProcess());
                                equipment.setLastProcessEndTime(lastpro.getPlanenddate());
                                equipment.setOnceprocessmin(lastop.getOnceprocessmin().intValue());
                                equipment.setLastProcessCutfinishmin(lastop.getCutfinishmin() == null ? null : lastop.getCutfinishmin().intValue());
                                equipment.setLastSinglerollweight(lastop.getSinglerollweight());
                                equipment.setLastSerialLbWeight(hasLbs);
                                // 合金+输入物料+宽度+厚度+输出物料厚度
                                equipment.setLastSeriesProduceMark(lastop.getMetal() + "^_^" + lastop.getProducttype() + "^_^" + lastop.getProwidth() + "^_^" + lastop.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
                                equipment.setLastProcessCutfinishmin(lastop.getCutfinishmin() == null ? null : lastop.getCutfinishmin().intValue());

                            }
                        }
                        // 设备占用时间段
                        List<EquipmentRunTime> equipmentRunTimes = new ArrayList<>();
                        // 查询相关工序作业
                        Set<String> processIds = new HashSet<>();
                        if (processEqus != null && processEqus.size() > 0) {
                            for (ApsProcessOperationProcessEquDo equs : processEqus) {
                                processIds.add(equs.getProcessid());
                            }
                            List<ApsProcessOperationDo> processOperationDos = null;
                            if (processIds.size() > 0) {
                                processOperationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                                        .in(ApsProcessOperationDo::getId, processIds));
                            }
                            //
                            List<ApsProcessOperationOutMaterDo> outMaterDosAll = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                                    .in(ApsProcessOperationOutMaterDo::getMainid, processIds));

                            for (ApsProcessOperationProcessEquDo equs : processEqus) {
                                EquipmentRunTime er = new EquipmentRunTime();
                                er.setStartRunTime(equs.getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setEndRunTime(equs.getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setOccupyType("process");
                                // 设备占用时间设置连续生产标识，参与排程
                                if (processOperationDos != null) {
                                    List<ApsProcessOperationDo> pos = processOperationDos.stream().filter(v -> v.getId().equals(equs.getProcessid())).collect(Collectors.toList());
                                    if (pos != null && pos.size() > 0) {
                                        ApsProcessOperationDo processesDo = pos.get(0);
                                        // 输出物料
//                                        List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
//                                                .eq(ApsProcessOperationOutMaterDo::getMainid, processesDo.getId()));
                                        List<ApsProcessOperationOutMaterDo> outMaterDos = outMaterDosAll.stream().filter(v->v.getMainid().equals(processesDo.getId())).collect(Collectors.toList());
                                        er.setProcessType(processesDo.getProcess());
                                        // 合金+输入物料+宽度+厚度
                                        er.setSeriesProduceMark(processesDo.getMetal() + "^_^" + processesDo.getProducttype() + "^_^" + processesDo.getProwidth() + "^_^" + processesDo.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
                                        er.setVolumeMetal(processesDo.getMetal());
                                        er.setVolumeMetalstate(processesDo.getMetalstate());
                                        er.setPrepressworkmin(processesDo.getPrepressworkmin() == null ? null : processesDo.getPrepressworkmin().intValue());
                                        er.setCutfinishmin(processesDo.getCutfinishmin() == null ? null : processesDo.getCutfinishmin().intValue());
                                        // 单卷宽度、重量数据赋值
                                        er.setTotalVolumeWidth(processesDo.getProwidth());
                                        if(processesDo.getProcess().equals("小卷成退")){
                                            er.setTotalSinglerollweight(processesDo.getSinglerollweight().multiply(new BigDecimal(equs.getPlanprocessrall())));
                                        }else{
                                            er.setTotalSinglerollweight(processesDo.getSinglerollweight());
                                        }
                                        er.setProducttype(processesDo.getProducttype());
                                        er.setTotalThickness(processesDo.getThickness());
                                        er.setOnceprocessmin(processesDo.getOnceprocessmin().intValue());
                                        if(lastpros != null && lastpros.size()>0 && equs.getId().equals(lastpros.get(0).getId())){
                                            er.setLastSerialLbWeight(hasLbs);
                                        }
                                    }
                                }
                                equipmentRunTimes.add(er);
                            }
                        }
                        // 设备日历不可用时间段
                        List<ApsEquipmentCalendarDo> equipmentCalendarDos = apsEquipmentCalendarService.list(
                                new LambdaQueryWrapper<ApsEquipmentCalendarDo>().ge(ApsEquipmentCalendarDo::getSdendtime, apsPlanStartDate)
                                        .eq(ApsEquipmentCalendarDo::getProcessdeviceid, equipment.getBsEquipmentId()));
                        if (equipmentCalendarDos != null && equipmentCalendarDos.size() > 0) {
                            for (ApsEquipmentCalendarDo equipmentCalendarDo : equipmentCalendarDos) {
                                EquipmentRunTime er = new EquipmentRunTime();
                                er.setStartRunTime(equipmentCalendarDo.getSdstarttime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setEndRunTime(equipmentCalendarDo.getSdendtime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                                er.setOccupyType("maintenance");
                                equipmentRunTimes.add(er);
                            }
                        }
                        if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
                            equipment.setEquipmentRunTimes(equipmentRunTimes);
                        }

                        equipmentList.add(equipment);
                    }
                }
            }
        }

        return optionalEquipments;
    }


    /**
     * 前后道工序作业关联关系初始化
     * @param rootOperationDo
     * @param operationProductionProcesses
     * @param operationMaps
     * @param apsBlankOrderVo
     */
    private void processesRelationInit(ApsProcessOperationDo rootOperationDo,Map<String,List<ProductionProcesses>> operationProductionProcesses
            ,Map<String,ApsProcessOperationDo> operationMaps,ApsBlankOrderVo apsBlankOrderVo){
        if(rootOperationDo.getId().equals("b4cf9ca488bb49268a9782ed1396c4f9")){
            System.out.println(rootOperationDo);
        }
        if(StringUtils.isNotBlank(rootOperationDo.getNextprocessid())){
            String[] nextids = rootOperationDo.getNextprocessid().split(",");
            // 前后道工序关联关系处理
            if(rootOperationDo == null){
                throw new CustomException("数据异常，ID为:"+apsBlankOrderVo.getId()+"的坯料计划作业模型初始化，作业为空");
            }else{
                boolean isEnd = true;
                // 当前作业计划加工卷数
                Integer planPres = rootOperationDo.getPlanprocessrall();
                // 下道工序按物料类型分组
                Map<String, List<ProductionProcesses>> wlPros = new HashMap<>();
                if(nextids != null && nextids.length>0){
                    for (String nextid : nextids) {
                        List<ProductionProcesses> productionProcesses = operationProductionProcesses.get(nextid);
                        if(productionProcesses != null && productionProcesses.size()>0 && operationMaps.get(nextid) != null){
                            if(wlPros.containsKey(operationMaps.get(nextid).getPlaninput())){
                                wlPros.get(operationMaps.get(nextid).getPlaninput()).addAll(productionProcesses);
                            }else{
                                wlPros.put(operationMaps.get(nextid).getPlaninput(),productionProcesses);
                            }
                        }
                    }
                }
                // 当前作业和下道工序建立关联关系
                if(wlPros.size()>0){
                    wlPros.forEach((k,v)->{
                        boolean isConnect = true;
                        int vi = 0;
                        List<ProductionProcesses> productionProcesses = operationProductionProcesses.get(rootOperationDo.getId());
                        while (vi<v.size()){
                            for(int i = 0;i <planPres;i++){
                                if(vi>=v.size()){
                                    break;
                                }
                                if(productionProcesses.get(i).getNextProcessesIds() == null){
                                    List<String> ids = new ArrayList<>();
                                    ids.add(v.get(vi).getId());
                                    productionProcesses.get(i).setNextProcessesIds(ids);
                                }else{
                                    productionProcesses.get(i).getNextProcessesIds().add(v.get(vi).getId());
                                }
                                if(v.get(vi).getPreviousProcessesIds() == null){
                                    List<String> ids = new ArrayList<>();
                                    ids.add(productionProcesses.get(i).getId());
                                    v.get(vi).setPreviousProcessesIds(ids);
                                }else{
                                    v.get(vi).getPreviousProcessesIds().add(productionProcesses.get(i).getId());
                                }
                                vi++;
                            }
                        }
                    });
                }
            }
            // 递归处理下道工序数据
            if(nextids != null && nextids.length>0){
                for (String nextid : nextids) {
                    ApsProcessOperationDo apsProcessOperationDo = operationMaps.get(nextid);
                    processesRelationInit(apsProcessOperationDo,operationProductionProcesses,operationMaps,apsBlankOrderVo);
                }
            }
        }
    }

    /**
     * 工序作业模型初始化
     * @param operationDo
     * @param produceOrder
     * @param processesList
     * @param operationProductionProcesses
     */
    private void productionProcessesInit(ApsProcessOperationDo operationDo,ProduceOrder produceOrder
            ,List<ProductionProcesses> processesList,Map<String,List<ProductionProcesses>> operationProductionProcesses,ApsBlankOrderVo apsBlankOrderVo,ProductionScheduleVo productionScheduleVo){
        // 输出物料
        List<ApsProcessOperationOutMaterDo> outMaterDos = apsProcessOperationOutMaterService.list(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                .eq(ApsProcessOperationOutMaterDo::getMainid, operationDo.getId()));
        List<ProductionProcesses> operationProcess = new ArrayList<>();
        if(operationDo != null && operationDo.getPlanprocessrall() != null && operationDo.getPlanprocessrall()>0){
            List<String> optionalEquipments = new ArrayList<>();
            String[] sbIds = operationDo.getCanchoosedeviceid().split(",");
            for (String equIds : sbIds) {
                optionalEquipments.add(equIds);
            }
            // 锁定的作业
            if(LOCKMARK_Y.equals(operationDo.getLockmark())){
                List<ApsProcessOperationProcessEquDo> processDetails = processOperationProcessEquService.list(new LambdaQueryWrapper<ApsProcessOperationProcessEquDo>()
                        .eq(ApsProcessOperationProcessEquDo::getProcessid, operationDo.getId()).orderByAsc(ApsProcessOperationProcessEquDo::getPlanstartdate));
                for (ApsProcessOperationProcessEquDo processDetail : processDetails) {
                    ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo);
                    processes.setIfLock(true);
                    processes.setEquipmentId(processDetail.getProcessdeviceid());
                    List<String> opeqs = new ArrayList<>();
                    opeqs.add(processDetail.getProcessdeviceid());
                    processes.setOptionalEquipments(opeqs);
                    processes.setDelay(0);
                    processes.setStartTime(processDetail.getPlanstartdate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                    processes.setEndTime(processDetail.getPlanenddate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
                    if("小卷成退".equals(operationDo.getProcess()) || "小卷包装".equals(operationDo.getProcess())){
                        String previousprocessid = operationDo.getPreviousprocessid();
                        ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                        processes.setMinThPcNum(processDetail.getPlanprocessrall());
                        processes.setProducePcNum(preprocess.getPlanprocessrall());
                    }
                    if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                        // 全局配置
                        ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                        Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                        LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                        apsOverallConfig.setStartTimeLong(startDate.getTime());
                        apsOverallConfig.setStartTime(startTime);
                        // 排程全局配置
                        apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                        apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                        apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                        apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                        apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                        apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                        apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                        apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                        processes.setApsOverallConfig(apsOverallConfig);
                    }
                    operationProcess.add(processes);
                }
            }else{
                if("小卷成退".equals(operationDo.getProcess())){
                    String previousprocessid = operationDo.getPreviousprocessid();
                    ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                    if(preprocess == null){
                        throw new CustomException("小卷成退没有前道工序："+operationDo.getId());
                    }
                    Integer planprocessrall = preprocess.getPlanprocessrall();
                    Integer ys = operationDo.getPlanprocessrall() % planprocessrall;
                    Integer js = operationDo.getPlanprocessrall() / planprocessrall;
                    for (Integer i = 0; i < planprocessrall; i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo);
                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        Integer alls = js;
                        if(i<ys){
                            alls = alls + 1;
                        }
                        processes.setProducePcNum(planprocessrall);
                        processes.setMinThPcNum(alls);
                        processes.setSinglerollweight(operationDo.getSinglerollweight().multiply(new BigDecimal(alls)));

                        operationProcess.add(processes);
                    }

                } else if ("小卷包装".equals(operationDo.getProcess())) {
                    String previousprocessid = operationDo.getPreviousprocessid();
                    ApsProcessOperationDo preprocess = apsProcessOperationService.getById(previousprocessid);
                    if(preprocess == null){
                        throw new CustomException("小卷成退没有前道工序："+operationDo.getId());
                    }
                    if("小卷成退".equals(preprocess.getProcess())){
                        preprocess = apsProcessOperationService.getById(preprocess.getPreviousprocessid());
                    }
                    Integer planprocessrall = preprocess.getPlanprocessrall();
                    Integer ys = operationDo.getPlanprocessrall() % planprocessrall;
                    Integer js = operationDo.getPlanprocessrall() / planprocessrall;
                    for (Integer i = 0; i < planprocessrall; i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo);
                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        Integer alls = js;
                        if(i<ys){
                            alls = alls + 1;
                        }
                        processes.setProducePcNum(planprocessrall);
                        processes.setMinThPcNum(alls);
                        processes.setProduceTime(operationDo.getOnceprocessmin().intValue() * alls);

                        operationProcess.add(processes);
                    }
                }else{
                    for (Integer i = 0; i < operationDo.getPlanprocessrall(); i++) {
                        ProductionProcesses processes = productionProcessesDetailInit(operationDo, produceOrder, optionalEquipments,outMaterDos,apsBlankOrderVo);
                        if(apsBlankOrderVo.getPlanhavematerialdate() != null){
                            // 全局配置
                            ApsOverallConfig apsOverallConfig = new ApsOverallConfig();
                            Date startDate = apsBlankOrderVo.getPlanhavematerialdate();
                            LocalDateTime startTime = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                            apsOverallConfig.setStartTimeLong(startDate.getTime());
                            apsOverallConfig.setStartTime(startTime);
                            // 排程全局配置
                            apsOverallConfig.setRoamTime(productionScheduleVo.getRoamTime());
                            apsOverallConfig.setWashingtime(productionScheduleVo.getWashingtime());
                            apsOverallConfig.setStandingtime(productionScheduleVo.getStandingtime());
                            apsOverallConfig.setClosealloynames(productionScheduleVo.getClosealloynames());
                            apsOverallConfig.setFurnaceInstallations(productionScheduleVo.getFurnaceInstallations());
                            apsOverallConfig.setMergeFurnaces(productionScheduleVo.getMergeFurnaces());
                            apsOverallConfig.setLooseness(productionScheduleVo.getLooseness());
                            apsOverallConfig.setStandingyield(productionScheduleVo.getStandingyield());
                            processes.setApsOverallConfig(apsOverallConfig);
                        }
                        operationProcess.add(processes);
                    }
                }
            }
            processesList.addAll(operationProcess);
            operationProductionProcesses.put(operationDo.getId(),operationProcess);
        }
    }

    private ProductionProcesses productionProcessesDetailInit(ApsProcessOperationDo operationDo,ProduceOrder produceOrder
            ,List<String> optionalEquipments,List<ApsProcessOperationOutMaterDo> outMaterDos,ApsBlankOrderVo apsBlankOrderVo){
        String warnPreMsg = "坯料计划号："+apsBlankOrderVo.getBlanknumber()+"  作业类型："+operationDo.getProcess()+"  作业名称："+operationDo.getProcessname();
        ProductionProcesses processes = new ProductionProcesses();
        // 工序所属订单
        processes.setProduceOrder(Arrays.asList(new ProduceOrder[]{produceOrder}));
        // 模型ID
        processes.setId(SecurityUtil.getUUID());
        // 业务表主键ID
        List<String> bss = new ArrayList<>();
        bss.add(operationDo.getId());
        processes.setBsProcessesId(bss);
        processes.setProcessName(operationDo.getProcessname());
        // 工序任务可选设备
        processes.setOptionalEquipments(optionalEquipments);
        // 批次
        processes.setProducePcNum(operationDo.getPlanprocessrall());
        processes.setOpeProducePcNum(1);
        processes.setProcessType(operationDo.getProcess());
        // 单次加工时长
        if(operationDo.getOnceprocessmin() == null){
            throw new CustomException(warnPreMsg + "的作业单卷加工时间为空");
        }
        // 是否分卷作业
        processes.setIssubsection(operationDo.getIssubsection());
        processes.setUnitProduceTime(operationDo.getOnceprocessmin().intValue());
        processes.setProduceTime(operationDo.getOnceprocessmin().intValue());
        // 单卷宽度和重量
        if(operationDo.getProwidth() == null){
            throw new CustomException(warnPreMsg + "的作业单卷宽度为空");
        }
        if(operationDo.getSinglerollweight() == null){
            throw new CustomException(warnPreMsg + "的作业单卷重量为空");
        }
        if(operationDo.getThickness() == null){
            throw new CustomException(warnPreMsg + "的作业单卷厚度为空");
        }
        processes.setVolumeWidth(operationDo.getProwidth());
        processes.setSinglerollweight(operationDo.getSinglerollweight());
        processes.setVolumeThickness(operationDo.getThickness());
        if (operationDo.getMinflowwaitmin() != null) {
            processes.setMinWaitTime(operationDo.getMinflowwaitmin().intValue());
        }
        if (operationDo.getMaxflowwaitmin() != null) {
            processes.setMaxWaitTime(operationDo.getMaxflowwaitmin().intValue());
        }
        // 合金
        if(operationDo.getMetal() == null){
            throw new CustomException(warnPreMsg + "的作业合金为空");
        }
        processes.setVolumeMetal(operationDo.getMetal());
        if("成退".equals(operationDo.getProcess()) || "中退".equals(operationDo.getProcess()) || "小卷成退".equals(operationDo.getProcess())){
            processes.setVolumeMetalstate(outMaterDos.get(0).getMetalstate());
        }else{
            processes.setVolumeMetalstate(operationDo.getMetalstate());
        }
        processes.setProducttype(operationDo.getProducttype());
        // 连续生产标识设置
        // 合金+输入物料+宽度+输入物料厚度+输出物料厚度（取第一个冷轧工序使用）
        processes.setSeriesProduceMark(operationDo.getMetal() + "^_^" + operationDo.getProducttype() + "^_^" + operationDo.getProwidth() + "^_^" + operationDo.getThickness() + "^_^" + outMaterDos.get(0).getThickness());
        processes.setPrepressworkmin(operationDo.getPrepressworkmin() == null ? null : operationDo.getPrepressworkmin().intValue());
        processes.setCutfinishmin(operationDo.getCutfinishmin() == null ? null : operationDo.getCutfinishmin().intValue());
        return processes;
    }

}
