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

import com.github.pagehelper.PageInfo;
import com.liquidnet.commons.lang.util.CollectionUtil;
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.dto.manage.GoblinGoodsAnticipateAddParam;
import com.liquidnet.service.goblin.dto.manage.GoblinGoodsAnticipateUpdateParam;
import com.liquidnet.service.goblin.dto.manage.GoblinGoodsAnticipateValueAddParam;
import com.liquidnet.service.goblin.dto.manage.GoblinGoodsAnticipateValueParam;
import com.liquidnet.service.goblin.dto.manage.vo.AnticipateValueVo;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinGoodsAnticipateValueVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodAnticipateUserVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsAnticipateVo;
import com.liquidnet.service.goblin.service.IGoblinGoodsAnticipateService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 * 预约表 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2022-04-07
 */
@Service
@Slf4j
public class GoblinGoodsAnticipateServiceImpl implements IGoblinGoodsAnticipateService {

    @Autowired
    GoblinMongoUtils goblinMongoUtils;

    @Autowired
    GoblinRedisUtils goblinRedisUtils;

    @Autowired
    QueueUtils queueUtils;

    @Override
    public ResponseDto<Object> add(GoblinGoodsAnticipateAddParam goodsAnticipateAddParam) {
        if (StringUtils.isNotBlank(goodsAnticipateAddParam.getRule()) && goodsAnticipateAddParam.getList() != null && goodsAnticipateAddParam.getList().size() > 0) {
            for (GoblinGoodsAnticipateValueAddParam vo : goodsAnticipateAddParam.getList()) {
                if (goblinRedisUtils.getSkuId(vo.getSkuId())) {
                    return ResponseDto.failure(vo.getSkuName().concat("该sku已存在预约"));
                }
            }
            //生成的antId
            String antId = IDGenerator.nextTimeId2();
            GoblinGoodsAnticipateVo goodsAnticipateVo = new GoblinGoodsAnticipateVo();
            BeanUtils.copyProperties(goodsAnticipateAddParam, goodsAnticipateVo);
            goodsAnticipateVo.setAntId(antId);
            goodsAnticipateVo.setCreatedDate(LocalDateTime.now());
            goodsAnticipateVo.setDelTag(0);

            //redis消息预约消息表
            LinkedList<Object[]> sqlAnt = CollectionUtil.linkedListObjectArr();
            sqlAnt.add(new Object[]{
                    antId,
                    goodsAnticipateVo.getRule(),
                    goodsAnticipateVo.getCreatedDate(),
                    goodsAnticipateVo.getDelTag()
            });
            sendRedis("goblin_goods_anticipate", sqlAnt);

            //mongodb新增
            goblinMongoUtils.setGoblinGoodsAnticipateVo(goodsAnticipateVo);

            addAnticipateValues(antId, goodsAnticipateAddParam.getRule(), goodsAnticipateAddParam.getList());

            //返回预约id
            return ResponseDto.success(antId);
        }
        return ResponseDto.failure("参数有误");
    }

