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

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.constant.GoblinRedisConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.param.GoblinMixDetailsItemParam;
import com.liquidnet.service.goblin.param.GoblinMixDetailsParam;
import com.liquidnet.service.goblin.param.GoblinMixUpdateParam;
import com.liquidnet.service.goblin.service.manage.IGoblinMixService;
import com.liquidnet.service.goblin.util.*;
import io.github.classgraph.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS;

/**
 * <p>
 * 商城-名单表 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2022-04-29
 */
@Service
@Slf4j
public class GoblinMixServiceImpl implements IGoblinMixService {

    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils mongoUtils;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinNftBoxUtils nftBoxUtils;


    @Override
    public ResponseDto<PageInfo<GoblinMixManageListVo>> mixList(String mixName, Integer page) {
        PageInfo<GoblinMixManageListVo> pageResult;
        HashMap<String, Object> map = mongoUtils.getGoblinMixListVo(mixName, CurrentUtil.getCurrentUid(), page);
        List<GoblinMixDetailsVo> detailsVoList = (List<GoblinMixDetailsVo>) map.get("data");
        List<GoblinMixManageListVo> voList = ObjectUtil.goblinMixManageListVo();
        for (GoblinMixDetailsVo item : detailsVoList) {
            GoblinMixManageListVo vo = GoblinMixManageListVo.getNew();
            vo.setMixId(item.getMixId());
            vo.setName(item.getName());
            vo.setTimeEnd(item.getTimeEnd());
            vo.setTimeStart(item.getTimeStart());
            vo.setCreatedAt(item.getCreatedAt());

            LocalDateTime st = LocalDateTime.parse(item.getTimeStart(), DTF_YMD_HMS);
            LocalDateTime et = LocalDateTime.parse(item.getTimeEnd(), DTF_YMD_HMS);
            LocalDateTime nt = LocalDateTime.now();
            if (item.getStatus() == 7) {
                vo.setStatus(7);
            } else {
                if (nt.isAfter(et)) {
                    vo.setStatus(10);
                } else if (nt.isBefore(st)) {
                    vo.setStatus(9);
                } else {
                    vo.setStatus(6);
                }
            }
            int stock = 0;
            for (GoblinMixDetailsItemVo itemVo : item.getItem()) {
                GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(itemVo.getSkuId());
                if (skuInfoVo.getUnbox().equals(1)) {
                    List<String> skuIds = redisUtils.getGoblinMixRelationBox(itemVo.getSkuId(), item.getMixId());
                    for (String skuId : skuIds) {
                        stock += redisUtils.getSkuStock(item.getMixId(), skuId);
                    }
                } else {
                    stock += redisUtils.getSkuStock(item.getMixId(), itemVo.getSkuId());
                }
            }
            vo.setRestStock(stock);
            voList.add(vo);
        }
        pageResult = new PageInfo(voList);
        pageResult.setTotal((Long) map.get("total"));
        return ResponseDto.success(pageResult);
    }

