package com.jeeplus.modules.sg.balancedlibrary.materialReportDetails.utils;

import com.jeeplus.modules.sg.balancedlibrary.liKuResourcePool.entity.LiKuResourcePool;
import com.jeeplus.modules.sg.balancedlibrary.liKuResourcePool.utils.OptimalUtil;
import com.jeeplus.modules.sg.balancedlibrary.materialReportDetails.entity.CompareHistory;
import com.jeeplus.modules.sg.balancedlibrary.materialReportDetails.entity.MaterialDetails;
import com.jeeplus.modules.sg.balancedlibrary.materialReportDetails.entity.MaterialReportDetails;
import com.jeeplus.modules.sg.balancedlibrary.replaceMaterial.entity.ReplaceMaterial;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import static java.math.BigDecimal.ROUND_HALF_UP;

public class AdjustUtil {

    public static final String LOCAL_ADJUST = "本地利库"; //本地利库
    public static final String SPAN_ADJUST = "跨区利库";    //跨区利库
    public static final String REP_LOCAL_ADJUST = "本地以大代小利库"; //本地以大代小利库
    public static final String REP_SPAN_ADJUST = "跨区以大代小利库"; //跨区以大代小利库
    public static final String COMBINE_ADJUST = "合并利库"; //合并利库
    public static final String REP_COMBINE_ADJUST = "以大代小合并利库"; //合并利库


