package com.prolog.eis.algorithm;

import com.prolog.eis.dto.buildwave.*;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;
import java.util.*;

@Getter
@Setter
public class PickOrderBuilder {
    @ApiModelProperty("一个拣选单的最大运单数")
    private int maxOrderCount;

    @ApiModelProperty("一个拣选单的最大品类数")
    private int maxSPCount = 99999999;

    @ApiModelProperty("最大体积")
    private BigDecimal maxVolume = new BigDecimal(99999999);

    @ApiModelProperty("所有订单集合")
    private PObOrderCollection orderCollection;

    @ApiModelProperty("可用库存")
    private Map<String, BigDecimal> storeMap = new HashMap<>();

    public PickOrderBuilder(PObOrderCollection orderCollection, int maxOrderCount, BigDecimal maxVolume, int maxSkuCount, Map<String, BigDecimal> storeMap) {
        this.setOrderCollection(orderCollection);
        this.setMaxVolume(maxVolume);
        this.setMaxOrderCount(maxOrderCount);
        this.setMaxSPCount(maxSkuCount);
        this.setStoreMap(storeMap);
    }

    /**
     * 扣减订单需求库存
     *
     * @param order
     * @throws Exception
     */
    private void subtractOrderStore(PObOrderDto order) throws Exception {
        for (PObOrderDetailDto detail : order.getDetailList()) {
            if (!storeMap.containsKey(detail.getItemNo())) {
                throw new Exception("选择的订单" + detail.getItemNo() + "库存不足");
            }

            BigDecimal storeNum = storeMap.get(detail.getItemNo());
            if (detail.getPlanNum().compareTo(storeNum) > 0) {
                throw new Exception("选择的订单" + detail.getItemNo() + "库存不足");
            }

            //库存扣减订单明细计划数量
            storeMap.put(detail.getItemNo(), storeNum.subtract(detail.getPlanNum()));
        }
    }

    private void removeStoreNotEnoughOrder() {
        for (int i = orderCollection.getOrderList().size() - 1; i > -1; i--) {
            PObOrderDto order = orderCollection.getOrderList().get(i);
            if (!this.checkOrderStore(order)) {
                orderCollection.getOrderList().remove(i);
            }
        }
    }

    private boolean checkOrderStore(PObOrderDto order) {
        for (PObOrderDetailDto detail : order.getDetailList()) {
            if (detail.getPlanNum().compareTo(BigDecimal.ZERO) > 0) {
                if (!storeMap.containsKey(detail.getItemNo())) {
                    System.out.println("新组波订单：" + order.getOrderId() + "，商品：" + detail.getItemNo() + "库存不足!");
                    return false;
                }

                BigDecimal storeNum = storeMap.get(detail.getItemNo());
                if (storeNum.compareTo(detail.getPlanNum()) < 0) {
                    System.out.println("新组波订单：" + order.getOrderId() + "，商品：" + detail.getItemNo() + "库存不足!");
                    return false;
                }
            }
        }
        return true;
    }


    private PObOrderDto FindFirstYunDanGroup(PObPickOrderDto pickOrder) {
        PObOrderDto bestOrder = null;
        for (PObOrderDto order : this.getOrderCollection().getOrderList()) {
            if (bestOrder == null) {
                bestOrder = order;
                continue;
            }

            if (order.getDetailStoreMap().size() > bestOrder.getDetailStoreMap().size()) {
                bestOrder = order;
                continue;
            }
        }

        if (bestOrder != null) {
            pickOrder.addYunDan(bestOrder);
            this.getOrderCollection().getOrderList().remove(bestOrder);
        }
        return bestOrder;
    }

    /**
     * 计算每个运单与当前拣选单的匹配数量和不匹配数量
     *
     * @param jxd
     */
    private void computeMatchCount(PObPickOrderDto jxd) {
        //查找一个完全包含的运单则直接加入拣选单
        for (PObOrderDto order : this.getOrderCollection().getOrderList()) {
            int matchCount = 0;
            int notMatchCount = 0;
            for (String spId : order.getDetailStoreMap().keySet()) {
                if (jxd.getSpPicHs().contains(spId))
                    matchCount += 1;
                else
                    notMatchCount += 1;
            }

            order.setMatchCount(matchCount);
            order.setNotMatchCount(notMatchCount);
        }
    }

