package com.liquidnet.service.platform.service.impl.goblin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.StringUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinNftExCodeVo;
import com.liquidnet.service.goblin.dto.vo.GoblinNftExSkuVo;
import com.liquidnet.service.goblin.entity.*;
import com.liquidnet.service.goblin.mapper.*;
import com.liquidnet.service.goblin.param.GoblinNftExSkuParam;
import com.liquidnet.service.goblin.service.IGoblinNftExSkuService;
import com.liquidnet.service.platform.utils.GoblinRedisUtils;
import com.liquidnet.service.platform.utils.ObjectUtil;
import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Author: wll
 * @Description: nft兑换活动和和sku的关联
 * @Date:Create：in 2022/4/19 5:14 下午
 */

@Service
@Slf4j
public class GoblinNftExSkuServiceImpl implements IGoblinNftExSkuService {

    @Autowired
    private GoblinRedisUtils goblinRedisUtils;
    @Autowired
    private GoblinGoodsSkuMapper goblinGoodsSkuMapper;
    @Autowired
    GoblinNftExCodeTaskMapper goblinNftExCodeTaskMapper;
    @Autowired
    private GoblinNftExCodeTaskRelationMapper goblinNftExCodeTaskRelationMapper;


    @Transactional
    @Override
    public ResponseDto<Object> add(List<GoblinNftExSkuParam> goblinNftExSkuParams) {

        LocalDateTime now = LocalDateTime.now();

        //ArrayList<GoblinNftExSkuVo> goblinNftExSkuArrayList = ObjectUtil.getGoblinNftExSkuArrayList();
        //FArrayList<GoblinNftExCodeVo> goblinNftExCodeArrayList = ObjectUtil.getGoblinNftExCodeArrayList();


        Boolean bol = false;
        Integer stockNumber = 0;
        StringBuffer spuIds = new StringBuffer();
        StringBuffer skuIds = new StringBuffer();
        for (GoblinNftExSkuParam goblinNftExSkuParam : goblinNftExSkuParams) {
            if (goblinNftExSkuParam.getUnbox().equals("1")) {
                bol = true;
                spuIds.append(goblinNftExSkuParam.getSpuId()).append(",");
                break;
            }
            stockNumber += goblinNftExSkuParam.getExStock();
            skuIds.append(goblinNftExSkuParam.getSkuId()).append(",");
        }

        if (stockNumber <= 0) {
            return ResponseDto.failure("配置库存为0，无法生成!");
        }

        if (StringUtil.isBlank(skuIds)) {
            return ResponseDto.failure("sku数据不可传空!");
        }

        // 获取sku数据校验是否正确
        List<GoblinGoodsSku> goblinGoodsSkuListCheck = goblinGoodsSkuMapper.selectBySkuIds(skuIds.toString());

        List<String> skuIdList = new ArrayList<>();
        for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkuListCheck) {
            // 不能购买的 没库存的 概率是0的 过滤
            if (getSkuAllStatusShow(goblinGoodsSku)) {
                skuIdList.add(goblinGoodsSku.getSkuId());
            }
        }

        if (skuIdList.size() <= 0) {
            return ResponseDto.failure("当前选中的sku不处于可售卖状态!");
        }

        if (goblinGoodsSkuListCheck == null || (goblinGoodsSkuListCheck.size() != (bol ? goblinNftExSkuParams.size() - 1 : goblinNftExSkuParams.size()))) {
            return ResponseDto.failure("sku数据异常!");
        }


        Map<String, BigDecimal> map = new HashMap<>();
        if (bol) {
            // 获取spu下所有sku
            List<GoblinGoodsSku> goblinGoodsSkus = goblinGoodsSkuMapper.selectBySpuIds(spuIds.toString());
            for (GoblinGoodsSku goblinGoodsSku : goblinGoodsSkus) {
                if (goblinGoodsSku.getUnbox().equals("1")) {
                    continue;
                }
                // 不能购买的 没库存的 概率是0的 过滤
                if (getSkuAllStatusShow(goblinGoodsSku) && goblinRedisUtils.getSkuAllStatusStock(goblinGoodsSku) > 0 && goblinGoodsSku.getHitRatio() != null) {
                    map.put(goblinGoodsSku.getSkuId(), goblinGoodsSku.getHitRatio());
                }
            }
        }


        List<GoblinNftExCodeTask> goblinNftExCodeTasks = new ArrayList<>();
        // List<GoblinNftExCode> goblinNftExCodes = new ArrayList<>();