    public void addAnticipateValues(String antId, String rule, List<GoblinGoodsAnticipateValueAddParam> list) {
        if (list != null && list.size() > 0) {
            list.forEach(item -> {
                GoblinGoodsAnticipateValueVo goodsAnticipateValueVo = new GoblinGoodsAnticipateValueVo();
                BeanUtils.copyProperties(item, goodsAnticipateValueVo);
                goodsAnticipateValueVo.setAntId(antId);
                goodsAnticipateValueVo.setRule(rule);
                goodsAnticipateValueVo.setCreatedDate(LocalDateTime.now());
                goodsAnticipateValueVo.setDelTag(0);
                goodsAnticipateValueVo.setAboutPeople(BigInteger.valueOf(0));
                goodsAnticipateValueVo.setActualPeople(BigInteger.valueOf(0));
                //redis消息
                //redis标识存入该sku处于预约列表
                goblinRedisUtils.setSkuId(goodsAnticipateValueVo.getSkuId());

                //保存mysql中间表
                LinkedList<Object[]> sqlValue = CollectionUtil.linkedListObjectArr();
                sqlValue.add(new Object[]{
                        goodsAnticipateValueVo.getAntId(),
                        goodsAnticipateValueVo.getSkuName(),
                        goodsAnticipateValueVo.getSkuId(),
                        goodsAnticipateValueVo.getSpuId(),
                        goodsAnticipateValueVo.getAboutPeople(),
                        goodsAnticipateValueVo.getActualPeople(),
                        goodsAnticipateValueVo.getRule(),
                        goodsAnticipateValueVo.getAboutStartDate(),
                        goodsAnticipateValueVo.getAboutEndDate(),
                        goodsAnticipateValueVo.getCreatedDate(),
                        goodsAnticipateValueVo.getDelTag()
                });
                sendRedis("goblin_goods_anticipate_value", sqlValue);

                //存入mongodb中
                goblinMongoUtils.addAnticipateValues(goodsAnticipateValueVo);
            });
        }
    }

    @Override
    public ResponseDto<PageInfo<GoblinGoodsAnticipateValueVo>> list(GoblinGoodsAnticipateValueParam goodsAnticipateValueParam) {
        PageInfo<GoblinGoodsAnticipateValueVo> pageInfo = new PageInfo<>();

        HashMap<String, Object> map = goblinMongoUtils.getGoblinGoodsAnticipateValueVos(goodsAnticipateValueParam);
        List<GoblinGoodsAnticipateValueVo> data = (List<GoblinGoodsAnticipateValueVo>) map.get("data");
        for (GoblinGoodsAnticipateValueVo anticipateValueVo : data) {
            //查询真实预约人数
            BigInteger autIdPeople = goblinRedisUtils.getSkuIdPeople(anticipateValueVo.getSkuId());
            autIdPeople = autIdPeople != null ? autIdPeople : BigInteger.valueOf(0);
            //预约人数   设置预约数+实际预约数
            anticipateValueVo.setAboutPeople(anticipateValueVo.getAboutPeople().add(autIdPeople));
            //实际预约人数
            anticipateValueVo.setActualPeople(autIdPeople);
            //设置预约状态
            anticipateValueVo.setState(setState(anticipateValueVo.getAboutStartDate(), anticipateValueVo.getAboutEndDate()));

        }
        pageInfo.setList(data);
        pageInfo.setTotal((Long) map.get("total"));
        return ResponseDto.success(pageInfo);
    }

    private Integer setState(LocalDateTime StartDate, LocalDateTime EndDate) {

        LocalDateTime now = LocalDateTime.now();
        if (StartDate.isAfter(now)) {
            //未开始  0
            return 0;
        }
        if (StartDate.isBefore(now) && EndDate.isAfter(now)) {
            //预约中 1
            return 1;
        }
        if (EndDate.isBefore(now)) {
            //已结束 2
            return 2;
        }
        //其他
        return null;
    }

    @Override
    public ResponseDto<Object> updatePeople(String skuId, BigInteger people) {
        //修改Mongodb
        goblinMongoUtils.updateGoblinGoodsAnticipateValueVoPeople(skuId, people);
        //修改mysql
        LinkedList<Object[]> sqlValue = CollectionUtil.linkedListObjectArr();
        sqlValue.add(new Object[]{
                people,
                skuId
        });
        sendRedis("goblin_goods_anticipate_value_update_proper", sqlValue);
        return ResponseDto.success();
    }

