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

import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.param.BackCouponParam;
import com.liquidnet.service.goblin.service.GoblinCouponService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import com.liquidnet.service.goblin.util.QueueUtils;
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.*;

@Slf4j
@Service
public class GoblinCouponImpl implements GoblinCouponService {
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    GoblinMongoUtils goblinMongoUtils;
    @Autowired
    QueueUtils queueUtils;

    @Override
    public ArrayList<String> getSpuType(String spuId, String storeId) {
        ArrayList<String> returnList = CollectionUtil.arrayListString();
        String pre = GoblinStatusConst.MarketPreStatus.getPre(spuId);
        if (pre != null) {
            spuId = spuId.split(pre)[0];
        }
        List<GoblinStoreCouponVo> listVo = goblinRedisUtils.getGoodsMarketsForCoupon(spuId, storeId);
        LocalDateTime now = LocalDateTime.now();
        for (GoblinStoreCouponVo vo : listVo) {
            if (!returnList.contains(vo.getType()) && "1".equals(vo.getReceiveCurb())
                    && now.isAfter(vo.getStartTime()) && now.isBefore(vo.getEndTime())) {
                returnList.add(vo.getType());
            }
        }
        return returnList;
    }

    @Override
    public ArrayList<GoblinStoreCouponVo> getSpuByType(String spuId, String storeId, String type) {
        ArrayList<GoblinStoreCouponVo> returnList = ObjectUtil.getGoblinStoreCouponVoArrayList();
        String pre = GoblinStatusConst.MarketPreStatus.getPre(spuId);
        if (pre != null) {
            spuId = spuId.split(pre)[0];
        }
        List<GoblinStoreCouponVo> listVo = goblinRedisUtils.getGoodsMarketsForCoupon(spuId, storeId);
        LocalDateTime now = LocalDateTime.now();
        for (GoblinStoreCouponVo vo : listVo) {
            if ((vo.getType().equals(type) || type.equals("0")) && "1".equals(vo.getReceiveCurb())
                    && now.isAfter(vo.getStartTime()) && now.isBefore(vo.getEndTime())) {
//                vo.setStock(null);
                if (0 == vo.getStock()) {// 无限库存
                    vo.setStock(1);
                } else {// 有限库存
                    int surplusStock = goblinRedisUtils.getStoreCouponStock(vo.getStoreCouponId());
                    vo.setStock(surplusStock == 0 ? 0 : 1);
                }
                returnList.add(vo);
            }
        }
        return returnList;
    }

    @Override
    public Boolean receiveCoupon(String uid, List<GoblinUserCouponVo> userCouponVoList, GoblinStoreCouponVo storeCouponVo) {
        String storeCouponId = storeCouponVo.getStoreCouponId();
        if (storeCouponVo.getStock().equals(0) || goblinRedisUtils.decrStoreCouponStock(storeCouponId, 1) >= 0) {
            LocalDateTime now = LocalDateTime.now();
            GoblinUserCouponBasicVo receiveUserCouponBasicVo = GoblinUserCouponBasicVo.getNew().initByStoreCouponVo(storeCouponVo);
            receiveUserCouponBasicVo.setUid(uid);
            receiveUserCouponBasicVo.setBindAt(now);
            receiveUserCouponBasicVo.setOperator(uid);
            receiveUserCouponBasicVo.setCreatedAt(now);

            userCouponVoList.add(GoblinUserCouponVo.getNew().copy(receiveUserCouponBasicVo));

//            long s = System.nanoTime();
            goblinMongoUtils.insertUserCouponVo(receiveUserCouponBasicVo);
//            log.info("MDB.I耗时:{}ms", (System.nanoTime() - s) / 1000000);
//            s = System.nanoTime();
            goblinRedisUtils.setUserCouponVos(uid, userCouponVoList);
//            log.info("RDS.S耗时:{}ms", (System.nanoTime() - s) / 1000000);

            LinkedList<Object[]> initUserCouponObjs = CollectionUtil.linkedListObjectArr();
            initUserCouponObjs.add(new Object[]{
                    receiveUserCouponBasicVo.getUcouponId(), receiveUserCouponBasicVo.getStoreCouponId(), receiveUserCouponBasicVo.getUid(),
                    receiveUserCouponBasicVo.getState(), receiveUserCouponBasicVo.getBindAt(), receiveUserCouponBasicVo.getDuedAt(),
                    receiveUserCouponBasicVo.getOperator(), receiveUserCouponBasicVo.getCreatedAt()
            });
            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                    SqlMapping.get("goblin_user_coupon.insert", initUserCouponObjs));
            return true;
        }
        if (!storeCouponVo.getStock().equals(0)) {
            goblinRedisUtils.incrStoreCouponStock(storeCouponId, 1);
        }
        return false;
    }

    @Override
    public List<GoblinUserCouponVo> getList(String type) {
        String uid = CurrentUtil.getCurrentUid();
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);
        List<GoblinUserCouponVo> returnList = ObjectUtil.getGoblinUserCouponVo();
