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

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
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.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.PmSdivSpecLimitBt;
import com.xisc.pm.domain.entity.PmSmallPltPos;
import com.xisc.pm.domain.repository.PmSdivSpecLimitBtRepository;
import com.xisc.pm.infra.enums.FormPlateMode;
import com.xisc.pm.infra.util.Utils;

import io.choerodon.core.exception.CommonException;

/**
 * 
 * 组板方式S处理策略
 * 
 * @author jun.zeng
 *
 */
@Component
public class FormPlateModeSStrategy extends DefaultFormPlateModeStrategy {

    @Autowired
    private PmSdivSpecLimitBtRepository pmSdivSpecLimitBtRepository;
    
    @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::getPickModeWidDir));
        Long blockNo1 = null ;
        Long blockNo2 = null ;
        for (Long temp : blockMap.keySet()) {
            if(blockNo1 == null) {
                blockNo1 = temp ;
            } else {
                if(temp.longValue() > blockNo1.longValue()) {
                    blockNo2 = temp ;
                } else {
                    blockNo2 = blockNo1;
                    blockNo1 = temp ;
                }
            }
        }
        
        List<PmCompositeBlockDTO> pmCompositeBlockDTOs = new ArrayList<>();
        pmCompositeBoardDTO.setPmCompositeBlockDTOs(pmCompositeBlockDTOs);
        PmCompositeBlockDTO pmCompositeBloc1 = getPmCompositeBlock(blockMap.get(blockNo1), blockNo1);
        PmCompositeBlockDTO pmCompositeBloc2 = getPmCompositeBlock(blockMap.get(blockNo2), blockNo2);
        pmCompositeBlockDTOs.add(pmCompositeBloc1);
        pmCompositeBlockDTOs.add(pmCompositeBloc2);
        
        pmCompositeBoardDTO.setOrderCount(pmCompositeBloc1.getBlkOrderNum() + pmCompositeBloc2.getBlkOrderNum());
        pmCompositeBoardDTO.setBlkCount(2);
        pmCompositeBoardDTO.setPickModeWidDir(2);
        pmCompositeBoardDTO.setSpCount(pmSmallPltPoss.size());
        pmCompositeBoardDTO.setPickModeLenDir(pmCompositeBloc1.getBlkSpNum());
        pmCompositeBoardDTO.setSzLength(Utils.maxValue(pmCompositeBloc1.getBlockLength() , pmCompositeBloc2.getBlockLength()));
        pmCompositeBoardDTO.setSzWidth(pmCompositeBloc1.getBlockWidth().add(pmCompositeBloc2.getBlockWidth()));
        
        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::getPickModeWidDir));

        // S型组板，合同上下同长，取block1即可确认
        List<PmSmallPltPos> basePosList = blockMap.entrySet().iterator().next().getValue();
        basePosList.sort(new Comparator<PmSmallPltPos>() {
            @Override
            public int compare(PmSmallPltPos pos1, PmSmallPltPos pos2) {
                return pos1.getPickModeLenDir().compareTo(pos2.getPickModeLenDir());
            }
        });
        List<BigDecimal> motherableEndPosList = new ArrayList<BigDecimal>(basePosList.size());
        BigDecimal pos = BigDecimal.ZERO;
        for (PmSmallPltPos pmSmallPltPos : basePosList) {
            pos = pos.add(pmSmallPltPos.getSmallPlateLen());
            motherableEndPosList.add(pos);
        }

        return motherableEndPosList;
    }

    @Override
    public int maxBlockNum() {
        return 2;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        FormPlateModeStrategyFactory.register(FormPlateMode.S1, this);
        FormPlateModeStrategyFactory.register(FormPlateMode.S2, this);
        FormPlateModeStrategyFactory.register(FormPlateMode.S3, this);
        FormPlateModeStrategyFactory.register(FormPlateMode.S7, this);
        FormPlateModeStrategyFactory.register(FormPlateMode.S, this);
    }

    @Override
    public PmCompositeSlabCalcDTO checkAndInitParams(Map<String, PmProContFilterResposeDTO> filterOrderMap,
            PmProContYieldRequestDTO pmProContYield, PmProContProdTtr axisPmProContProdTtr) {
        FormPlateMode mode = getFormPlateMode(pmProContYield);
        PmCompositeBoardDTO compositeBoard = pmProContYield.getCompositeBoard();

        PmCompositeSlabCalcDTO pmCompositeSlabCalcDTO = super.checkAndInitParams(filterOrderMap, pmProContYield,
                axisPmProContProdTtr);
        if (compositeBoard.getBlkCount() != 2) {
            throw new CommonException("pm.pm_pro_cont_026");
        }
        // 长度方向取最大值，宽度方向两层相加
        pmCompositeSlabCalcDTO.setPickModeWidDir(maxBlockNum());
        int b1 = compositeBoard.getPmCompositeBlockDTOs().get(0).getBlkSpNum();
        int b2 = compositeBoard.getPmCompositeBlockDTOs().get(1).getBlkSpNum();
        if (b1 != b2) {
            throw new CommonException("pm.pm_pro_cont_027");
        }
        pmCompositeSlabCalcDTO.setPickModeLenDir(b1);
        pmCompositeSlabCalcDTO.setMotherableNum(compositeBoard.getPmCompositeBlockDTOs().get(0).getBlkSpNum());
        compositeBoard.getPmCompositeBlockDTOs().sort(new Comparator<PmCompositeBlockDTO>() {
            @Override
            public int compare(PmCompositeBlockDTO o1, PmCompositeBlockDTO o2) {
                return o1.getBlockNo().compareTo(o2.getBlockNo());
            }
        });
        PmCompositeBlockDTO block1 = compositeBoard.getPmCompositeBlockDTOs().get(0);
        PmCompositeBlockDTO block2 = compositeBoard.getPmCompositeBlockDTOs().get(1);

        // 默认长度，宽度
        BigDecimal defaultLen = block1.getSmallPlateDTOList().get(0).getSmallPlateLen();
        BigDecimal defaultWidth = block1.getSmallPlateDTOList().get(0).getSmallPlateWidth();
        BigDecimal defaultWidth2 = block2.getSmallPlateDTOList().get(0).getSmallPlateWidth();

        Map<String, PmProContYieldDTO> pmProContYieldMap = getPmProContYieldDTOMap(filterOrderMap ,pmProContYield);

        PmSdivSpecLimitBt record = new PmSdivSpecLimitBt();
        record.setRollLineNo(Utils.mscLineNoToRoolLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo()));
        record.setTenantId(pmProContYield.getTenantId());
        record = pmSdivSpecLimitBtRepository.selectOne(record);
        if (record == null) {
            throw new CommonException("pm.pm_pro_cont_035",
                    Utils.mscLineNoToRoolLineNo(pmProContYield.getPmContFilterRequest().getMscLineNo()));
        }

        // 同层小板长度相同标记
        boolean blockSmallPlateLenSameFlag = true ;
        
        for (int i = 0; i < block1.getSmallPlateDTOList().size(); i++) {
            PmSmallPlateDTO currnetSmallPlate = block1.getSmallPlateDTOList().get(i);
            pmCompositeSlabCalcDTO.getMLen().add(currnetSmallPlate.getSmallPlateLen());
            if (i > 0) {
                // 处理异宽，理论上S型一定是同宽的
                PmSmallPlateDTO lastSmallPlate = block1.getSmallPlateDTOList().get(i - 1);
                if (!lastSmallPlate.getOrderWidth().equals(currnetSmallPlate.getOrderWidth())) {
                    // 统计异宽
                    pmCompositeSlabCalcDTO.setDiffNum(pmCompositeSlabCalcDTO.getDiffNum() + 1);
                    pmCompositeSlabCalcDTO.getDiffLoc().add(i);
                }

            }
            PmSmallPlateDTO samllPlate1 = block1.getSmallPlateDTOList().get(i);
            PmSmallPlateDTO samllPlate2 = block2.getSmallPlateDTOList().get(i);

            checkSmallPlateCount(samllPlate1, filterOrderMap.get(samllPlate1.getOrderNo()),
                    pmProContYieldMap.get(samllPlate1.getOrderNo()));
            checkSmallPlateCount(samllPlate2, filterOrderMap.get(samllPlate2.getOrderNo()),
                    pmProContYieldMap.get(samllPlate2.getOrderNo()));
            checkCutModeAndMultiPlateFlag(filterOrderMap.get(samllPlate1.getOrderNo()));
            checkCutModeAndMultiPlateFlag(filterOrderMap.get(samllPlate2.getOrderNo()));
            if (FormPlateMode.S1.equals(mode)) {
                if (!defaultLen.equals(samllPlate1.getSmallPlateLen())
                        || !defaultLen.equals(samllPlate2.getSmallPlateLen())
                        || !defaultWidth.equals(samllPlate1.getSmallPlateWidth())
                        || !defaultWidth.equals(samllPlate2.getSmallPlateWidth())) {
                    // S1型组板所有合同必须同宽同长
                    throw new CommonException("pm.pm_pro_cont_028");
                }
            } else if (FormPlateMode.S2.equals(mode)) {
                if (0 != samllPlate1.getSmallPlateLen().compareTo(samllPlate2.getSmallPlateLen())) {
                    // 上下小板同长
                    throw new CommonException("pm.pm_pro_cont_029");
                }
                if (0 != defaultWidth.compareTo(samllPlate1.getSmallPlateWidth())) {
                    // 同层同宽
                    throw new CommonException("pm.pm_pro_cont_030", mode.getCode());
                }
                if (block1.getBlockWidth().compareTo(block2.getBlockWidth()) > 0) {
                    // 固定侧（block1）较移动侧（block2）窄。
                    throw new CommonException("pm.pm_pro_cont_033", mode.getCode());
                }
            } else if (FormPlateMode.S3.equals(mode)) {
                if (samllPlate1.getSmallPlateLen().compareTo(samllPlate2.getSmallPlateLen()) != 0) {
                    // 上下小板同长
                    throw new CommonException("pm.pm_pro_cont_029");
                }
                if (defaultWidth.compareTo(samllPlate1.getSmallPlateWidth()) != 0
                        || defaultWidth.compareTo(samllPlate2.getSmallPlateWidth()) != 0) {
                    // 所有合同同框
                    throw new CommonException("pm.pm_pro_cont_032", mode.getCode());
                }
            } else if (FormPlateMode.S7.equals(mode)) {
                if (samllPlate1.getSmallPlateLen().compareTo(samllPlate2.getSmallPlateLen()) != 0) {
                    // 上下小板同长
                    throw new CommonException("pm.pm_pro_cont_029");
                }
                if (defaultWidth.compareTo(samllPlate1.getSmallPlateWidth()) != 0) {
                    // 同层同宽
                    throw new CommonException("pm.pm_pro_cont_030", mode.getCode());
                }
                if (block1.getBlockWidth().compareTo(block2.getBlockWidth()) < 0) {
                    // 固定侧（block1）较移动侧（block2）宽。
                    throw new CommonException("pm.pm_pro_cont_033", mode.getCode());
                }
            } else {
                if (samllPlate1.getSmallPlateLen().compareTo(samllPlate2.getSmallPlateLen()) != 0) {
                    // 上下小板同长
                    throw new CommonException("pm.pm_pro_cont_029");
                }
                if (defaultWidth.compareTo(samllPlate1.getSmallPlateWidth())  != 0 || defaultWidth2.compareTo(samllPlate2.getSmallPlateWidth()) != 0) {
                    // 同层同宽
                    throw new CommonException("pm.pm_pro_cont_030", mode.getCode());
                }
                if(!defaultLen.equals(samllPlate1.getSmallPlateLen())) {
                    blockSmallPlateLenSameFlag = false ;
                }
            }
            if (block1.getSmallPlateDTOList().get(i).getSmallPlateWidth().compareTo(record.getSPdFixWidthMax()) > 0
                    || block1.getSmallPlateDTOList().get(i).getSmallPlateWidth()
                            .compareTo(record.getSPdFixWidthMin()) < 0) {
                throw new CommonException("pm.pm_pro_cont_036",
                        block1.getSmallPlateDTOList().get(i).getSmallPlateWidth().toPlainString(),
                        record.getSPdFixWidthMax().toPlainString(), record.getSPdFixWidthMin().toPlainString());
            }
            if (block2.getSmallPlateDTOList().get(i).getSmallPlateWidth().compareTo(record.getSPdMoveWidthMax()) > 0
                    || block2.getSmallPlateDTOList().get(i).getSmallPlateWidth()
                            .compareTo(record.getSPdMoveWidthMin()) < 0) {
                throw new CommonException("pm.pm_pro_cont_037",
                        block2.getSmallPlateDTOList().get(i).getSmallPlateWidth().toPlainString(),
                        record.getSPdMoveWidthMax().toPlainString(), record.getSPdMoveWidthMin().toPlainString());
            }
        }
        
        if(block1.getBlockWidth().compareTo(block2.getBlockWidth()) == 0) {
            if(blockSmallPlateLenSameFlag) {
                // a)   若组板所有合同同宽同长，组板方式form_plate_mode=S1;
                pmProContYield.getPmContFilterRequest().setFormPlateMode(FormPlateMode.S1.getCode()); 
            } else {
                // b)  若组板上下两层小板同宽，合同不同长，组板方式form_plate_mode=S3;
                pmProContYield.getPmContFilterRequest().setFormPlateMode(FormPlateMode.S3.getCode());
            }
        } else if(block1.getBlockWidth().compareTo(block2.getBlockWidth()) < 0) {
            // c)  若组板BLOCK2宽度大于BLOCK1宽度，组板方式form_plate_mode=S2;
            pmProContYield.getPmContFilterRequest().setFormPlateMode(FormPlateMode.S2.getCode());
        } else if(block1.getBlockWidth().compareTo(block2.getBlockWidth()) > 0) {
            // d)   若组板BLOLK2宽度小于BLOCK1宽度，组板方式form_plate_mode=S7;
            pmProContYield.getPmContFilterRequest().setFormPlateMode(FormPlateMode.S7.getCode());
        }

        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;
    }

}