        // sku ---> 兑换码关联
        // Map<String, GoblinNftExSkuParam> goblinNftExSkuParamMap = new HashMap<>();

        // 构建对象
        for (GoblinNftExSkuParam goblinNftExSkuParam : goblinNftExSkuParams) {

            if (!goblinNftExSkuParam.getUnbox().equals("1") && !skuIdList.contains(goblinNftExSkuParam.getSkuId())) {
                continue;
            }

            // 定时任务对象构建
            GoblinNftExCodeTask goblinNftExCodeTask = GoblinNftExCodeTask.getNew();
            goblinNftExCodeTask.setTaskId(IDGenerator.nextSnowId());
            goblinNftExCodeTask.setActivityId(goblinNftExSkuParam.getActivityId());
            goblinNftExCodeTask.setStoreId(goblinNftExSkuParam.getStoreId());
            goblinNftExCodeTask.setSpuId(goblinNftExSkuParam.getSpuId());
            goblinNftExCodeTask.setSkuId(goblinNftExSkuParam.getSkuId());
            goblinNftExCodeTask.setUnbox(goblinNftExSkuParam.getUnbox());
            goblinNftExCodeTask.setExStock(goblinNftExSkuParam.getExStock());
            goblinNftExCodeTask.setExLimit(goblinNftExSkuParam.getExLimit());
            goblinNftExCodeTask.setExStartTime(goblinNftExSkuParam.getExStartTime());
            goblinNftExCodeTask.setExStopTime(goblinNftExSkuParam.getExStopTime());
            goblinNftExCodeTask.setTyp(1);
            goblinNftExCodeTask.setCreatedAt(now);
            if (goblinNftExSkuParam.getUnbox().equals("1")) {

                List<GoblinNftExCodeTaskRelation> goblinNftExCodeTaskRelations = new ArrayList<>();

                // sku ---> 库存
                Map<String, Integer> skuMap = getSkuHitRatio(goblinNftExSkuParam.getExStock(), map);

                if (skuMap.size() > 0) {
                    Integer sNumber = 0;
                    for (String key : skuMap.keySet()) {
                        Integer stockNum = skuMap.get(key);
                        // 根据sku减库存
                        int stock = goblinRedisUtils.decrSkuStock(null, key, stockNum);
                        if (stock < 0) {
                            goblinRedisUtils.incrSkuStock(null, key, stockNum);
                        } else {
                            GoblinNftExCodeTaskRelation goblinNftExCodeTaskRelation = new GoblinNftExCodeTaskRelation();
                            goblinNftExCodeTaskRelation.setTaskId(goblinNftExCodeTask.getTaskId());
                            goblinNftExCodeTaskRelation.setSkuId(key);
                            goblinNftExCodeTaskRelation.setStock(stockNum);
                            goblinNftExCodeTaskRelation.setCreatedAt(now);
                            goblinNftExCodeTaskRelations.add(goblinNftExCodeTaskRelation);
                        }
                        sNumber += stockNum;
                    }
                    goblinNftExCodeTaskRelationMapper.inserts(goblinNftExCodeTaskRelations);
                    goblinNftExCodeTask.setExStock(sNumber);
                }

            } else {
                int stock = goblinRedisUtils.decrSkuStock(null, goblinNftExSkuParam.getSkuId(), goblinNftExSkuParam.getExStock());
                if (stock < 0) {
                    goblinRedisUtils.incrSkuStock(null, goblinNftExSkuParam.getSkuId(), goblinNftExSkuParam.getExStock());
                }
            }

            goblinNftExCodeTasks.add(goblinNftExCodeTask);


            // 盲盒  概率
            /*switch (goblinNftExSkuParam.getUnbox()) {
                case "1":

                    // sku ---> 库存
                    Map<String, Integer> skuMap = getSkuHitRatio(goblinNftExSkuParam.getExStock(), map);

                    for (String key : skuMap.keySet()) {

                        Integer stockNum = skuMap.get(key);

                        // 根据sku减库存
                        int stock = goblinRedisUtils.decrSkuStock(null, key, stockNum);
                        if (stock < 0) {
                            goblinRedisUtils.incrSkuStock(null, key, stockNum);
                        } else {
                            for (int i = 0; i < stockNum; i++) {
                                GoblinNftExCode goblinNftExCode = GoblinNftExCode.getNew();
                                goblinNftExCode.setCodeId(IDGenerator.nextSnowId());
                                goblinNftExCode.setActivityId(goblinNftExSkuParam.getActivityId());

                                // 获取兑换码ZA
                                // 样例 2978-6496-9269-0694-XX
                                String code = IDGenerator.createCode(3, 4, true);
                                goblinNftExCode.setCode(code);
                                goblinNftExCode.setBoxSkuId(key);
                                goblinNftExCode.setState(1);
                                goblinNftExCode.setCreatedAt(now);
                                goblinNftExCodes.add(goblinNftExCode);

                                GoblinNftExCodeVo goblinNftExCodeVo = GoblinNftExCodeVo.getNew().copy(goblinNftExCode);

                                // 赋值额外属性
                                goblinNftExCodeVo.setExLimit(goblinNftExSkuParam.getExLimit());
                                goblinNftExCodeVo.setExStartTime(goblinNftExSkuParam.getExStartTime());
                                goblinNftExCodeVo.setExStopTime(goblinNftExSkuParam.getExStopTime());
                                goblinNftExCodeVo.setStoreId(goblinNftExSkuParam.getStoreId());
                                goblinNftExCodeVo.setSpuId(goblinNftExSkuParam.getSpuId());

                                // LocalDateTime exStartTime = goblinNftExSkuParam.getExStartTime();
                                LocalDateTime exStopTime = goblinNftExSkuParam.getExStopTime();

                                // 时间差  以秒表示
                                long millisNum = Duration.between(LocalDateTime.now(), exStopTime).toMillis();

                                // redis 存储
                                goblinRedisUtils.addCode(code, goblinNftExCodeVo, millisNum);

                                goblinNftExCode.setSkuId(goblinNftExSkuParam.getSkuId());
                            }
                            // goblinNftExSkuParamMap.put(key, goblinNftExSkuParam);
                        }

                    }

                    break;
                default:

                    // 根据sku减库存
                    int stock = goblinRedisUtils.decrSkuStock(null, goblinNftExSkuParam.getSkuId(), goblinNftExSkuParam.getExStock());
                    if (stock < 0) {
                        goblinRedisUtils.incrSkuStock(null, goblinNftExSkuParam.getSkuId(), goblinNftExSkuParam.getExStock());
                    } else {
                        // 构建兑换码数量
                        for (int i = 0; i < goblinNftExSkuParam.getExStock(); i++) {
                            GoblinNftExCode goblinNftExCode = GoblinNftExCode.getNew();
                            goblinNftExCode.setCodeId(IDGenerator.nextSnowId());
                            goblinNftExCode.setActivityId(goblinNftExSkuParam.getActivityId());

                            // 获取兑换码ZA
                            // 样例 2978-6496-9269-0694-XX
                            String code = IDGenerator.createCode(3, 4, true);
                            goblinNftExCode.setCode(code);
                            goblinNftExCode.setSkuId(goblinNftExSkuParam.getSkuId());
                            goblinNftExCode.setState(1);
                            goblinNftExCode.setCreatedAt(now);
                            goblinNftExCodes.add(goblinNftExCode);

                            GoblinNftExCodeVo goblinNftExCodeVo = GoblinNftExCodeVo.getNew().copy(goblinNftExCode);

                            // 赋值额外属性
                            goblinNftExCodeVo.setStoreId(goblinNftExSkuParam.getStoreId());
                            goblinNftExCodeVo.setExLimit(goblinNftExSkuParam.getExLimit());
                            goblinNftExCodeVo.setExStartTime(goblinNftExSkuParam.getExStartTime());
                            goblinNftExCodeVo.setExStopTime(goblinNftExSkuParam.getExStopTime());
                            goblinNftExCodeVo.setSpuId(goblinNftExSkuParam.getSpuId());
                            // LocalDateTime exStartTime = goblinNftExSkuParam.getExStartTime();
                            LocalDateTime exStopTime = goblinNftExSkuParam.getExStopTime();

                            // 时间差  以秒表示
                            long millisNum = Duration.between(LocalDateTime.now(), exStopTime).toMillis();

                            // redis 存储
                            goblinRedisUtils.addCode(code, goblinNftExCodeVo, millisNum);
                            // goblinNftExCodeArrayList.add(GoblinNftExCodeVo.getNew().copy(goblinNftExCode));
                        }

                        GoblinNftExSkuParam value = goblinNftExSkuParamMap.get(goblinNftExSkuParam.getSkuId());
                        if (value == null) {
                            goblinNftExSkuParamMap.put(goblinNftExSkuParam.getSkuId(), goblinNftExSkuParam);
                        }

                    }


                    // goblinNftExSkuArrayList.add(GoblinNftExSkuVo.getNew().copy(goblinNftExSku));
            }*/


        }