//        HashMap<String, String> storeIdNameMap = CollectionUtil.mapStringString();
//        GoblinStoreInfoVo storeInfoVoTmp;
        LocalDateTime now = LocalDateTime.now();
        for (GoblinUserCouponVo vo : voList) {
//            if (StringUtils.isNotEmpty(vo.getStoreId())) {
//                storeInfoVoTmp = goblinRedisUtils.getStoreInfoVo(vo.getStoreId());
//                vo.setStoreName(storeIdNameMap.getOrDefault(vo.getStoreId(), null == storeInfoVoTmp ? null : storeInfoVoTmp.getStoreName()));
//            }
            if ("1".equals(type)) {
                if (vo.getDuedAt().isAfter(now) && vo.getState().equals(1)) {
                    returnList.add(vo);
                }
            } else {
                if (vo.getDuedAt().isBefore(now) || vo.getState().equals(3)) {
                    vo.setState(3);
                    returnList.add(vo);
                }
                if (vo.getState().equals(5)) {
                    returnList.add(vo);
                }
            }

        }
        return returnList;
    }

    @Override
    public GoblinUserCouponVo canUse(BigDecimal totalPrice, String spuId, String uid, String storeId) {
        BigDecimal maxPrice = BigDecimal.ZERO;
        GoblinUserCouponVo returnVo = GoblinUserCouponVo.getNew();
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);

        LocalDateTime now = LocalDateTime.now();
        for (GoblinUserCouponVo vo : voList) {
            //判断券状态 和 触发金额
            if (vo.getDuedAt().isAfter(now) && vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) <= 0 && vo.getStoreId().equals(storeId)) {
                if (vo.getUseScope().equals("0")) {
                    BigDecimal tempPrice = BigDecimal.ZERO;
                    if (vo.getType().equals("1")) {//代金券
                        tempPrice = vo.getValFace();
                    } else if (vo.getType().equals("2")) {//折扣
                        tempPrice = totalPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP);
                        if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                            tempPrice = vo.getDeduction();
                        }
                    } else if (vo.getType().equals("3") && vo.getTriggers().compareTo(totalPrice) <= 0) {//满减
                        tempPrice = vo.getValMinus();
                    }
                    if (maxPrice.compareTo(tempPrice) < 0) {
                        maxPrice = tempPrice;
                        returnVo = vo;
                    }
                } else {
                    List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                    if (spuId == null) {
                        continue;
                    }
                    //判断是否在可用商品内
                    for (String item : spuIds) {
                        List<String> spuList = Arrays.asList(spuId.split(","));
                        if (spuList.contains(item)) {
                            BigDecimal tempPrice = BigDecimal.ZERO;
                            if (vo.getType().equals("1")) {//代金券
                                tempPrice = vo.getValFace();
                            } else if (vo.getType().equals("2")) {//折扣
                                tempPrice = totalPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP);
                                if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                                    tempPrice = vo.getDeduction();
                                }
                            } else if (vo.getType().equals("3") && vo.getTriggers().compareTo(totalPrice) <= 0) {//满减
                                tempPrice = vo.getValMinus();
                            }
                            if (maxPrice.compareTo(tempPrice) < 0) {
                                maxPrice = tempPrice;
                                returnVo = vo;
                            }
                        }
                    }
                }
            }
        }
        return returnVo;
    }

    @Override
    public List<GoblinUserCouponVo> useList(BigDecimal totalPrice, String spuId, String uid) {
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);
        List<GoblinUserCouponVo> returnList = ObjectUtil.getGoblinUserCouponVo();

        LocalDateTime now = LocalDateTime.now();
        for (GoblinUserCouponVo vo : voList) {
            //判断券状态 和 触发金额
            if (vo.getDuedAt().isAfter(now) && vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) <= 0) {
                if (vo.getUseScope().equals("0")) {
                    returnList.add(vo);
                } else {
                    List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                    if (spuId == null) {
                        break;
                    }
                    //判断是否在可用商品内
                    for (String item : spuIds) {
                        List<String> spuList = Arrays.asList(spuId.split(","));
                        if (spuList.contains(item)) {
                            returnList.add(vo);
                            break;
                        }
                    }
                }
            }
        }
        returnList.sort(Comparator.comparing(GoblinUserCouponVo::getState));
        return returnList;
    }

    @Override
    public GoblinUseResultVo useCoupon(String ucouponId, String content, BigDecimal totalPrice, String spuId, String uid) {
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);
        GoblinUseResultVo returnVo = GoblinUseResultVo.getNew();
        returnVo.setValue(BigDecimal.ZERO);
        returnVo.setCouType("-1");

        LocalDateTime now = LocalDateTime.now();
        for (GoblinUserCouponVo vo : voList) {
            if (vo.getUcouponId().equals(ucouponId)) {
                //判断券状态 和 触发金额
                if (vo.getDuedAt().isAfter(now) && vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) <= 0) {
                    if (vo.getUseScope().equals("0")) {
                        if (vo.getType().equals("1")) {//代金券
                            returnVo.setValue(vo.getValFace());
                            returnVo.setCouType(vo.getType());
                        } else if (vo.getType().equals("2")) {//折扣
                            BigDecimal tempPrice = totalPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP);
                            if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                                tempPrice = vo.getDeduction();
                            }
                            returnVo.setValue(tempPrice);
                            returnVo.setCouType(vo.getType());
                        } else if (vo.getType().equals("3") && vo.getTriggers().compareTo(totalPrice) <= 0) {//满减
                            returnVo.setValue(vo.getValMinus());
                            returnVo.setCouType(vo.getType());
                        }
                        vo.setState(5);
                        vo.setUsedFor(content);
                        goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                        queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                        break;
                    } else {
                        List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                        if (spuId == null) {
                            continue;
                        }
                        //判断是否在可用商品内
                        List<String> spuList = Arrays.asList(spuId.split(","));
                        for (String item : spuIds) {
                            if (spuList.contains(item)) {
                                if (vo.getType().equals("1")) {//代金券
                                    returnVo.setValue(vo.getValFace());
                                    returnVo.setCouType(vo.getType());
                                } else if (vo.getType().equals("2")) {//折扣
                                    BigDecimal tempPrice = totalPrice.multiply(vo.getDiscount()).setScale(2, BigDecimal.ROUND_HALF_UP);
                                    if (tempPrice.compareTo(vo.getDeduction()) > 0) {
                                        tempPrice = vo.getDeduction();
                                    }
                                    returnVo.setValue(tempPrice);
                                    returnVo.setCouType(vo.getType());
                                } else if (vo.getType().equals("3") && vo.getTriggers().compareTo(totalPrice) <= 0) {//满减
                                    returnVo.setValue(vo.getValMinus());
                                    returnVo.setCouType(vo.getType());
                                }
                                vo.setState(5);
                                vo.setUsedFor(content);
                                goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                                queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                        SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                            }
                            break;
                        }
                    }
                }
                break;
            }
        }
        if (!returnVo.getCouType().equals("-1")) {
            goblinRedisUtils.setUserCouponVos(uid, voList);
        }
        return returnVo;
    }

    @Override
    public Boolean backCoupon(List<BackCouponParam> params) {
        try {
            for (BackCouponParam item : params) {
                List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(item.getUid());
                for (GoblinUserCouponVo vo : voList) {
                    if (vo.getUcouponId().equals(item.getuCouponIds())) {
                        if (LocalDateTime.now().isBefore(vo.getDuedAt())) {
                            vo.setState(1);
                            vo.setUsedFor("");
                            goblinRedisUtils.setUserCouponVos(item.getUid(), voList);
                            goblinMongoUtils.changeCouponVos(vo.getUcouponId(), vo);
                            queueUtils.sendMsgByRedis(MQConst.GoblinQueue.SQL_COUPON.getKey(),
                                    SqlMapping.get("goblin_user_coupon.updateState", vo.getState(), vo.getUsedFor(), LocalDateTime.now(), vo.getUcouponId()));
                        }
                        break;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