    @Override
    public ResponseDto<GoblinMixDetailsVo> mixDetails(String mixId) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinMixDetailsVo vo = redisUtils.getMixDetails(mixId);
        if (!vo.getUserId().equals(uid)) {
            return ResponseDto.failure("身份异常");
        }
        for (GoblinMixDetailsItemVo item : vo.getItem()) {
            GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(item.getSkuId());
            item.setSkuName(skuInfoVo.getName());
            item.setSkuPrice(skuInfoVo.getPrice());
            item.setStock(skuInfoVo.getSkuStock());
            item.setSurplusStock(redisUtils.getSkuStock(mixId, item.getSkuId()));
        }
        return ResponseDto.success(vo);
    }

    @Override
    public ResponseDto<String> mixInsert(GoblinMixDetailsParam param) {
        String mixId = IDGenerator.nextTimeId2();
        String uid = CurrentUtil.getCurrentUid();
        List<GoblinMixDetailsItemVo> itemList = ObjectUtil.goblinMixDetailsItemVo();
        List<GoblinMixDetailsItemParam> itemParams = param.getItem();

        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_mix_insert"));
        sqls.add(SqlMapping.get("goblin_mix_details_insert"));
        LinkedList<Object[]> goblinMix = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> goblinMixDetails = CollectionUtil.linkedListObjectArr();

        if (param.getWhiteType() == 1 && (null == param.getWhiteUrl() || "".equals(param.getWhiteUrl()))) {
            return ResponseDto.failure("未上床指定文件");
        }

        //校验库存
        List<String> errorNameList = initStock(itemParams, mixId, param.getStock());
        if (errorNameList.size() > 0) {
            return ResponseDto.failure(JSON.toJSONString(errorNameList));
        }

        //处理vo
        BigDecimal price = BigDecimal.ZERO;
        BigDecimal sellPrice = BigDecimal.ZERO;
        for (GoblinMixDetailsItemParam itemParam : itemParams) {
            GoblinMixDetailsItemVo itemVo = GoblinMixDetailsItemVo.getNew().copyByInsert(itemParam);
            itemList.add(itemVo);
            sellPrice.add(itemVo.getPrice());
            price.add(itemVo.getSkuPrice());
            goblinMixDetails.add(new Object[]{
                    mixId, itemVo.getPosition(), itemVo.getSpuId(), itemVo.getSkuId(), itemVo.getPrice(), itemVo.getPriceV(),
                    itemVo.getProductId(), itemVo.getCount(), LocalDateTime.now()
            });
            //白名单
//            if (param.getWhiteType() == 1) {
//                queueUtils.sendMsgByRedisXls(mixId, param.getWhiteUrl(), "", "3", itemVo.getSkuId());
//            }
        }
        GoblinMixDetailsVo vo = GoblinMixDetailsVo.getNew().copyByInsert(mixId, param, itemList, uid, sellPrice, price);
        goblinMix.add(new Object[]{
                mixId, uid, vo.getName(), vo.getTimeStart(), vo.getTimeEnd(), 6, vo.getShowPosition(),
                vo.getSellName(), vo.getExpressPrice(), vo.getIntro(), vo.getWatchType(), vo.getCoverPic(),
                vo.getVideo(), vo.getDetailUrl(), vo.getDetails(), vo.getStock(), vo.getStockLock(),
                vo.getIsLock(), vo.getLimit(), vo.getWhiteType(), vo.getWhiteUrl(), vo.getPayType(), LocalDateTime.now()
        });
        //设置redis
        redisUtils.setMixDetails(mixId, vo);
        redisList(vo.getShowPosition(), vo.getMixId(), vo.getStatus());
        if (param.getWhiteType() == 1) {
            queueUtils.sendMsgByRedisXls(mixId, param.getWhiteUrl(), "", "3", mixId);
        }
        //设置mongo
        mongoUtils.setGoblinMixDetailsVo(vo);
        //设置mysql
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(), SqlMapping.gets(sqls, goblinMix, goblinMixDetails));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> mixUpdate(GoblinMixUpdateParam param) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinMixDetailsVo vo = redisUtils.getMixDetails(param.getMixId());
        if (!vo.getUserId().equals(uid)) {
            return ResponseDto.failure("身份异常");
        }

        if (param.getWhiteType() == 1 && (null == param.getWhiteUrl() || "".equals(param.getWhiteUrl()))) {
            return ResponseDto.failure("未上床指定文件");
        }

        for (GoblinMixDetailsItemVo itemVo : vo.getItem()) {
            //白名单
//            if (param.getWhiteType() == 1) {
//                queueUtils.sendMsgByRedisXls(param.getMixId(), param.getWhiteUrl(), vo.getWhiteUrl(), "3", param.getMixId());
//            }
        }

        vo.setShowPosition(param.getShowPosition());
        vo.setLimit(param.getLimit());
        vo.setWhiteType(param.getWhiteType());
        vo.setWhiteUrl(param.getWhiteUrl());
        vo.setXlsName(param.getXlsName());
        //redis
        redisUtils.setMixDetails(param.getMixId(), vo);
        if (param.getWhiteType() == 1) {
            queueUtils.sendMsgByRedisXls(param.getMixId(), param.getWhiteUrl(), vo.getWhiteUrl(), "3", param.getMixId());
        }
        //mongo
        mongoUtils.changeGoblinMixDetailsVo(vo);
        //sql入库
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(),
                SqlMapping.get("goblin_mix_update", vo.getShowPosition(), vo.getLimit(), vo.getWhiteType(), vo.getWhiteUrl(), LocalDateTime.now(), param.getMixId()));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> mixLine(String mixId, Integer status) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinMixDetailsVo vo = redisUtils.getMixDetails(mixId);
        if (!vo.getUserId().equals(uid)) {
            return ResponseDto.failure("身份异常");
        }
        vo.setStatus(status);
        //redis
        redisUtils.setMixDetails(mixId, vo);
        redisList(vo.getShowPosition(), mixId, vo.getStatus());
        //mongo
        mongoUtils.changeGoblinMixDetailsVo(vo);
        //sql入库
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(),
                SqlMapping.get("goblin_mix_status_update", status, LocalDateTime.now(), mixId));
        return ResponseDto.success();
    }

    //库存管理
    private List<String> initStock(List<GoblinMixDetailsItemParam> data, String mixId, int stock) {
        List<String> errorNameList = CollectionUtil.linkedListString();//库存异常的 sku名称
        List<String> sucSkuId = CollectionUtil.linkedListString();//库存成功的skuId
        for (GoblinMixDetailsItemParam item : data) {
            String skuId = item.getSkuId();
            GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(skuId);
            if (skuInfoVo.getSkuType() == 1 && "1".equals(skuInfoVo.getUnbox())) { //盲盒
                HashMap<String, BigDecimal> map = CollectionUtil.mapStringBigDecimal();
                GoblinGoodsInfoVo spuInfoVo = redisUtils.getGoodsInfoVo(item.getSpuId());
                // 是否存在概率为空
                boolean isHit = false;
                BigDecimal hitRatioCount = new BigDecimal(0);
                for (String itemSkuId : spuInfoVo.getSkuIdList()) {
                    GoblinGoodsSkuInfoVo skuItemVo = redisUtils.getGoodsSkuInfoVo(itemSkuId);
                    if (skuItemVo.getUnbox().equals("1")) {
                        continue;
                    }
                    //是否购买
                    if (!skuItemVo.getSkuCanbuy().equals("1")) {
                        continue;
                    }

                    if (nftBoxUtils.getSkuAllStatusShow(skuItemVo) && nftBoxUtils.getSkuAllStatusStock(skuItemVo) > 0) {
                        if (skuItemVo.getHitRatio() == null) {
                            isHit = true;
                        } else {
                            hitRatioCount = hitRatioCount.add(skuItemVo.getHitRatio());
                        }
                        map.put(skuItemVo.getSkuId(), skuItemVo.getHitRatio());
                    }
                }
                if (isHit && hitRatioCount.doubleValue() < 100.00 && map.size() > 0) {
                    nftBoxUtils.arrangeHitRatioMap(map, hitRatioCount);
                }
                Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(stock * item.getCount(), map);
                for (String key : skuMap.keySet()) {
                    Integer stockNum = skuMap.get(key);
                    //库存
                    int skuStock = redisUtils.decrSkuStock(null, key, stockNum);
                    log.info("盲盒库存 SKUID = " + key + " 数量 = " + stockNum);
                    if (skuStock < 0) {
                        redisUtils.incrSkuStock(null, key, stockNum);
                        errorNameList.add("盲盒" + item.getSkuName());
                    } else {
                        redisUtils.setSkuStock(mixId, key, stockNum);
                        redisUtils.addGoblinMixRelationBox(skuId, mixId, key);
                        sucSkuId.add(key);
                    }
                }
            } else {
                //库存
                int skuStock = redisUtils.decrSkuStock(null, skuId, stock * item.getCount());
                if (skuStock < 0) {
                    redisUtils.incrSkuStock(null, skuId, stock * item.getCount());
                    errorNameList.add(item.getSkuName());
                } else {
                    redisUtils.setSkuStock(mixId, skuId, stock * item.getCount());
                    sucSkuId.add(skuId);
                }
            }//普通商品
        }

        if (errorNameList.size() > 0) {
            for (String skuId : sucSkuId) {
                redisUtils.decrSkuStock(mixId, skuId, stock);
                redisUtils.incrSkuStock(null, skuId, stock);
            }
        }

        return errorNameList;
    }

    //列表
    private boolean redisList(Integer showPosition, String mixId, Integer status) {
        if (showPosition == 1) {//商品
            if (status == 6) {
                redisUtils.addGoblinMixSkuList(mixId);
            } else if (status == 7) {
                redisUtils.removeGoblinMixSkuList(mixId);
            }
        } else if (showPosition == 2) {//nft
            if (status == 6) {
                redisUtils.addGoblinMixNftList(mixId);
            } else if (status == 7) {
                redisUtils.removeGoblinMixNftList(mixId);
            }
        }
        return true;
    }
}