        /*
        for (String key : goblinNftExSkuParamMap.keySet()) {
            GoblinNftExSkuVo goblinNftExSkuVo = goblinRedisUtils.getSkuTime(key);

            GoblinNftExSkuParam goblinNftExSkuParam = goblinNftExSkuParamMap.get(key);

            LocalDateTime exStartTime = goblinNftExSkuParam.getExStartTime(); // "2022-06-26 19:00:00";
            LocalDateTime exStopTime = goblinNftExSkuParam.getExStopTime(); // "2024-06-26 19:00:00";

            if (!StringUtil.isEmpty(goblinNftExSkuVo)) {
                // redis存储 单个sku的开始和结束时间
                LocalDateTime rdExStartTime = LocalDateTime.parse(goblinNftExSkuVo.getRdStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // "2019-06-26 19:00:00";
                LocalDateTime rdExStopTime = LocalDateTime.parse(goblinNftExSkuVo.getRdStopTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // "2019-06-26 19:00:00";


                // 时间比对
                if (!rdExStartTime.isAfter(exStartTime)) {
                    exStartTime = rdExStartTime;
                }

                if (rdExStopTime.isAfter(exStopTime)) {
                    exStopTime = rdExStopTime;
                }
            }

            GoblinNftExSkuVo goblinNftExSku = GoblinNftExSkuVo.getNew();
            goblinNftExSku.setExStartTime(exStartTime);
            goblinNftExSku.setExStopTime(exStopTime);
            goblinNftExSku.setRdStartTime(exStartTime.toString());
            goblinNftExSku.setRdStopTime(exStopTime.toString());

            goblinRedisUtils.addSkuTime(key, goblinNftExSku);
        }
*/


