package com.liquidnet.service.goblin.util;

import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.entity.GoblinGoodsSku;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class GoblinNftBoxUtils {

    @Autowired
    GoblinRedisUtils redisUtils;

    /**
     * 获取每个sku的兑换码生成数量
     * <p>
     * sku兑换码数 = 生码总数 * sku概率/总概率
     * 若sku兑换码数 > sku剩余库存
     * 用 sku兑换码数 - sku剩余库存 * (其他sku概率/其他总概率)
     * <p>
     * 例：生成兑换码 120 有sku1,sku2,sku3
     * sku1 库存5 概率 10%
     * sku2 库存100 概率 20%
     * sku3 库存100 概率 30%
     * <p>
     * sku1兑换码数=120 * (10/60) = 20   >5
     * sku2兑换码数=120 * (20/60) = 40 <100
     * sku3兑换码数=120 * (30/60) = 60 <100
     * <p>
     * sku2第二轮兑换码数 = (20-5) * (20/50) = 6 < 60
     * sku3第二轮兑换码数 = (20-5) * (30/50) = 9 < 40
     * <p>
     * 总兑换码 = sku1兑换码数+sku2兑换码数+sku3兑换码数+sku2第二轮兑换码数+sku3第二轮兑换码数
     *
     * @return
     */
    public Map<String, Integer> getSkuHitRatio(Integer exStock, Map<String, BigDecimal> map) {

        // 获取sku总概率
        BigDecimal hitRatioCount = new BigDecimal(0);


        // Map<String, Map<String, Object>> mapMap = new HashMap<>();

        // sku --> 概率/库存
        Integer countStockNumber = 0;
        HashMap<String, Map<String, Object>> mapMap = CollectionUtil.mapHashMap();
        for (String key : map.keySet()) {
            BigDecimal skuHitRatio = BigDecimal.valueOf(Double.valueOf(map.get(key).toString()));
            HashMap<String, Object> objectMap = CollectionUtil.mapStringObject();
            if (skuHitRatio == null) {
                continue;
            }
            hitRatioCount = hitRatioCount.add(skuHitRatio);
            objectMap.put("hitRatio", skuHitRatio);
            objectMap.put("stock", redisUtils.getSkuStock(null,key));
            countStockNumber += redisUtils.getSkuStock(null,key);
            mapMap.put(key, objectMap);

        }


        // sku ---> 库存
        HashMap<String, Integer> stockMap = CollectionUtil.mapStringInteger();
        ArrayList<String> eliminateSkuIdList = CollectionUtil.arrayListString();
        getStock(exStock, hitRatioCount, mapMap, stockMap, countStockNumber, eliminateSkuIdList);
        return stockMap;
    }

    /**
     * 获取单个sku库存
     *
     * @param exStock
     * @param hitRatioCount
     * @param mapMap
     * @return
     */
    private static void getStock(Integer exStock, BigDecimal hitRatioCount, Map<String, Map<String, Object>> mapMap, Map<String, Integer> stockMap, Integer countStockNumber, ArrayList<String> eliminateSkuIdList) {
        if (exStock <= 0 || countStockNumber == 0) {
            return;
        }

        // 单个sku ---> 当前循环权重
        HashMap<String, BigDecimal> bigDecimalHashMap = CollectionUtil.mapStringBigDecimal();
        int subNumber = 0;
        for (String key : mapMap.keySet()) {
            Object stock = mapMap.get(key).get("stock");
            Object hitRatio = mapMap.get(key).get("hitRatio");
            if (Integer.valueOf(stock.toString()) <= 0) {
                continue;
            }

            BigDecimal bigDecimal = BigDecimal.valueOf(exStock).multiply((new BigDecimal(hitRatio.toString()).divide(hitRatioCount, 5, BigDecimal.ROUND_HALF_UP)));
            bigDecimalHashMap.put(key, bigDecimal);

            // 要减去的库存
            int subStock = BigDecimal.valueOf(exStock).multiply((new BigDecimal(hitRatio.toString()).divide(hitRatioCount, 5, BigDecimal.ROUND_HALF_UP))).setScale(0, BigDecimal.ROUND_UP).intValue();

            if (subStock > Integer.valueOf(stock.toString())) {
                subNumber += Integer.valueOf(stock.toString());
                countStockNumber -= Integer.valueOf(stock.toString());
                mapMap.get(key).put("stock", 0);
                if (stockMap.get(key) == null) {
                    stockMap.put(key, Integer.valueOf(stock.toString()));
                } else {
                    stockMap.put(key, stockMap.get(key) + Integer.valueOf(stock.toString()));
                }

            } else {
                countStockNumber -= subStock;
                mapMap.get(key).put("stock", Integer.valueOf(stock.toString()) - subStock);
                subNumber += subStock;
                if (stockMap.get(key) == null) {
                    stockMap.put(key, subStock);
                } else {
                    stockMap.put(key, stockMap.get(key) + subStock);
                }
            }
        }

        if (subNumber > exStock) {
            int usNumber = subNumber - exStock;
            ArrayList<String> skuIdList = CollectionUtil.arrayListString();
            for (int k = 0; k < usNumber; k++) {
                String subKey = "";
                double maxValue = Double.MAX_VALUE;

                for (String key : bigDecimalHashMap.keySet()) {
                    if (skuIdList.contains(key) || stockMap.get(key) == 0) {
                        continue;
                    }
                    Double compare = Double.valueOf(bigDecimalHashMap.get(key).toString());
                    if (maxValue > compare) {
                        maxValue = compare;
                        subKey = key;
                    }
                }
                Integer stock = stockMap.get(subKey);
                stockMap.put(subKey, stock - 1);
                skuIdList.add(subKey);
            }

            return;
        }

        exStock -= subNumber;
        if (exStock > 0) {
            for (String key : mapMap.keySet()) {
                Object hitRatio = mapMap.get(key).get("hitRatio");
                Object stock = mapMap.get(key).get("stock");
                if (Integer.valueOf(stock.toString()) <= 0 && !eliminateSkuIdList.contains(key)) {
                    eliminateSkuIdList.add(key);
                    hitRatioCount = hitRatioCount.subtract(new BigDecimal(hitRatio.toString()));
                }
            }
            getStock(exStock, hitRatioCount, mapMap, stockMap, countStockNumber, eliminateSkuIdList);
        }
    }

    // 各种状态下判断藏品是否可以展示
    public boolean getSkuAllStatusShow(GoblinGoodsSkuInfoVo info) {
        if (
                info != null
                        && info.getSkuType() == 1
                        && info.getStatus().equals("3")
                        && info.getShelvesStatus().equals("3")
                        // && (info.getSkuAppear() == null || info.getSkuAppear().equals("0"))
                        && info.getDelFlg().equals("0")
        ) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 整理map集合中存在空概率的值
     *
     * @param map,hitRatioCount
     */
    public void arrangeHitRatioMap(Map<String, BigDecimal> map, BigDecimal hitRatioCount) {

        // 定义最大概率
        BigDecimal maxHitRatio = new BigDecimal(100);

        // 剩余概率
        BigDecimal remainHitRatio = maxHitRatio.subtract(hitRatioCount);

        // 获取值为空的数量
        int number = 0;
        for (String key : map.keySet()) {
            if (map.get(key) == null) {
                number++;
            }
        }

        // 平均值
        BigDecimal averageNumber = remainHitRatio.divide(BigDecimal.valueOf(number), 2, BigDecimal.ROUND_DOWN);

        for (String key : map.keySet()) {
            if (map.get(key) == null) {
                map.put(key, averageNumber);
            }
        }
    }

    // 获取盲盒下藏品的库存 各种状态下不能算库存的排除掉
    public int getSkuAllStatusStock(GoblinGoodsSkuInfoVo info) {
        if (
                info != null
                        // && LocalDateTime.now().isAfter(info.getSaleStartTime())
                        && (null == info.getSoldoutStatus() || info.getSoldoutStatus().equals("0"))
                        && (null == info.getHitRatio() || info.getHitRatio().compareTo(BigDecimal.ZERO) > 0)
        ) {// 可以返回库存

            return (int)redisUtils.getSkuStock(null,info.getSkuId());
        } else {// 不计入库存
            return 0;
        }
    }
}
