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

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.PagedResult;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.param.GoblinListCreateItemParam;
import com.liquidnet.service.goblin.param.GoblinListCreateParam;
import com.liquidnet.service.goblin.param.GoblinListUpdateParam;
import com.liquidnet.service.goblin.service.manage.IGoblinListService;
import com.liquidnet.service.goblin.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

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

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

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

    @Override
    public ResponseDto<PageInfo<GoblinListVo>> getList(String name, Integer page) {
        PageInfo<GoblinListVo> pageResult;
        HashMap<String, Object> map = mongoUtils.getGoblinListVo(name, CurrentUtil.getCurrentUid(), page);
        List<GoblinListDetailsVo> detailsVoList = (List<GoblinListDetailsVo>) map.get("data");
        List<GoblinListVo> voList = ObjectUtil.getGoblinListVo();
        for (GoblinListDetailsVo item : detailsVoList) {
            GoblinListVo vo = GoblinListVo.getNew();
            vo.setListId(item.getListId());
            vo.setName(item.getName());
            vo.setTimeStart(item.getTimeStart());
            vo.setTimeEnd(item.getTimeEnd());
            vo.setSkuCount(item.getItemVo().size());
            vo.setHasBlack(item.getBlackUrl().equals("") ? 0 : 1);
            voList.add(vo);
        }
        pageResult = new PageInfo(voList);
        pageResult.setTotal((Long) map.get("total"));
        return ResponseDto.success(pageResult);
    }

    @Override
    public ResponseDto<GoblinListDetailsVo> getDetails(String listId) {
        GoblinListDetailsVo vo = redisUtils.getGoblinListDetailsVo(listId);
        if (vo == null || !vo.getUid().equals(CurrentUtil.getCurrentUid())) {
            return ResponseDto.failure("信息错误");
        }
        for (GoblinListDetailsItemVo item : vo.getItemVo()) {
            GoblinGoodsSkuInfoVo skuVo = redisUtils.getGoodsSkuInfoVo(item.getSkuId());
            item.setSkuName(skuVo.getName());
            if (skuVo.getUnbox().equals("1")) {
                int stock = 0;
                ArrayList<String> skuIdList = redisUtils.getGoblinListRelationBox(skuVo.getSkuId(), vo.getListId());
                for (String relationSkuId : skuIdList) {
                    stock += redisUtils.getSkuStock(listId, relationSkuId);
                }
                item.setSurplusStock(stock);
            } else {
                item.setSurplusStock(redisUtils.getSkuStock(listId, skuVo.getSkuId()));
            }
//            if (skuVo.getUnbox().equals("0")) {
//                item.setSurplusStock(redisUtils.getSkuStock(null, item.getSkuId()));
//                item.setStock(skuVo.getSkuStock());
//            } else {
//                List<String> skuIdList = redisUtils.getGoodsInfoVo(item.getSpuId()).getSkuIdList();
//                int surplusStock = 0;
//                int stock = 0;
//                for (String skuIdItem : skuIdList) {// 盲盒计算所有sku库存总数
//                    if (skuIdItem.equals(item.getSkuId())) {// 过滤自己
//                        stock += skuVo.getSkuStock();
//                        continue;
//                    }
//                    GoblinGoodsSkuInfoVo itemVo = redisUtils.getGoodsSkuInfoVo(skuIdItem);
//                    surplusStock += redisUtils.getSkuAllStatusStock(itemVo);
//                    stock += itemVo.getSkuStock();
//                }
//                item.setSurplusStock(surplusStock);
//                item.setStock(stock);
//            }
        }
        return ResponseDto.success(vo);
    }

    @Override
    public ResponseDto<Boolean> create(GoblinListCreateParam param) {
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        sqls.add(SqlMapping.get("goblin_list_insert"));
        sqls.add(SqlMapping.get("goblin_list_detail_insert"));
        LinkedList<Object[]> goblinList = CollectionUtil.linkedListObjectArr();
        LinkedList<Object[]> goblinListDetails = CollectionUtil.linkedListObjectArr();
        LocalDateTime now = LocalDateTime.now();

        //时间
        if (param.getItemParams().size() > 1) {
            return ResponseDto.failure("只能配置一个sku");
        }
        //判断重名
        if (mongoUtils.hasGoblinListDetailsVoByName(param.getName())) {
            return ResponseDto.failure("活动名称重复");
        }
        String skuId = param.getItemParams().get(0).getSkuId();
        GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(skuId);
        LocalDateTime st = LocalDateTime.parse(param.getTimeStart(), DTF_YMD_HMS);
        LocalDateTime et = null;
        List<GoblinListCollectVo> collectVos;
        if (param.getTimeEnd() != null) {//传结束时间
            et = LocalDateTime.parse(param.getTimeEnd(), DTF_YMD_HMS);
            if (st.isAfter(et)) {
                return ResponseDto.failure("开始时间不能晚于结束时间");
            }
            if (et.isAfter(skuInfoVo.getSaleStartTime().minusSeconds(1))) {
                return ResponseDto.failure("结束时间不能晚于商品开售时间");
            }
            collectVos = redisUtils.getGoblinListCollect(skuId);

            boolean isSame = judgeTime(st, et, collectVos);
            if (isSame) {
                return ResponseDto.failure("sku时间不能重合");
            }
            for (GoblinListCollectVo collectItem : collectVos) {
                if (collectItem.getTimeEnd() != null) {
                    if ((st.isAfter(collectItem.getTimeStart()) && st.isBefore(collectItem.getTimeEnd())) ||
                            (et.isAfter(collectItem.getTimeStart()) && et.isBefore(collectItem.getTimeEnd())) ||
                            (st.isBefore(collectItem.getTimeStart()) && et.isAfter(collectItem.getTimeEnd()))
                    ) {//开始时间不能在其他时间段内/结束间不能在其他时间段内/开始结束时间不能包含其他时间段
                        return ResponseDto.failure("sku时间不能重合");
                    }
                } else {
                    if (st.isBefore(collectItem.getTimeStart()) && et.isAfter(collectItem.getTimeStart())) {
                        return ResponseDto.failure("sku时间不能重合");//开始结束时间不能包含只有开始时间的时间段
                    }
                }
            }
        } else {//未结束时间
            if (st.isAfter(skuInfoVo.getSaleStartTime())) {
                return ResponseDto.failure("结束时间不能晚于商品开售时间");
            }
            collectVos = redisUtils.getGoblinListCollect(skuId);
            for (GoblinListCollectVo collectItem : collectVos) {
                if (collectItem.getTimeEnd() != null) {
                    if (st.isAfter(collectItem.getTimeStart().minusSeconds(1)) && st.isBefore(collectItem.getTimeEnd().plusSeconds(1))) {
                        return ResponseDto.failure("sku时间不能重合");
                    }
                } else {
                }
            }
        }

        GoblinListDetailsVo vo = GoblinListDetailsVo.getNew();
        List<GoblinListDetailsItemVo> voItemList = ObjectUtil.goblinListDetailsItemVoArrayList();
        vo.setListId(IDGenerator.nextTimeId2());
        vo.setUid(CurrentUtil.getCurrentUid());
        vo.setName(param.getName());
        vo.setTagType(param.getTagType());
        vo.setTimeStart(param.getTimeStart());
        vo.setTimeEnd(param.getTimeEnd());
        vo.setWhiteType(param.getWhiteType());
        vo.setCreatedAt(DateUtil.format(now, DateUtil.Formatter.yyyyMMddHHmmss));
        //判断 白名单类型
        if (param.getWhiteType().equals(1)) {//需要xls文件
//            if (param.getWhiteUrl() == null || param.getWhiteUrl().equals("")) {
//                return ResponseDto.failure("未上传指定用户文件");
//            }
            vo.setWhiteUrl(param.getWhiteUrl());
            vo.setWhiteName(param.getWhiteName());
        } else {//不需要xls文件
            vo.setWhiteUrl("");
            vo.setWhiteName("");
        }
        vo.setBlackName(param.getBlackName() == null ? "" : param.getBlackName());
        vo.setBlackUrl(param.getBlackUrl() == null ? "" : param.getBlackUrl());
        for (GoblinListCreateItemParam item : param.getItemParams()) {
            GoblinListDetailsItemVo itemVo = GoblinListDetailsItemVo.getNew();
            itemVo.setSkuId(item.getSkuId());
            itemVo.setSpuId(item.getSpuId());
            itemVo.setPrice(item.getPrice());
            itemVo.setPriceV(item.getPriceV());
            itemVo.setSkuStock(item.getSkuStock());
            itemVo.setProductId(item.getProductId());
            voItemList.add(itemVo);
            if (skuInfoVo.getUnbox().equals("1")) {//盲盒逻辑
                //计算盲盒对应sku数量
                HashMap<String, BigDecimal> map = CollectionUtil.mapStringBigDecimal();
                GoblinGoodsInfoVo spuInfoVo = redisUtils.getGoodsInfoVo(item.getSpuId());
//                int countStockNumber = 0;
//                int checkNumberSku = 0;
                // 是否存在概率为空
                boolean isHit = false;
                // 概率相加
                BigDecimal hitRatioCount = new BigDecimal(0);
                for (String itemSkuId : spuInfoVo.getSkuIdList()) {
                    GoblinGoodsSkuInfoVo skuItemVo = redisUtils.getGoodsSkuInfoVo(itemSkuId);
                    if (skuItemVo.getUnbox().equals("1")) {
                        continue;
                    }

//                    // 判断开售、停售时间
//                    LocalDateTime saleStartTime = skuItemVo.getSaleStartTime();
//                    LocalDateTime saleStopTime = skuItemVo.getSaleStopTime();
//                    LocalDateTime nowTime = LocalDateTime.now();
//                    if (nowTime.isBefore(saleStartTime)) {
//                        continue;
//                    } else if (null != saleStopTime && nowTime.isAfter(saleStopTime)) {
//                        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());
                        }
//                        countStockNumber += goblinRedisUtils.getSkuStock(goblinGoodsSku.getSkuId());
                        map.put(skuItemVo.getSkuId(), skuItemVo.getHitRatio());
//                        checkNumberSku++;
                    }
                }
//                    if (checkNumberSku <= 0) {
//                        return ResponseDto.failure("盲盒下没有可生成兑换码的sku!");
//                    }
//
//                    if (countStockNumber < stockNumber) {
//                        ResponseDto.failure("配置库存大于sku总库存!");
//                    }
                if (isHit && hitRatioCount.doubleValue() < 100.00 && map.size() > 0) {
                    nftBoxUtils.arrangeHitRatioMap(map, hitRatioCount);
                }
                Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(item.getSkuStock(), 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);
                        return ResponseDto.failure("库存不足");
                    } else {
                        redisUtils.setSkuStock(vo.getListId(), key, stockNum);
                        redisUtils.addGoblinListRelationBox(itemVo.getSkuId(), vo.getListId(), key);
                    }
                }

            } else {//非盲盒逻辑
                //库存
                int skuStock = redisUtils.decrSkuStock(null, itemVo.getSkuId(), itemVo.getSkuStock());
                if (skuStock < 0) {
                    redisUtils.incrSkuStock(null, itemVo.getSkuId(), itemVo.getSkuStock());
                    return ResponseDto.failure("库存不足");
                } else {
                    redisUtils.setSkuStock(vo.getListId(), itemVo.getSkuId(), itemVo.getSkuStock());
                }
            }

            //集合
            GoblinListCollectVo collectVo = GoblinListCollectVo.getNew();
            collectVo.setSpuId(itemVo.getSpuId());
            collectVo.setSkuId(itemVo.getSkuId());
            collectVo.setPrice(itemVo.getPrice());
            collectVo.setPriceV(itemVo.getPriceV());
            collectVo.setProductId(itemVo.getProductId());
            collectVo.setWhiteType(vo.getWhiteType());
            if (vo.getWhiteType().equals(1) && vo.getWhiteUrl().equals("")) {
                collectVo.setWhiteType(-1);
            }
            collectVo.setTimeStart(st);
            collectVo.setTimeEnd(et);
            collectVo.setTagType(vo.getTagType());
            collectVo.setListId(vo.getListId());
            collectVos.add(collectVo);
            redisUtils.setGoblinListCollect(itemVo.getSkuId(), collectVos);
            // 白名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), vo.getWhiteUrl(), "", "3", item.getSkuId());
            // 黑名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), vo.getBlackUrl(), "", "4", item.getSkuId());
            goblinListDetails.add(new Object[]{
                    vo.getListId(), itemVo.getSpuId(), itemVo.getSkuId(), now, itemVo.getSkuStock(), itemVo.getPriceV(), itemVo.getProductId(), itemVo.getPrice()
            });
        }
        vo.setItemVo(voItemList);
        redisUtils.setGoblinListDetailsVo(vo);
        mongoUtils.insertGoblinListDetailsVo(vo);
        goblinList.add(new Object[]{
                vo.getListId(), vo.getUid(), vo.getName(), vo.getWhiteType(), vo.getWhiteUrl(), vo.getTimeStart(), vo.getTimeEnd(), vo.getTagType(), vo.getBlackUrl(), now
        });
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(), SqlMapping.gets(sqls, goblinList, goblinListDetails));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> update(GoblinListUpdateParam param) {
        String whiteUrl = "";
        String blackUrl = "";
        LocalDateTime now = LocalDateTime.now();
        GoblinListDetailsVo vo = redisUtils.getGoblinListDetailsVo(param.getListId());
        if (vo == null || !vo.getUid().equals(CurrentUtil.getCurrentUid())) {
            return ResponseDto.failure("信息错误");
        }
        whiteUrl = vo.getWhiteUrl();
        blackUrl = vo.getBlackUrl();
        //判断 白名单类型
        vo.setWhiteType(param.getWhiteType());
        if (param.getWhiteType().equals(1)) {//需要xls文件
//            if (param.getWhiteUrl() == null || param.getWhiteUrl().equals("")) {
//                return ResponseDto.failure("未上传指定用户文件");
//            }
            vo.setWhiteUrl(param.getWhiteUrl());
            vo.setWhiteName(param.getWhiteName());
        } else {//不需要xls文件
            vo.setWhiteUrl("");
            vo.setWhiteName("");
        }
        vo.setBlackUrl(param.getBlackUrl() == null ? "" : param.getBlackUrl());
        vo.setBlackName(param.getBlackName() == null ? "" : param.getBlackName());
        for (GoblinListDetailsItemVo item : vo.getItemVo()) {
            // 白名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), param.getWhiteUrl(), whiteUrl, "3", item.getSkuId());
            // 黑名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), param.getBlackUrl(), blackUrl, "4", item.getSkuId());
        }
        List<GoblinListCollectVo> collectVos = redisUtils.getGoblinListCollect(vo.getItemVo().get(0).getSkuId());
        for (GoblinListCollectVo itemVo : collectVos) {
            if (itemVo.getListId().equals(param.getListId())) {
                itemVo.setWhiteType(vo.getWhiteType());
                if (vo.getWhiteType().equals(1) && vo.getWhiteUrl().equals("")) {
                    itemVo.setWhiteType(-1);
                }
                break;
            }
        }
        redisUtils.setGoblinListCollect(vo.getItemVo().get(0).getSkuId(), collectVos);
        redisUtils.setGoblinListDetailsVo(vo);
        mongoUtils.changeGoblinListDetailsVo(vo);
        //sql入库
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(),
                SqlMapping.get("goblin_list_update", param.getWhiteUrl(), param.getWhiteType(), param.getBlackUrl(), now, param.getListId()));
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Boolean> delete(String listId) {
        LocalDateTime now = LocalDateTime.now();
        GoblinListDetailsVo vo = redisUtils.getGoblinListDetailsVo(listId);
        if (vo == null || !vo.getUid().equals(CurrentUtil.getCurrentUid())) {
            return ResponseDto.failure("信息错误");
        }
        for (GoblinListDetailsItemVo item : vo.getItemVo()) {
            // 白名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), "", vo.getWhiteUrl(), "3", item.getSkuId());
            // 黑名单
            queueUtils.sendMsgByRedisXls(vo.getListId(), "", vo.getBlackUrl(), "4", item.getSkuId());
        }

        //获取skuVo
        GoblinGoodsSkuInfoVo skuVo = redisUtils.getGoodsSkuInfoVo(vo.getItemVo().get(0).getSkuId());
        if (skuVo.getUnbox().equals("1")) {
            ArrayList<String> skuIdList = redisUtils.getGoblinListRelationBox(skuVo.getSkuId(), vo.getListId());
            for (String relationSkuId : skuIdList) {
                int restStock = redisUtils.getSkuStock(vo.getListId(), relationSkuId);
                if (restStock > 0) {
                    redisUtils.incrSkuStock(null, relationSkuId, restStock);
                }
            }
        } else {
            //库存
            int restStock = redisUtils.getSkuStock(vo.getListId(), vo.getItemVo().get(0).getSkuId());
            if (restStock > 0) {
                redisUtils.incrSkuStock(null, vo.getItemVo().get(0).getSkuId(), restStock);
            }
        }

        redisUtils.delGoblinListCollect(vo.getItemVo().get(0).getSkuId(), listId);
        redisUtils.delGoblinListDetailsVo(listId);
        mongoUtils.removeGoblinListDetailsVo(listId);
        //sql入库
        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(),
                SqlMapping.get("goblin_list_remove", now, listId));
        return ResponseDto.success();
    }

    private boolean judgeTime(LocalDateTime st, LocalDateTime et, List<GoblinListCollectVo> collects) {
        for (GoblinListCollectVo collectItem : collects) {
            if (st.compareTo(collectItem.getTimeStart()) == 0) {
                return true;
            } else if (et != null && et.compareTo(collectItem.getTimeStart()) == 0) {
                return true;
            } else if (collectItem.getTimeEnd() != null && st.compareTo(collectItem.getTimeEnd()) == 0) {
                return true;
            } else if (collectItem.getTimeEnd() != null && et != null && et.compareTo(collectItem.getTimeEnd()) == 0) {
                return true;
            }
        }
        return false;
    }
}
