package com.xisc.pm.app.service.strategy.formplatemode;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import org.springframework.stereotype.Component;

import com.xisc.pm.api.dto.PmCompositeBlockDTO;
import com.xisc.pm.api.dto.PmCompositeBoardDTO;
import com.xisc.pm.api.dto.PmCompositeSlabCalcDTO;
import com.xisc.pm.api.dto.PmCutPlaceDTO;
import com.xisc.pm.api.dto.PmProContFilterResposeDTO;
import com.xisc.pm.api.dto.PmProContYieldDTO;
import com.xisc.pm.api.dto.PmProContYieldRequestDTO;
import com.xisc.pm.api.dto.PmSmallPlateDTO;
import com.xisc.pm.app.service.strategy.FormPlateModeStrategyFactory;
import com.xisc.pm.domain.entity.PmProContProdTtr;
import com.xisc.pm.domain.entity.PmSmallPltPos;
import com.xisc.pm.infra.enums.FormPlateMode;
import com.xisc.pm.infra.util.BeanUtils;
import com.xisc.pm.infra.util.Utils;

/**
 * 
 * 组板方式G处理策略
 * @author jun.zeng
 *
 */
@Component
public class FormPlateModeGStrategy extends DefaultFormPlateModeStrategy {
    
    @Override
    public PmCompositeBoardDTO buildPmCompositeBoard(FormPlateMode formPlateMode ,List<PmSmallPltPos> pmSmallPltPoss,
            PmProContProdTtr axisPmProContProdTtr, String mscLineNo, Long tenantId) {
        PmCompositeBoardDTO pmCompositeBoardDTO = new PmCompositeBoardDTO();
        Map<Long, List<PmSmallPltPos>> blockMap = pmSmallPltPoss.stream()
                .collect(Collectors.groupingBy(PmSmallPltPos::getPickModeLenDir));
        Set<Long> keys = blockMap.keySet();
        TreeSet<Long> sortedSet = new TreeSet<>(keys);
        
        List<PmCompositeBlockDTO> pmCompositeBlockDTOs = new ArrayList<>();
        pmCompositeBoardDTO.setPmCompositeBlockDTOs(pmCompositeBlockDTOs);
        
        // 初始化值
        pmCompositeBoardDTO.setSzWidth(BigDecimal.ZERO);
        pmCompositeBoardDTO.setSzLength(BigDecimal.ZERO);
        pmCompositeBoardDTO.setOrderCount(0);
        pmCompositeBoardDTO.setBlkCount(keys.size());
        pmCompositeBoardDTO.setPickModeWidDir(0);
        pmCompositeBoardDTO.setSpCount(pmSmallPltPoss.size());
        pmCompositeBoardDTO.setPickModeLenDir(keys.size());
        
        PmCutPlaceDTO pmCutPlace = null ;
        
        for (Long key : sortedSet) {
            List<PmSmallPltPos> pmSmallPltPosList = blockMap.get(key);
            pmSmallPltPosList.sort(new Comparator<PmSmallPltPos>() {
                @Override
                public int compare(PmSmallPltPos pos1, PmSmallPltPos pos2) {
                    return pos1.getPickModeWidDir().compareTo(pos2.getPickModeWidDir());
                }
            });
            
            PmCompositeBlockDTO pmCompositeBloc = new PmCompositeBlockDTO();
            pmCompositeBloc.setBlkSpNum(pmSmallPltPosList.size());
            pmCompositeBloc.setBlockNo(key.intValue());
            pmCompositeBloc.setBlockLength(BigDecimal.ZERO);
            pmCompositeBloc.setBlockWidth(BigDecimal.ZERO);
            List<PmSmallPlateDTO> smallPlateDTOList = new ArrayList<>();
            pmCompositeBloc.setSmallPlateDTOList(smallPlateDTOList);
            
            Map<String , Long> orderNoMap = new HashMap<String , Long>();
            
            BigDecimal blockLen = BigDecimal.ZERO;
            BigDecimal blockWidth = BigDecimal.ZERO;
            
            BigDecimal tempBlockLen = BigDecimal.ZERO;
            BigDecimal tempBlockWidth = BigDecimal.ZERO;
            
            for (PmSmallPltPos pmSmallPltPos : pmSmallPltPosList) {
                if(!orderNoMap.containsKey(pmSmallPltPos.getOrderNo())) {
                    orderNoMap.put(pmSmallPltPos.getOrderNo(), 0L);
                }
                orderNoMap.put(pmSmallPltPos.getOrderNo(), orderNoMap.get(pmSmallPltPos.getOrderNo()) + 1L);
                
                if(FormPlateMode.G1.equals(formPlateMode)) {
                    if(pmCutPlace == null) {
                        pmCutPlace = pmCutPlaceBtRepository.queryCutPlace(formPlateMode, Utils.mscLineNoToRoolLineNo(mscLineNo), axisPmProContProdTtr, tenantId);
                    }
                    if(tempBlockLen.add(pmSmallPltPos.getSmallPlateLen()).compareTo(pmCutPlace.getCutMax()) <= 0 
                            && (tempBlockWidth.compareTo(BigDecimal.ZERO) == 0 || tempBlockWidth.compareTo(pmSmallPltPos.getSmallPlateWidth()) == 0)) {
                        // 尝试比较相加后的值是不是小于等于最大粗切长度，如果是的话，可以放在同一层，直接长度相加
                        tempBlockLen = tempBlockLen.add(pmSmallPltPos.getSmallPlateLen());
                        tempBlockWidth = Utils.maxValue(tempBlockWidth , pmSmallPltPos.getSmallPlateWidth());
                    } else {
                        // 如果该层放不下，新开一层，并记录最大长度。
                        blockLen = Utils.maxValue(blockLen , tempBlockLen);
                        blockWidth = blockWidth.add(tempBlockWidth);
                        tempBlockLen = pmSmallPltPos.getSmallPlateLen();
                        tempBlockWidth = pmSmallPltPos.getSmallPlateWidth();
                        pmCompositeBoardDTO.setPickModeWidDir(pmCompositeBoardDTO.getPickModeWidDir() + 1);
                    }
                } else {
                    pmCompositeBoardDTO.setPickModeWidDir(pmSmallPltPosList.size());
                    blockWidth = blockWidth.add(pmSmallPltPos.getSmallPlateWidth());
                    if(blockLen.compareTo(pmSmallPltPos.getSmallPlateLen()) <= 0) {
                        blockLen = pmSmallPltPos.getSmallPlateLen();
                    }
                }
                
                PmSmallPlateDTO smallPlate = BeanUtils.copy(pmSmallPltPos, PmSmallPlateDTO.class);
                smallPlateDTOList.add(smallPlate);
                smallPlate.setBlockNo(key);
                smallPlate.setPickModeLenDirPos(pmSmallPltPos.getPickModeLenDir().intValue());
                smallPlate.setPickModeWidDirPos(pmSmallPltPos.getPickModeWidDir().intValue());
            }
            for (PmSmallPlateDTO smallPlate : smallPlateDTOList) {
                smallPlate.setOrderBlockNum(orderNoMap.get(smallPlate.getOrderNo()));
            }
            if(blockLen.compareTo(tempBlockLen) <= 0) {
                // 最后一块如果长度比较
                blockLen = tempBlockLen;
            }
            if(FormPlateMode.G1.equals(formPlateMode)) {
                blockWidth = blockWidth.add(tempBlockWidth);
                pmCompositeBoardDTO.setPickModeWidDir(pmCompositeBoardDTO.getPickModeWidDir() + 1);
            }
            
            pmCompositeBloc.setBlockLength(blockLen);
            pmCompositeBloc.setBlockWidth(blockWidth);
            pmCompositeBloc.setBlkOrderNum(orderNoMap.size());
            pmCompositeBlockDTOs.add(pmCompositeBloc);
            
            pmCompositeBoardDTO.setSzWidth(Utils.maxValue(pmCompositeBoardDTO.getSzWidth() , blockWidth));
            pmCompositeBoardDTO.setSzLength(pmCompositeBoardDTO.getSzLength().add(blockLen));
            pmCompositeBoardDTO.setOrderCount(pmCompositeBoardDTO.getOrderCount() + pmCompositeBloc.getBlkOrderNum());
        }
        
        return pmCompositeBoardDTO;
    }
    
