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

import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.vo.GoblinStoreCouponVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUseResultVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUserCouponBasicVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUserCouponVo;
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.ArrayList;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.List;

@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);
        for (GoblinStoreCouponVo vo : listVo) {
            if (!returnList.contains(vo.getType()) && LocalDateTime.now().isAfter(vo.getStartTime()) && LocalDateTime.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);
        for (GoblinStoreCouponVo vo : listVo) {
            if (vo.getType().equals(type) && LocalDateTime.now().isAfter(vo.getStartTime()) && LocalDateTime.now().isBefore(vo.getEndTime())) {
                vo.setStock(null);
                returnList.add(vo);
            }
        }
        return returnList;
    }

    @Override
    public Boolean receiveCoupon(String uid, List<GoblinUserCouponVo> userCouponVoList, GoblinStoreCouponVo storeCouponVo) {
        String storeCouponId = storeCouponVo.getStoreCouponId();
        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));
        if (goblinRedisUtils.decrStoreCouponStock(storeCouponId, 1) >= 0) {
            goblinMongoUtils.insertUserCouponVo(receiveUserCouponBasicVo);
            goblinRedisUtils.setUserCouponVos(uid, userCouponVoList);

            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_STORE.getKey(),
                    SqlMapping.get("goblin_user_coupon.insert", initUserCouponObjs));
            return true;
        }
        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();
        for (GoblinUserCouponVo vo : voList) {
            if ("1".equals(type)) {
                if (vo.getState().equals(1)) {
                    returnList.add(vo);
                }
            } else {
                if (vo.getState().equals(3) || vo.getState().equals(5)) {
                    returnList.add(vo);
                }
            }

        }
        return returnList;
    }

    @Override
    public Boolean canUse(BigDecimal totalPrice, String spuId, String uid) {
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);
        Boolean canUse = false;
        for (GoblinUserCouponVo vo : voList) {
            //判断券状态 和 触发金额
            if (vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) >= 0) {
                List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                //判断是否在可用商品内
                for (String item : spuIds) {
                    List<String> spuList = Arrays.asList(spuId.split(","));
                    if (spuList.contains(item)) {
                        canUse = true;
                        break;
                    }
                }
            }
            if (canUse) {
                break;
            }
        }
        return canUse;
    }

    @Override
    public List<GoblinUserCouponVo> useList(BigDecimal totalPrice, String spuId, String uid) {
        List<GoblinUserCouponVo> voList = goblinRedisUtils.getUserCouponVos(uid);
        List<GoblinUserCouponVo> returnList = ObjectUtil.getGoblinUserCouponVo();
        for (GoblinUserCouponVo vo : voList) {
            //判断券状态 和 触发金额
            if (vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) >= 0) {
                List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                //判断是否在可用商品内
                for (String item : spuIds) {
                    List<String> spuList = Arrays.asList(spuId.split(","));
                    if (spuList.contains(item)) {
                        returnList.add(vo);
                        break;
                    }
                }
            }
        }
        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");
        for (GoblinUserCouponVo vo : voList) {
            if (vo.getUcouponId().equals(ucouponId)) {
                //判断券状态 和 触发金额
                if (vo.getState().equals(1) && vo.getTriggers().compareTo(totalPrice) >= 0) {
                    List<String> spuIds = goblinRedisUtils.getStoreCouponSpuIds(vo.getStoreCouponId());
                    //判断是否在可用商品内
                    for (String item : spuIds) {
                        List<String> spuList = Arrays.asList(spuId.split(","));
                        if (spuList.contains(item)) {
                            if (vo.getType().equals("1")) {//代金券
                                returnVo.setValue(vo.getValFace());
                                returnVo.setCouType(vo.getType());
                            } else if (vo.getType().equals("2")) {//折扣
                                returnVo.setValue(totalPrice.multiply(vo.getDeduction()).setScale(2, BigDecimal.ROUND_HALF_UP));
                                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_STORE.getKey(),
                                    SqlMapping.get("goblin_user_coupon.updateState",  vo.getState(),vo.getUsedFor(),LocalDateTime.now()));
                            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_STORE.getKey(),
                                    SqlMapping.get("goblin_user_coupon.updateState", vo.getState(),vo.getUsedFor(),LocalDateTime.now()));
                        }
                        break;
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
