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.DateUtil;
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;
    @Autowired
    GoblinOrderUtils goblinOrderUtils;


    @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.setSkuPic(skuInfoVo.getSkuPic());
            item.setStock(vo.getStock() * item.getCount());
            if (skuInfoVo.getUnbox().equals("1")) {
                List<String> skuIds = redisUtils.getGoblinMixRelationBox(skuInfoVo.getSkuId(), mixId);
                int stock = 0;
                for (String skuId : skuIds) {
                    stock += redisUtils.getSkuStock(mixId, skuId);
                }
                item.setSurplusStock(stock);

                GoblinGoodsInfoVo spuVo = redisUtils.getGoodsInfoVo(skuInfoVo.getSpuId());
                int skuSurplusStock = 0;
                int skuStock = 0;
                for (String skuIdItem : spuVo.getSkuIdList()) {// 盲盒计算所有sku库存总数
                    if (skuIdItem.equals(skuInfoVo.getSkuId())) {// 过滤自己
                        continue;
                    }
                    GoblinGoodsSkuInfoVo itemVo = redisUtils.getGoodsSkuInfoVo(skuIdItem);
                    skuSurplusStock += redisUtils.getSkuAllStatusStockType1(itemVo);
                    skuStock += redisUtils.getSkuTotalStockShelvesStatus3(itemVo);
                }
                item.setSkuStock(skuStock);
                item.setSkuSurplusStock(skuSurplusStock);
            } else {
                item.setSurplusStock(redisUtils.getSkuStock(mixId, item.getSkuId()));
                item.setSkuStock(skuInfoVo.getSkuStock());
                item.setSkuSurplusStock(redisUtils.getSkuStock(null, 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();
        //开启预约 判断上架时间必须大于开始时间
        if (DateUtil.compareStrDay(param.getShelvesTime(), param.getTimeStart()) >= 0) {
            return ResponseDto.failure("上架时间必须小于开始时间！");
        }

        //判断活动名称
        int count = (int) mongoUtils.getMixNameCount(param.getName());
        if (count > 0) {
            return ResponseDto.failure("活动名称重复");
        }

        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);
            sellPrice = sellPrice.add(itemVo.getPrice());
            price = price.add(itemVo.getSkuPrice().multiply(BigDecimal.valueOf(itemParam.getCount())));
            itemList.add(itemVo);
            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(), vo.getStoreId(), LocalDateTime.now(), vo.getShelvesTime(), vo.getReserve()
        });
        //设置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());
        String oldWhiteUrl = vo.getWhiteUrl();
        //开启预约 判断上架时间必须大于开始时间
        if (DateUtil.compareStrDay(param.getShelvesTime(), vo.getTimeStart()) >= 0) {
            return ResponseDto.failure("上架时间必须小于开始时间！");
        }

        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());
        vo.setShelvesTime(param.getShelvesTime());
        vo.setReserve(param.getReserve());
        //redis
        redisUtils.setMixDetails(param.getMixId(), vo);
        redisList(vo.getShowPosition(), vo.getMixId(), vo.getStatus());
        if (param.getWhiteType() == 1) {
            queueUtils.sendMsgByRedisXls(param.getMixId(), param.getWhiteUrl(), oldWhiteUrl, "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(), vo.getShelvesTime(), vo.getReserve(), 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();
    }

    @Override
    public ResponseDto<Boolean> nameCount(String name) {
        //判断活动名称
        int count = (int) mongoUtils.getMixNameCount(name);
        if (count > 0) {
            return ResponseDto.success(true);
        } else {
            return ResponseDto.success(false);
        }
    }

    //库存管理
    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);
                if (skuMap.size() == 0) {
                    errorNameList.add(item.getSkuName() + " 库存不足");
                } else {
                    int boxStock = 0;
                    List<String> boxSkuId = CollectionUtil.linkedListString();
                    for (String key : skuMap.keySet()) {
                        Integer stockNum = skuMap.get(key);
                        if (stockNum == 0) {
                            continue;
                        }
                        //库存
                        int skuStock = redisUtils.decrSkuStock(null, key, stockNum);
                        log.info("盲盒库存 SKUID = " + key + " 数量 = " + stockNum);
                        boxStock += stockNum;
                        if (skuStock < 0) {
                            redisUtils.incrSkuStock(null, key, stockNum);
                            errorNameList.add("盲盒 " + item.getSkuName() + " 库存不足");
                        } else {
                            boxSkuId.add(key + "," + stockNum);
                            redisUtils.setSkuStock(mixId, key, stockNum);
                            redisUtils.addGoblinMixRelationBox(skuId, mixId, key);
                            log.debug("id = " + redisUtils.getGoblinMixRelationBox(skuId, mixId));
                            sucSkuId.add(key + "," + stockNum);
                        }
                    }

                    if (boxStock < stock * item.getCount()) {
                        errorNameList.add("盲盒 " + item.getSkuName() + " 库存不足");
//                        for (String temp : boxSkuId) {
//                            String id = temp.split(",")[0];
//                            int count = Integer.parseInt(temp.split(",")[1]);
//                            redisUtils.incrSkuStock(null, id, count);
//                            redisUtils.decrSkuStock(mixId, id, count);
//                        }
                    }
                }
            } 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 + "," + stock * item.getCount());
                }
            }//普通商品
        }

        if (errorNameList.size() > 0) {
            for (String skuId : sucSkuId) {
                String id = skuId.split(",")[0];
                int count = Integer.parseInt(skuId.split(",")[1]);
                redisUtils.decrSkuStock(mixId, id, count);
                redisUtils.incrSkuStock(null, id, count);
            }
        }

        return errorNameList;
    }

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