        // 数据库操作
        long startm = System.currentTimeMillis();
        if (goblinNftExCodeTasks.size() > 0) {
            goblinNftExCodeTaskMapper.addGoblinNftExCodeTasks(goblinNftExCodeTasks);
        }
        // goblinNftExCodeMapper.addGoblinNftExCodes(goblinNftExCodes);
        log.debug("MSQ耗时：ms", System.currentTimeMillis() - startm);

        return ResponseDto.success(true);
    }

    /**
     * 获取每个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
     */
    private  Map<String, Integer> getSkuHitRatio(Integer exStock, Map<String, BigDecimal> map) {

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

        // sku --> 概率/库存
        Map<String, Map<String, Object>> mapMap = new HashMap<>();

        int j = 0;
        for (String key : map.keySet()) {
            BigDecimal skuHitRatio = map.get(key);
            Map<String, Object> objectMap = new HashMap<>();
            if (skuHitRatio == null) {
                continue;
            }
            hitRatioCount = hitRatioCount.add(skuHitRatio);
            objectMap.put("hitRatio", skuHitRatio);
            objectMap.put("stock", goblinRedisUtils.getSkuStock(key));
            mapMap.put(key, objectMap);
            j += 100;
        }

        // sku ---> 库存
        Map<String, Integer> stockMap = new HashMap<>();
        getStock(exStock, hitRatioCount, mapMap, stockMap);
        return stockMap;
    }

    /**
     * 获取单个sku库存
     *
     * @param exStock
     * @param hitRatioCount
     * @param mapMap
     * @return
     */
    private  void getStock(Integer exStock, BigDecimal hitRatioCount, Map<String, Map<String, Object>> mapMap, Map<String, Integer> stockMap) {
        if (exStock < 0) {
            return;
        }
        for (String key : mapMap.keySet()) {
            Object stock = mapMap.get(key).get("stock");
            Object hitRatio = mapMap.get(key).get("hitRatio");
            // 要减去的库存
            int subStock = BigDecimal.valueOf(exStock).multiply((new BigDecimal(hitRatio.toString()).divide(hitRatioCount, 2, BigDecimal.ROUND_HALF_UP))).setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
            if (subStock > Integer.valueOf(stock.toString())) {
                exStock = exStock - 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 {
                exStock = exStock - subStock;
                if (stockMap.get(key) == null) {
                    stockMap.put(key, subStock);
                } else {
                    stockMap.put(key, stockMap.get(key) + subStock);
                }
            }
        }
        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) {

                }
                hitRatioCount.subtract(new BigDecimal(hitRatio.toString()));
            }
            getStock(exStock, hitRatioCount, mapMap, stockMap);
        }
    }


    // 各种状态下判断藏品是否可以展示
    public boolean getSkuAllStatusShow(GoblinGoodsSku 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;
        }
    }


}