    @Override
    public ResponseDto<Object> delete(String skuId) {
        //更具skuId查询
        GoblinGoodsAnticipateValueVo goodsAnticipateValueVo = goblinMongoUtils.getAnticipateValueVo(skuId);
        if (goodsAnticipateValueVo != null) {
            goodsAnticipateValueVo.setState(setState(goodsAnticipateValueVo.getAboutStartDate(), goodsAnticipateValueVo.getAboutEndDate()));
            //没有开启则可以删除预约
            if (!goodsAnticipateValueVo.getState().equals(0)) {
                return ResponseDto.failure("预约状态为已开启或已结束，不可删除！");
            }
            //mysql删除
            LinkedList<Object[]> sqlValue = CollectionUtil.linkedListObjectArr();
            sqlValue.add(new Object[]{
                    skuId
            });
            //预约库删除
            sendRedis("goblin_goods_anticipate_value_delete", sqlValue);
            //删除mongodb
            goblinMongoUtils.delGoodsAnticipateValueVo(skuId);
            return ResponseDto.success();
        }
        return ResponseDto.failure("该预约不存在");
    }

    private void delUserBySkuId(String skuId) {
        //删除redis 和mongodb
        goblinMongoUtils.delUserBySkuId(skuId);
        //数据库修改  用户预约过该skuId的表字段全部修改未 1
        LinkedList<Object[]> sqlValue = CollectionUtil.linkedListObjectArr();
        sqlValue.add(new Object[]{
                skuId
        });
        sendRedis("goblin_goods_anticipate_user_update_sku", sqlValue);
    }

    @Override
    public ResponseDto<Object> userAbout(String skuId, String uid, String phone) {
        //查询该skuId是否能被预约
        GoblinGoodsAnticipateValueVo anticipateValueVo = goblinMongoUtils.getAnticipateValueVo(skuId);
        if (anticipateValueVo != null) {
            anticipateValueVo.setState(setState(anticipateValueVo.getAboutStartDate(), anticipateValueVo.getAboutEndDate()));
            if (!anticipateValueVo.getState().equals(1)) {
                return ResponseDto.failure("预约尚未开始或已结束！");
            }
            //查询该用户是否预
            GoblinGoodAnticipateUserVo userVo = goblinRedisUtils.getUserAboutAut(skuId, uid);
            LinkedList<Object[]> sqlValue = CollectionUtil.linkedListObjectArr();
            if (userVo == null) {
                GoblinGoodAnticipateUserVo user = new GoblinGoodAnticipateUserVo();
                user.setUid(uid);
                user.setSkuId(skuId);
                user.setPhone(phone);
                user.setState(0);
                //mongodb记录
                goblinRedisUtils.setUserAboutSku(user);
                //用户没有预约过
                //发送redis消息修改mysql记录用户预约
                sqlValue.add(new Object[]{
                        uid,
                        skuId,
                        phone,
                        0
                });
                sendRedis("goblin_goods_anticipate_user", sqlValue);
                goblinRedisUtils.setSkuIdPeople(skuId, 0);
                //储存用户头像
                userAvatar(skuId);
            }
            return ResponseDto.success();
        }
        return ResponseDto.failure("该预约不存在！");
    }

    @Override
    public ResponseDto<AnticipateValueVo> getAnticipateValueBySkuId(String skuId) {
        GoblinGoodsAnticipateValueVo anticipateValueVo = goblinMongoUtils.getAnticipateValueVo(skuId);
        AnticipateValueVo valueVo = AnticipateValueVo.getNew();
        if (anticipateValueVo != null) {
            BeanUtils.copyProperties(anticipateValueVo, valueVo);
            valueVo.setState(setState(valueVo.getAboutStartDate(), valueVo.getAboutEndDate()));
        } else {
            valueVo.setState(null);
            valueVo.setAboutEndDate(null);
            valueVo.setAboutStartDate(null);
        }
        return ResponseDto.success(valueVo);
    }

    private void userAvatar(String skuId) {
        //获取
        goblinRedisUtils.setUserAvatar(skuId);
    }

    public void sendRedis(String sqlKey, LinkedList<Object[]> sqlData) {
        LinkedList<String> sql = CollectionUtil.linkedListString();
        sql.add(SqlMapping.get(sqlKey));
        String sqlStr = SqlMapping.gets(sql, sqlData);
        queueUtils.sendMsgByRedis(
                MQConst.GoblinQueue.GOBLIN_STORE_MARKET.getKey(),
                sqlStr);
    }

}
