package com.xisc.pm.app.service.autoboard.dto;

import java.io.Serializable;
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.TreeMap;
import java.util.Map.Entry;
import java.util.Set;

import com.xisc.pm.app.service.autoboard.config.CalcLog;

import lombok.Data;

/**
 * 自动组板策略
 * 
 * @author jun.zeng
 *
 */
@Data
public class PmAutoBoardExecResult implements Serializable {

    private static final long serialVersionUID = 6281508617849119620L;

    // 已经组板的数量
    private Map<String, BigDecimal> pdQty = new HashMap<String, BigDecimal>(10000);
    // 超投数量
    private Map<String, BigDecimal> pdOverDevoQty = new HashMap<String, BigDecimal>(10000);

    private List<PmPdResultDTO> pmPdResultDTOs = new ArrayList<PmPdResultDTO>(10000);

    private Map<String, BigDecimal> mscLineNoWt = new HashMap<String, BigDecimal>();
    // 产线+钢种为key
    private Map<String , BigDecimal> stWt = new HashMap<String, BigDecimal>();
    // 产线+客户为key
    private Map<String , BigDecimal> customerWt = new HashMap<String, BigDecimal>();

    private BigDecimal sumWt = BigDecimal.ZERO;
    private int slabNoCount = 0;
    private int spCount = 0;
    
    private int version = 0;
    
    private long endTime = 0;
    private long startTime = 0;
    
    private BigDecimal score ;
    
    private BigDecimal averageYield = BigDecimal.ZERO;
    
    private BigDecimal contractAllowance = BigDecimal.ZERO;
    
    public PmAutoBoardExecResult(){
        this.startTime = System.currentTimeMillis();
    }

    /**
     * 获取剩余组板欠件
     * 
     * @param pmContBoardParam
     * @return
     */
    public BigDecimal calcRemainingPdQty(PmContBoardParam pmContBoardParam) {
        if (pdQty.containsKey(pmContBoardParam.getOrderNo())) {
            return pmContBoardParam.getPdLockQty().subtract(pdQty.get(pmContBoardParam.getOrderNo()));
        }
        return pmContBoardParam.getPdLockQty();
    }

    public String getBoardSummaryData() {
        return "得分：" + (this.score != null ? this.score.toPlainString():"") + "合约尾量：" + contractAllowance.toPlainString() + "总重量：" + sumWt.toPlainString() + " 总组板数：" + slabNoCount + "  总小板数：" + spCount 
                + " 【版本" + version +"】执行总耗时：" + (endTime - startTime);
    }

    /**
     * 判断是否满足产线产能
     * @param pmAutoBoardExecParam
     * @return
     */
    public boolean judgeMscLineSumWt(PmAutoBoardExecParam pmAutoBoardExecParam , BigDecimal sumWt) {
        if (pmAutoBoardExecParam.getPolicy().getProdLineProductivity() == null) {
            return true;
        }
        BigDecimal mscLineNoSumWt = sumWt;
        if(mscLineNoSumWt == null) {
            mscLineNoSumWt = this.getMscLineNoWt().get(pmAutoBoardExecParam.getMscLineNo());
        }
        if (mscLineNoSumWt == null) {
            return true;
        }
        if (mscLineNoSumWt.compareTo(pmAutoBoardExecParam.getPolicy().getProdLineProductivity()) > 0) {
            CalcLog.log("当前产线合同总重量：" + mscLineNoSumWt.toPlainString() + ",超过产线总产能："
                    + pmAutoBoardExecParam.getPolicy().getProdLineProductivity().toPlainString());
            return false;
        }
        return true;
    }
    
    private void checkStAndCustomerWt(PmPdResultDTO pdResult , Map<String , PmContBoardParam> orderMap) {
        if(pdResult.getCurrent().getPolicy().getStLowerEconomicLots() == null && pdResult.getCurrent().getPolicy().getCustLowerEconomicLots() == null) {
            return ;
        }
        Map<String , BigDecimal> tmpStWtMap = new HashMap<>();
        Map<String , BigDecimal> tmpCustWtMap = new HashMap<>();
        if (pdResult.getBlock1() != null) {
            for (String orderNo : pdResult.getBlock1()) {
                PmContBoardParam pmContBoardParam = orderMap.get(orderNo);
                String stKey = pdResult.getCurrent().getMscLineNo() + "-" + pmContBoardParam.getStNo();
                String cusKey = pdResult.getCurrent().getMscLineNo() + "-" + pmContBoardParam.getOrderCustCname();
                BigDecimal tmpStWt = pmContBoardParam.getOrderUnitAim() ;
                BigDecimal tmpCustWt = pmContBoardParam.getOrderUnitAim() ;
                if(this.stWt.containsKey(stKey)) {
                    tmpStWt = this.stWt.get(stKey).add(pmContBoardParam.getOrderUnitAim());
                } 
                if(this.customerWt.containsKey(cusKey)) {
                    tmpCustWt = this.customerWt.get(cusKey).add(pmContBoardParam.getOrderUnitAim());
                }
                tmpStWtMap.put(stKey, tmpStWt);
                tmpCustWtMap.put(stKey, tmpCustWt);
            }
        }
        if (pdResult.getBlock2() != null) {
            for (String orderNo : pdResult.getBlock2()) {
                PmContBoardParam pmContBoardParam = orderMap.get(orderNo);
                String stKey = pdResult.getCurrent().getMscLineNo() + "-" + pmContBoardParam.getStNo();
                String cusKey = pdResult.getCurrent().getMscLineNo() + "-" + pmContBoardParam.getOrderCustCname();
                BigDecimal tmpStWt = pmContBoardParam.getOrderUnitAim() ;
                BigDecimal tmpCustWt = pmContBoardParam.getOrderUnitAim() ;
                if(this.stWt.containsKey(stKey)) {
                    tmpStWt = this.stWt.get(stKey).add(pmContBoardParam.getOrderUnitAim());
                } 
                if(this.customerWt.containsKey(cusKey)) {
                    tmpCustWt = this.customerWt.get(cusKey).add(pmContBoardParam.getOrderUnitAim());
                }
                tmpStWtMap.put(stKey, tmpStWt);
                tmpCustWtMap.put(stKey, tmpCustWt);
            }
        }
        if(tmpStWtMap != null && !tmpStWtMap.isEmpty()) {
            this.stWt.putAll(tmpStWtMap);
        }
        if(tmpCustWtMap != null && !tmpStWtMap.isEmpty()) {
            this.customerWt.putAll(tmpCustWtMap);
        }
    }
    