    /**
     * 非段长利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     */
    public static void nonSegAdjust(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList,String type){
        try {


            for (MaterialReportDetails report : reports) {
                String code = report.getMaterialCode();
                String exCode = report.getExtendedCoding();
                BigDecimal applyRemain = BigDecimal.valueOf(report.getNumberOfApplications());//剩余物资需求数量
                BigDecimal applyTotal = BigDecimal.valueOf(report.getTotal());//总需求数量
                BigDecimal applyLiku = BigDecimal.valueOf(report.getNumberOfNiches());//利库数量
                //如果总需求数量等于利库数量则不利库
                if (applyTotal.compareTo(applyLiku) == 0) {
                    continue;
                }
                for (LiKuResourcePool pool : pools) {
                    String poolCode = pool.getMaterialCode();
                    String poExCode = pool.getExtendedCoding();
                    Double remaining = pool.getRemaining();
                    if (null == remaining) {
                        remaining = 0.0;
                    }
                    Double numberOfNiches = pool.getNumberOfNiches();
                    if (null == numberOfNiches) {
                        numberOfNiches = 0.0;
                    }
                    BigDecimal poolRemain = BigDecimal.valueOf(remaining);//利库剩余库存数量
                    BigDecimal poolLiku = BigDecimal.valueOf(numberOfNiches);//利库数量
                    if (code.equals(poolCode) && exCode.equals(poExCode) && poolRemain.compareTo(BigDecimal.ZERO) != 0) {
                        BigDecimal likuAmount;//本次利库数量
                        if (applyRemain.compareTo(poolRemain) >= 0) {
                            likuAmount = poolRemain;
                        } else {
                            likuAmount = applyRemain;
                        }
                        //修改利库资源池的 剩余库存数量和利库数量
                        pool.setRemaining(poolRemain.subtract(likuAmount).setScale(2, ROUND_HALF_UP).doubleValue());
                        pool.setNumberOfNiches(poolLiku.add(likuAmount).setScale(2, ROUND_HALF_UP).doubleValue());
                        //修改物料申请的 利库数量和剩余申请数量
                        applyRemain = applyRemain.subtract(likuAmount).setScale(2, ROUND_HALF_UP);
                        applyLiku = applyLiku.add(likuAmount).setScale(2, ROUND_HALF_UP);
                        report.setNumberOfNiches(applyLiku.doubleValue());
                        report.setNumberOfApplications(applyRemain.doubleValue());
                        //记录利库详细信息
                        CompareHistory compareHistory = new CompareHistory();
                        compareHistory.setLiKuId(pool.getId());
                        compareHistory.setMaterialId(report.getId());
                        compareHistory.setComparisonType(type);
                        compareHistory.setNumberNiches(likuAmount.doubleValue());

                        compareList.add(compareHistory);
                        if (report.getNumberOfNiches().compareTo(report.getTotal()) == 0) {
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 非段长以大代小利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     * @param replaceList
     */
    public static void nonSegRepAdjust(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList, String type, List<ReplaceMaterial> replaceList){
        for (MaterialReportDetails report:reports) {
            String code = report.getMaterialCode();
            String exCode = report.getExtendedCoding();
            BigDecimal applyRemain = BigDecimal.valueOf(report.getNumberOfApplications());//剩余物资需求数量
            BigDecimal applyTotal = BigDecimal.valueOf(report.getTotal());//总需求数量
            BigDecimal applyLiku = BigDecimal.valueOf(report.getNumberOfNiches());//利库数量
            //如果总需求数量等于利库数量则不利库
            if (applyTotal.compareTo(applyLiku) == 0) {
                continue;
            }
            //查找所有可以替代信息
            List<ReplaceMaterial> usefulReplaces = new ArrayList<>();
            for(ReplaceMaterial replace:replaceList){
                if(code.equals(replace.getMaterialCode())&&exCode.equals(replace.getExtendedCoding())){
                    usefulReplaces.add(replace);
                }
            }
            //存在对应替换信息时才走后续流程
            if(usefulReplaces.size()>0){
                for(ReplaceMaterial replace:usefulReplaces){
                    String codeRep = replace.getMaterialCodeRep();
                    String exCodeRep = replace.getExtendedCodingRep();

                    for (LiKuResourcePool pool:pools) {
                        String poolCode = pool.getMaterialCode();
                        String poExCode = pool.getExtendedCoding();
                        BigDecimal poolRemain = BigDecimal.valueOf(pool.getRemaining());//利库剩余库存数量
                        BigDecimal poolLiku = BigDecimal.valueOf(pool.getNumberOfNiches());//利库数量
                        if (codeRep.equals(poolCode) && exCodeRep.equals(poExCode) && poolRemain.compareTo(BigDecimal.ZERO) != 0) {
                            BigDecimal likuAmount;//本次利库数量
                            if(applyRemain.compareTo(poolRemain) >= 0){
                                likuAmount = poolRemain;
                            }else {
                                likuAmount = applyRemain;
                            }
                            //修改利库资源池的 剩余库存数量和利库数量
                            pool.setRemaining(poolRemain.subtract(likuAmount).setScale(2, ROUND_HALF_UP).doubleValue());
                            pool.setNumberOfNiches(poolLiku.add(likuAmount).setScale(2, ROUND_HALF_UP).doubleValue());
                            //修改物料申请的 利库数量和剩余申请数量
                            applyRemain = applyRemain.subtract(likuAmount).setScale(2, ROUND_HALF_UP);
                            applyLiku = applyLiku.add(likuAmount).setScale(2, ROUND_HALF_UP);
                            report.setNumberOfNiches(applyLiku.doubleValue());
                            report.setNumberOfApplications(applyRemain.doubleValue());
                            //记录利库详细信息
                            CompareHistory compareHistory = new CompareHistory();
                            compareHistory.setLiKuId(pool.getId());
                            compareHistory.setMaterialId(report.getId());
                            compareHistory.setComparisonType(type);
                            compareHistory.setNumberNiches(likuAmount.doubleValue());
                            compareList.add(compareHistory);
                            //如果利库完成退出这个替换循环
                            if (report.getNumberOfNiches().compareTo(report.getTotal()) == 0) {
                                break;
                            }
                        }
                    }
                    //如果利库完成退出整个替换循环
                    if (report.getNumberOfNiches().compareTo(report.getTotal()) == 0) {
                        break;
                    }

                }
            }

        }
    }

    /**
     * 段长利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     */
    public static void segAdjust(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList,String type){
        for (LiKuResourcePool pool:pools) {
            if (pool.getCompleteLiKu() == 1) {
                continue;
            }
            String poolCode = pool.getMaterialCode();
            String poExCode = pool.getExtendedCoding();

            //通过物料编码，扩展编码，是否完成利库，获取符合当前利库线段数据的项目集合数据
            List<MaterialReportDetails> usefulReportList = Calculation(reports, poolCode, poExCode);
            if(usefulReportList.size()>0){
                //都是以米计算
                String unit = pool.getUnitOfMeasurement();
                Double lengthOfCable = pool.getLengthOfCable();
                if(unit.contains("千米")){
                    lengthOfCable = lengthOfCable*1000;
                }
                OptimalUtil optimalUtil = new OptimalUtil();
                //返回最优解
                List<MaterialReportDetails> bestChose = optimalUtil.getOptimal(lengthOfCable,usefulReportList);
                //计算最优解
                if (bestChose.size() > 0) {
                    BigDecimal totalLiku = BigDecimal.valueOf(0.0);
                    for (MaterialReportDetails report:bestChose) {
                        //修改物料的 待申报数量和利库数量
                        report.setNumberOfApplications(0.0);
                        report.setNumberOfNiches(report.getTotal());
                        //新增调整记录
                        CompareHistory compareHistory = new CompareHistory();
                        compareHistory.setLiKuId(pool.getId());
                        compareHistory.setMaterialId(report.getId());
                        compareHistory.setComparisonType(type);
                        compareHistory.setNumberNiches(report.getTotal());
                        compareList.add(compareHistory);
                        //计算资源池记录利库数量
                        totalLiku  = totalLiku.add(BigDecimal.valueOf(report.getTotal()));
                    }
                    BigDecimal poolLength = BigDecimal.valueOf(pool.getLengthOfCable());
                    BigDecimal remainLength = poolLength.subtract(totalLiku).setScale(2, ROUND_HALF_UP);
                    //存在最优解，当前利库信息使用，变更状态
                    pool.setNumberOfNiches(totalLiku.doubleValue());
                    pool.setRemaining(remainLength.doubleValue());
                    pool.setCompleteLiKu(1);
                }
            }

        }
    }

    /**
     * 以上报物资为主的段长利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     */
    public static void segAdjustReverse(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList,String type){
        for (MaterialReportDetails report:reports) {
            Double total = report.getTotal();
            Double niches = report.getNumberOfNiches();
            if (niches>=total) {
                continue;
            }
            String code = report.getMaterialCode();
            String exCode = report.getExtendedCoding();

            //通过物料编码，扩展编码，是否完成利库，获取符合当前利库线段数据的项目集合数据
            List<LiKuResourcePool> usefulLikuList = CalculationReverse(pools, code, exCode);
            if(usefulLikuList.size()>0){
                //都是以米计算
                String unit = report.getUnit();
                double totalMetre = total.doubleValue();
                if(unit.contains("千米")){
                    totalMetre = totalMetre*1000;
                }
                OptimalUtil optimalUtil = new OptimalUtil();
                //返回最优解
                List<LiKuResourcePool> bestChose = optimalUtil.getOptimalReverse(totalMetre,usefulLikuList);
                //计算最优解
                if (bestChose.size() > 0) {
                    BigDecimal totalLiku = BigDecimal.valueOf(0.0);
                    for (LiKuResourcePool pool:bestChose) {
                        //修改利库的剩余数量、利库数量和利库状态
                        pool.setRemaining(0.0);
                        pool.setNumberOfNiches(pool.getLengthOfCable());
                        pool.setCompleteLiKu(1);

                        report.setNumberOfApplications(0.0);
                        report.setNumberOfNiches(report.getTotal());
                        //新增调整记录
                        CompareHistory compareHistory = new CompareHistory();
                        compareHistory.setLiKuId(pool.getId());
                        compareHistory.setMaterialId(report.getId());
                        compareHistory.setComparisonType(type);
                        compareHistory.setNumberNiches(pool.getLengthOfCable());
                        compareList.add(compareHistory);
                        //计算记录利库总量
                        totalLiku  = totalLiku.add(BigDecimal.valueOf(pool.getLengthOfCable()));
                    }
                    report.setNumberOfApplications(0.0);
                    //这里利库数量有可能超过总量
                    report.setNumberOfNiches(totalLiku.doubleValue());
                }
            }

        }
    }

    /**
     * 段长以大代小利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     * @param replaceList
     */
    public static void segRepAdjust(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList,String type,List<ReplaceMaterial> replaceList){
        for (LiKuResourcePool pool:pools) {
            if (pool.getCompleteLiKu() == 1) {
                continue;
            }
            String poolCode = pool.getMaterialCode();
            String poExCode = pool.getExtendedCoding();
            //通过物料编码，扩展编码，是否完成利库，获取符合当前利库线段数据的项目集合数据
            List<MaterialReportDetails> usefulReportList = CalculationRep(reports, poolCode, poExCode,replaceList);
            if(usefulReportList.size()>0){
                //都是以米计算
                String poolUnit = pool.getUnitOfMeasurement();
                Double lengthOfCable = pool.getLengthOfCable();
                if(poolUnit.contains("千米")){
                    lengthOfCable = lengthOfCable*1000;
                }
                OptimalUtil optimalUtil = new OptimalUtil();
                //返回最优解
                List<MaterialReportDetails> bestChose = optimalUtil.getOptimal(lengthOfCable,usefulReportList);
                //计算最优解
                if (bestChose.size() > 0) {
                    BigDecimal totalLiku = BigDecimal.valueOf(0.0);
                    for (MaterialReportDetails report:bestChose) {
                        //修改物料的 待申报数量和利库数量
                        report.setNumberOfApplications(0.0);
                        report.setNumberOfNiches(report.getTotal());
                        //新增调整记录
                        CompareHistory compareHistory = new CompareHistory();
                        compareHistory.setLiKuId(pool.getId());
                        compareHistory.setMaterialId(report.getId());
                        compareHistory.setComparisonType(type);
                        compareHistory.setNumberNiches(report.getTotal());
                        compareList.add(compareHistory);
                        //这里处理资源池记录和物资申请记录单位不一致情况
                        String reportUnit = report.getUnit();
                        Double poolLiku = report.getTotal();//资源池在该物料身上的利库数量
                        if(poolUnit.trim().equals("千米")&&reportUnit.trim().equals("米")){
                            poolLiku = poolLiku/1000;
                        }
                        if(poolUnit.trim().equals("米")&&reportUnit.trim().equals("千米")){
                            poolLiku = poolLiku*1000;
                        }
                        //计算资源池记录利库数量
                        totalLiku  = totalLiku.add(BigDecimal.valueOf(poolLiku));
                    }
                    BigDecimal poolLength = BigDecimal.valueOf(pool.getLengthOfCable());
                    BigDecimal remainLength = poolLength.subtract(totalLiku).setScale(2, ROUND_HALF_UP);
                    //存在最优解，当前利库信息使用，变更状态
                    pool.setNumberOfNiches(totalLiku.doubleValue());
                    pool.setRemaining(remainLength.doubleValue());
                    pool.setCompleteLiKu(1);
                }
            }

        }
    }


    /**
     * 以上报物资为主的段长以大代小利库
     * @param reports
     * @param pools
     * @param compareList
     * @param type
     * @param replaceList
     */
    public static void segRepAdjustReverse(List<MaterialReportDetails> reports, List<LiKuResourcePool> pools, List<CompareHistory> compareList,String type,List<ReplaceMaterial> replaceList){
        for (MaterialReportDetails report:reports) {
            Double total = report.getTotal();
            Double niches = report.getNumberOfNiches();
            if (niches>=total) {
                continue;
            }
            String code = report.getMaterialCode();
            String exCode = report.getExtendedCoding();


            //通过物料编码，扩展编码，是否完成利库，获取符合当前利库线段数据的项目集合数据
            List<LiKuResourcePool> usefulPoolList = CalculationRepReverse(pools, code, exCode,replaceList);
            if(usefulPoolList.size()>0){
                //都是以米计算
                String unit = report.getUnit();
                double totalMetre = total.doubleValue();
                if(unit.contains("千米")){
                    totalMetre = totalMetre*1000;
                }
                OptimalUtil optimalUtil = new OptimalUtil();
                //返回最优解
                List<LiKuResourcePool> bestChose = optimalUtil.getOptimalReverse(totalMetre,usefulPoolList);
                //计算最优解
                if (bestChose.size() > 0) {
                    BigDecimal totalLiku = BigDecimal.valueOf(0.0);
                    for (LiKuResourcePool pool:bestChose) {
                        pool.setNumberOfNiches(pool.getLengthOfCable());
                        pool.setRemaining(0.0);
                        pool.setCompleteLiKu(1);
                        //新增调整记录
                        CompareHistory compareHistory = new CompareHistory();
                        compareHistory.setLiKuId(pool.getId());
                        compareHistory.setMaterialId(report.getId());
                        compareHistory.setComparisonType(type);
                        compareHistory.setNumberNiches(pool.getLengthOfCable());
                        compareList.add(compareHistory);
                        //计算资源池记录利库数量(米)
                        totalLiku  = totalLiku.add(BigDecimal.valueOf(pool.getLengthOfMetre()));
                    }
                    report.setNumberOfApplications(0.0);
                    if(unit.contains("千米")){
                        report.setNumberOfNiches(totalLiku.doubleValue()/1000);
                    }else{
                        report.setNumberOfNiches(totalLiku.doubleValue());
                    }
                }
            }

        }
    }


    /***
     * 通过项目编码，扩展编码，查询在物资上报中，符合利库数据集合，且这些上报数据都应未利库
     * */
    private static List<MaterialReportDetails> Calculation(List<MaterialReportDetails> segmentList, String poolCode, String poExCode) {
        List<MaterialReportDetails> returnList = new ArrayList<>();
        for (MaterialReportDetails details:segmentList) {
            String code = details.getMaterialCode();
            String exCode = details.getExtendedCoding();
            //物资需求数量
            BigDecimal total = BigDecimal.valueOf(details.getTotal());
            //利库数量
            BigDecimal numberOfNiches = BigDecimal.valueOf(details.getNumberOfNiches());
            if (poolCode.equals(code) && poExCode.equals(exCode) && total.compareTo(numberOfNiches) > 0) {
                //对可用的物资做米和千米的处理
                String unit = details.getUnit();
                if(unit.contains("千米")){
                    details.setLengthOfMetre(details.getTotal()*1000);
                }else{
                    details.setLengthOfMetre(details.getTotal());
                }
                returnList.add(details);
            }
        }
        return returnList;
    }

    /***
     * 以上报物资为主查找利库中可用数据
     * */
    private static List<LiKuResourcePool> CalculationReverse(List<LiKuResourcePool> poolList, String code, String exCode) {
        List<LiKuResourcePool> returnList = new ArrayList<>();
        for (LiKuResourcePool pool:poolList) {
            String poolCode = pool.getMaterialCode();
            String poolExCode = pool.getExtendedCoding();
            Integer likuStatus = pool.getCompleteLiKu();
            //利库未完成
            if (code.equals(poolCode) && exCode.equals(poolExCode) && likuStatus!=1) {
                //对可用的物资做米和千米的处理
                String unit = pool.getUnitOfMeasurement();
                if(unit.contains("千米")){
                    pool.setLengthOfMetre(pool.getLengthOfCable()*1000);
                }else{
                    pool.setLengthOfMetre(pool.getLengthOfCable());
                }
                returnList.add(pool);
            }
        }
        return returnList;
    }

    /***
     * 通过项目编码，扩展编码，查询在物资上报中，符合利库替换数据集合，计算后续最优解-以大代小
     * */
    private static List<MaterialReportDetails> CalculationRep(List<MaterialReportDetails> reportList, String poolCode, String poExCode,List<ReplaceMaterial> replaceList) {
        List<MaterialReportDetails> returnList = new ArrayList<>();

        //查找所有可以替代信息
        List<ReplaceMaterial> usefulReplaces = new ArrayList<>();
        for(ReplaceMaterial replace:replaceList){
            //不管何时一定是上报物资编码与replace中的编码匹配，利库编码与replace中的替代编码匹配
            if(poolCode.equals(replace.getMaterialCodeRep())&&poExCode.equals(replace.getExtendedCodingRep())){
                usefulReplaces.add(replace);
            }
        }
        if(usefulReplaces.size()>0){
            for(ReplaceMaterial replace:usefulReplaces){
                String repCode = replace.getMaterialCode();
                String repExCode = replace.getExtendedCoding();
                for(MaterialReportDetails report:reportList){
                    String code = report.getMaterialCode();
                    String exCode = report.getExtendedCoding();
                    BigDecimal totalNeed = BigDecimal.valueOf(report.getTotal());//物资需求数量
                    BigDecimal likuNum = BigDecimal.valueOf(report.getNumberOfNiches());//利库数量
                    if (repCode.equals(code) && repExCode.equals(exCode) && totalNeed.compareTo(likuNum) > 0) {
                        //对可用的物资做米和千米的处理
                        String unit = report.getUnit();
                        if(unit.contains("千米")){
                            report.setLengthOfMetre(report.getTotal()*1000);
                        }else{
                            report.setLengthOfMetre(report.getTotal());
                        }
                        returnList.add(report);
                    }
                }
            }
        }

        return returnList;
    }

    /***
     * 以上报物资为主，在利库资源池中查找可用的替换物资
     * */
    private static List<LiKuResourcePool> CalculationRepReverse(List<LiKuResourcePool> poolList, String code, String exCode,List<ReplaceMaterial> replaceList) {
        List<LiKuResourcePool> returnList = new ArrayList<>();

        //查找所有可以替代信息
        List<ReplaceMaterial> usefulReplaces = new ArrayList<>();
        for(ReplaceMaterial replace:replaceList){
            if(code.equals(replace.getMaterialCode())&&exCode.equals(replace.getExtendedCoding())){
                usefulReplaces.add(replace);
            }
        }
        if(usefulReplaces.size()>0){
            for(ReplaceMaterial replace:usefulReplaces){
                String repCode = replace.getMaterialCodeRep();
                String repExCode = replace.getExtendedCodingRep();
                for(LiKuResourcePool pool:poolList){
                    String poolCode = pool.getMaterialCode();
                    String poolExCode = pool.getExtendedCoding();
                    Integer likuStatus = pool.getCompleteLiKu();
                    if (repCode.equals(poolCode) && repExCode.equals(poolExCode) && likuStatus!=1) {
                        //对可用的物资做米和千米的处理
                        String unit = pool.getUnitOfMeasurement();
                        if(unit.contains("千米")){
                            pool.setLengthOfMetre(pool.getLengthOfCable()*1000);
                        }else{
                            pool.setLengthOfMetre(pool.getLengthOfCable());
                        }
                        returnList.add(pool);
                    }
                }
            }
        }

        return returnList;
    }
}