    /**
     * 根据比较器查找集合中的最大元素
     */
    private PObOrderDto FindBestYDGroup(Collection<PObOrderDto> orderList, Comparator<PObOrderDto> orderComparator) {
        PObOrderDto bestOrder = null;

        for (PObOrderDto order : orderList) {
            if (bestOrder == null) {
                bestOrder = order;
            } else {
                if (orderComparator.compare(order, bestOrder) < 0)//判断当前元素是否比最大元素要大
                {
                    bestOrder = order;
                }
            }
        }

        return bestOrder;
    }

    private PObOrderDto findYunDan(PObPickOrderDto jxd) {
        if (this.getOrderCollection().getOrderList() == null || this.getOrderCollection().getOrderList().size() == 0)
            return null;

        this.computeMatchCount(jxd);

        PObOrderDto bestOrder = this.FindBestYDGroup(this.getOrderCollection().getOrderList(), (order1, order2) ->
        {
            //计算匹配系数
            float p1 = (float) order1.getMatchCount() / (order1.getMatchCount() + order1.getNotMatchCount());
            float p2 = (float) order2.getMatchCount() / (order2.getMatchCount() + order2.getNotMatchCount());

            if (Math.abs(p1 - p2) < 0.001f) {
                //匹配系数相同的情况下匹配数量多的优先
                if (order1.getMatchCount() > order2.getMatchCount()) {
                    return -1;
                } else if (order1.getMatchCount() < order2.getMatchCount()) {
                    return 1;
                } else {
                    return 0;
                }
            } else {
                //匹配数量高的优先
                if (p1 > p2)
                    return -1;
                if (p1 < p2)
                    return 1;
                else
                    return 0;
            }
        });

        if (bestOrder != null) {
            jxd.addYunDan(bestOrder);
            this.getOrderCollection().getOrderList().remove(bestOrder);
        }
        return bestOrder;
    }

    private void init() {
        for (PObOrderDto order : this.getOrderCollection().getOrderList()) {
            order.init();
        }
    }

    public PObPickOrderDto takerPickOrder() throws Exception {
        this.init();

        PObPickOrderDto jxd = new PObPickOrderDto();

        this.removeStoreNotEnoughOrder();
        PObOrderDto order = this.FindFirstYunDanGroup(jxd);
        if (order == null) {
            return jxd;
        }
        this.subtractOrderStore(order);

        while (this.getOrderCollection().getOrderList().size() > 0 && jxd.getOrderList().size() < this.getMaxOrderCount()) {
            this.removeStoreNotEnoughOrder();
            PObOrderDto bestOrder = this.findYunDan(jxd);
            if (bestOrder == null)
                break;

            this.subtractOrderStore(bestOrder);

            //超过SKU限制，则从当前订单结束
            if (jxd.getSpPicHs().size() > this.getMaxSPCount())
                break;
        }

        return jxd;
    }

//    private boolean takeYunDan(PObPickOrderDto jxd, PObOrderDto order) {
//        int maxTakeCount = this.getMaxOrderCount() - jxd.getOrderList().size();
//        int takeCount = ydGroup.getYunDanList().size();
//
//        if (takeCount > maxTakeCount)
//            takeCount = maxTakeCount;
//
//        for (int i = 0; i < takeCount; i++) {
//            PObOrderDto order = ydGroup.getYunDanList().get(0);
//
//            jxd.addYunDan(order);
//            ydGroup.getYunDanList().remove(0);
//            jxd.setTotalVolume(jxd.getTotalVolume().add(order.getVolume()));
//
//            //超过体积范围则从当前订单结束
//            if (jxd.getTotalVolume().compareTo(this.getMaxVolume()) >= 0)
//                return true;
//        }
//
//        //移除已经没有订单的订单组
//        if (ydGroup.getYunDanList().isEmpty())
//            this.getOrderGroupDic().remove(ydGroup.getYunDanSPKey());
//
//        return false;
//    }

//    public PObPickOrderDto buildPickOrder() throws Exception {
//        PObPickOrderDto pickOrder = this.takerPickOrder();
//        return pickOrder;
//    }

    public List<PObPickOrderDto> buildPickOrderList(int pickOrderCount) throws Exception {
        List<PObPickOrderDto> pickOrderList = new ArrayList<>();
        while (pickOrderList.size() < pickOrderCount) {
            PObPickOrderDto pickOrder = this.takerPickOrder();
            pickOrderList.add(pickOrder);
        }

        return pickOrderList;
    }
}