    @Override
    public List<BigDecimal> motherableEndPosList(FormPlateMode formPlateMode ,String matNo, Long tenantId , String rollLineNo , PmProContProdTtr axisPmProContProdTtr) {
        List<PmSmallPltPos> pmSmallPltPoss = pmSmallPltPosRepository.selectByPdMatNo(tenantId, matNo);
        Map<Long, List<PmSmallPltPos>> blockMap = pmSmallPltPoss.stream()
                .collect(Collectors.groupingBy(PmSmallPltPos::getPickModeLenDir));
        
        List<BigDecimal> motherableEndPosList = new ArrayList<BigDecimal>(blockMap.keySet().size());
        
        PmCutPlaceDTO pmCutPlace = pmCutPlaceBtRepository.queryCutPlace(formPlateMode, rollLineNo, axisPmProContProdTtr, tenantId);
        
        BigDecimal pos = BigDecimal.ZERO;
        Set<Long> keys = blockMap.keySet();
        TreeSet<Long> sortedSet = new TreeSet<>(keys);
        
        for (Long key : sortedSet) {
            List<PmSmallPltPos> basePosList = blockMap.get(key);
            BigDecimal blockLen = BigDecimal.ZERO;
            BigDecimal tempBlockLen = BigDecimal.ZERO;
            BigDecimal tempBlockWidth = BigDecimal.ZERO;
            if(FormPlateMode.G1.equals(formPlateMode)) {
                // G1 组板需要按宽度坐标排序从小到大
                basePosList.sort(new Comparator<PmSmallPltPos>() {
                    @Override
                    public int compare(PmSmallPltPos pos1, PmSmallPltPos pos2) {
                        return pos1.getPickModeWidDir().compareTo(pos2.getPickModeWidDir());
                    }
                });
            
                for (PmSmallPltPos pmSmallPltPos : basePosList) {
                    if(tempBlockLen.add(pmSmallPltPos.getSmallPlateLen()).compareTo(pmCutPlace.getCutMax()) <= 0 &&
                            (tempBlockWidth.compareTo(BigDecimal.ZERO) == 0  || tempBlockWidth.compareTo(pmSmallPltPos.getSmallPlateWidth()) == 0)) {
                        // 尝试比较相加后的值是不是小于等于最大粗切长度，如果是的话，可以放在同一层，直接长度相加
                        tempBlockLen = tempBlockLen.add(pmSmallPltPos.getSmallPlateLen());
                        tempBlockWidth = pmSmallPltPos.getSmallPlateWidth();
                    } else {
                        // 如果该层放不下，新开一层，并记录最大长度。
                        if(blockLen.compareTo(tempBlockLen) <= 0) {
                            blockLen = tempBlockLen;
                        }
                        tempBlockWidth = pmSmallPltPos.getSmallPlateWidth();
                        tempBlockLen = pmSmallPltPos.getSmallPlateLen();
                    }
                }
                if(blockLen.compareTo(tempBlockLen) <= 0) {
                    // 最后一块如果长度比较
                    blockLen = tempBlockLen;
                }
            } else {
                for (PmSmallPltPos pmSmallPltPos : basePosList) {
                    if(blockLen.compareTo(pmSmallPltPos.getSmallPlateLen()) <= 0) {
                        blockLen = pmSmallPltPos.getSmallPlateLen();
                    }
                }
            }
            // 记录母板终点位置
            pos = pos.add(blockLen);
            motherableEndPosList.add(pos);
        }

        return motherableEndPosList;
    }
    