    /**
     * 生产板坯记录
     * @param pdResult
     * @return
     */
    public boolean addVirtualSlab(PmPdResultDTO pdResult) {
        PmAutoBoardExecParam pmAutoBoardExecParam = pdResult.getCurrent();
        BigDecimal mscLineNoSumWt = pdResult.getSumWt();
        if (mscLineNoWt.containsKey(pmAutoBoardExecParam.getMscLineNo())) {
            mscLineNoSumWt = mscLineNoSumWt.add(mscLineNoWt.get(pmAutoBoardExecParam.getMscLineNo()));
        }
        if (!judgeMscLineSumWt(pmAutoBoardExecParam , mscLineNoSumWt)) {
            return false;
        }
        Map<String , PmContBoardParam> orderMap = new HashMap<>();
        for (PmContBoardParam pmContBoardParam : pdResult.getPmContBoardParams()) {
            orderMap.put(pmContBoardParam.getOrderNo() ,pmContBoardParam);
        }
//        checkStAndCustomerWt(pdResult, orderMap);
        mscLineNoWt.put(pmAutoBoardExecParam.getMscLineNo(), mscLineNoSumWt);
        slabNoCount++;
        averageYield = averageYield.add(pdResult.getRespose().getCommandYield());
        pmPdResultDTOs.add(pdResult);
        sumWt = sumWt.add(pdResult.getSumWt());
        if (pdResult.getBlock1() != null) {
            for (String orderNo : pdResult.getBlock1()) {
                PmContBoardParam pmContBoardParam = orderMap.get(orderNo);
                if(pmContBoardParam != null && pmContBoardParam.getContractAllowanceFlag() != null && pmContBoardParam.getContractAllowanceFlag() == 1L) {
                    contractAllowance = contractAllowance.add(BigDecimal.ONE);
                }
                if (!pdQty.containsKey(orderNo)) {
                    pdQty.put(orderNo, BigDecimal.ZERO);
                }
                pdQty.put(orderNo, pdQty.get(orderNo).add(BigDecimal.ONE));
            }
            spCount += pdResult.getBlock1().size();
        }
        if (pdResult.getBlock2() != null) {
            for (String orderNo : pdResult.getBlock2()) {
                PmContBoardParam pmContBoardParam = orderMap.get(orderNo);
                if(pmContBoardParam != null && pmContBoardParam.getContractAllowanceFlag() != null && pmContBoardParam.getContractAllowanceFlag() == 1L) {
                    contractAllowance = contractAllowance.add(BigDecimal.ONE);
                }
                if (!pdQty.containsKey(orderNo)) {
                    pdQty.put(orderNo, BigDecimal.ZERO);
                }
                pdQty.put(orderNo, pdQty.get(orderNo).add(BigDecimal.ONE));
            }
            spCount += pdResult.getBlock2().size();
        }
        CalcLog.log("组板成功：" + pdResult.toString());
        return true;
    }

    public TreeMap<String, Integer> print(Map<String, PmContBoardParam> orignData) {
        int count = 0;
        @SuppressWarnings({ "unchecked", "rawtypes" })
        TreeMap<String, Integer> treeMap = new TreeMap(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        for (PmPdResultDTO pmPdResultDTO : this.pmPdResultDTOs) {
            if (pmPdResultDTO.getBlock1() != null) {
                for (String value : pmPdResultDTO.getBlock1()) {
                    if (!treeMap.containsKey(value)) {
                        count++;
                        treeMap.put(value, 1);
                    } else {
                        count++;
                        treeMap.put(value, treeMap.get(value) + 1);
                    }
                }
            }
            if (pmPdResultDTO.getBlock2() != null) {
                for (String value : pmPdResultDTO.getBlock2()) {
                    if (!treeMap.containsKey(value)) {
                        count++;
                        treeMap.put(value, 1);
                    } else {
                        count++;
                        treeMap.put(value, treeMap.get(value) + 1);
                    }
                }
            }
        }
        for (Entry<String, Integer> entry : treeMap.entrySet()) {
            CalcLog.log(entry.getKey() + ": " + entry.getValue() + " 计算: " + this.pdQty.get(entry.getKey()) + " 欠件： "
                    + orignData.get(entry.getKey()).getPdLockQty());
        }
        CalcLog.log("合同：" + treeMap.size() + " all: " + count);
        return treeMap;
    }

}