    @Override
    public int maxBlockNum() {
        return 20;
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        FormPlateModeStrategyFactory.register(FormPlateMode.G, this);
        FormPlateModeStrategyFactory.register(FormPlateMode.G1, this);
    }
    
    @Override
    public PmCompositeSlabCalcDTO checkAndInitParams(Map<String, PmProContFilterResposeDTO> filterOrderMap, PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr) {
        PmCompositeBoardDTO compositeBoard = pmProContYield.getCompositeBoard();
        
        PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO = super.checkAndInitParams(filterOrderMap, pmProContYield , axisPmProContProdTtr);
        
        // 取板方式_长度方向以组合子板为单位，即BLOCK数量
        pmCompositeSlabCalcDTO.setPickModeLenDir(compositeBoard.getBlkCount());
        // motherable_num=block数，即组合子板个数
        pmCompositeSlabCalcDTO.setMotherableNum(compositeBoard.getBlkCount());
        
        Map<String, PmProContYieldDTO> pmProContYieldMap = getPmProContYieldDTOMap(filterOrderMap ,pmProContYield);
        compositeBoard.getPmCompositeBlockDTOs().sort(new Comparator<PmCompositeBlockDTO>() {
            @Override
            public int compare(PmCompositeBlockDTO o1, PmCompositeBlockDTO o2) {
                return o1.getBlockNo().compareTo(o2.getBlockNo());
            }
        });
        // A 型BLOCK一定是1,模板个数等于小板数
        int pickModeWidDir = 0;
        for (int i = 0 ; i < compositeBoard.getBlkCount() ; i ++) {
            PmCompositeBlockDTO block = compositeBoard.getPmCompositeBlockDTOs().get(i);
            for(int j = 0 ; j < block.getSmallPlateDTOList().size() ; j++) {
                PmSmallPlateDTO currnetSmallPlate = block.getSmallPlateDTOList().get(j);
                checkSmallPlateCount(currnetSmallPlate, filterOrderMap.get(currnetSmallPlate.getOrderNo()), pmProContYieldMap.get(currnetSmallPlate.getOrderNo()));
                checkCutModeAndMultiPlateFlag(filterOrderMap.get(currnetSmallPlate.getOrderNo()));
                
                if(pickModeWidDir < currnetSmallPlate.getPickModeWidDirPos()) {
                    pickModeWidDir = currnetSmallPlate.getPickModeWidDirPos();
                }
            }
            pmCompositeSlabCalcDTO.getMLen().add(block.getBlockLength());
            if(i > 0) {
                PmCompositeBlockDTO lastBlock = compositeBoard.getPmCompositeBlockDTOs().get(i - 1);
                if(!lastBlock.getBlockWidth().equals(block.getBlockWidth())) {
                    // 统计异宽
                    pmCompositeSlabCalcDTO.setDiffNum(pmCompositeSlabCalcDTO.getDiffNum() + 1);
                    pmCompositeSlabCalcDTO.getDiffLoc().add(i);
                }
            }
        }
        pmCompositeSlabCalcDTO.setPickModeWidDir(pickModeWidDir);
        return pmCompositeSlabCalcDTO;
    }

    @Override
    public BigDecimal getSumPlateWt(Map<String, PmProContProdTtr> pmProContProdTtrs,
            PmProContYieldRequestDTO pmProContYield) {
        BigDecimal total = BigDecimal.ZERO;
        for (PmCompositeBlockDTO blockDTO : pmProContYield.getCompositeBoard().getPmCompositeBlockDTOs()) {
            for (PmSmallPlateDTO pmSmallPlateDTO : blockDTO.getSmallPlateDTOList()) {
                PmProContProdTtr pmProContProdTtr = pmProContProdTtrs.get(pmSmallPlateDTO.getOrderNo());
                total = total.add(pmProContProdTtr.getOrderUnitAimWt());
            }
        }
        return total;
    }

}
