package com.liquidnet.service.kylin.utils;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dto.vo.*;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketTimesVo;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.*;
import com.liquidnet.service.kylin.dto.vo.returns.KylinOrderListVo;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.mapper.KylinBuyNoticeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;

@Component
public class DataUtils {

    @Autowired
    private KylinBuyNoticeMapper buyNoticeMapper;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private MongoVoUtils mongoVoUtils;
    @Autowired
    private DataUtils dataUtils;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 根据 购票须知 id 获取 购票须知文案
     *
     * @param buyNoticeIds 购票须知 数组
     * @return 购票须知 json串
     */
    public String getBuyNoticeJsonString(List<String> buyNoticeIds) {
        List<KylinBuyNotice> data = buyNoticeMapper.selectList(new UpdateWrapper<KylinBuyNotice>().in("buy_notice_id", buyNoticeIds));
        return JsonUtils.toJson(data);
    }

    /**
     * 初始化普通库存
     *
     * @param ticketId     票id
     * @param totalGeneral 普通库存
     */
    public void setSurplusGeneral(String ticketId, int totalGeneral) {
        redisUtil.set(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_GENERAL, totalGeneral);
    }

    /**
     * 获取普通剩余库存
     *
     * @param ticketId 票id
     * @return 普通剩余库存
     */
    public int getSurplusGeneral(String ticketId) {
        return (int) redisUtil.get(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_GENERAL);
    }

    /**
     * 修改普通库存 并 返回修改后的数量
     *
     * @param ticketId       票id
     * @param surplusGeneral 普通库存
     * @return 普通剩余库存
     */
    public int changeSurplusGeneral(String ticketId, int surplusGeneral) {
        if (surplusGeneral > 0) {
            return (int) redisUtil.incr(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_GENERAL, surplusGeneral);
        } else {
            return (int) redisUtil.decr(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_GENERAL, Math.abs(surplusGeneral));
        }
    }

    /**
     * 判断 当前库存是否售罄
     *
     * @param ticketId 票id
     * @return boolean
     */
    public boolean ticketIsSoldOut(String ticketId) {
        if (0 >= getSurplusGeneral(ticketId)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 初始化兑换库存
     *
     * @param ticketId      票id
     * @param totalExchange 兑换库存
     */
    public void setSurplusExchange(String ticketId, int totalExchange) {
        redisUtil.set(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_EXCHANGE, totalExchange);
    }

    /**
     * 获取兑换剩余库存
     *
     * @param ticketId 票id
     * @return 兑换剩余库存
     */
    public int getSurplusExchange(String ticketId) {
        return (int) redisUtil.get(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_EXCHANGE);
    }

    /**
     * 变更兑换库存 并 返回 修改后的数量
     *
     * @param ticketId        票id
     * @param surplusExchange 普通库存
     * @return 兑换剩余库存
     */
    public int changeSurplusExchange(String ticketId, int surplusExchange) {
        if (surplusExchange > 0) {
            return (int) redisUtil.incr(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_EXCHANGE, surplusExchange);
        } else {
            return (int) redisUtil.decr(KylinRedisConst.PERFORMANCES_INVENTORY + ticketId + ":" + KylinRedisConst.SURPLUS_EXCHANGE, Math.abs(surplusExchange));
        }
    }

    /**
     * 根据演出id 获取 演出vo 详情
     *
     * @param performanceId
     * @return
     */
    public KylinPerformanceVo getPerformanceVo(String performanceId) {
        if (redisUtil.hasKey(KylinRedisConst.PERFORMANCES + performanceId)) {
        } else {
            KylinPerformanceVo performanceData = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            List<KylinPerformanceVo> roadList = new ArrayList();
            if (Integer.parseInt(performanceData.getRoadShowId()) > 0) {
                roadList = dataUtils.getRoadList(performanceData.getRoadShowId());
            }
            redisUtil.set(KylinRedisConst.PERFORMANCES + performanceId, performanceData);
            performanceData.setRoadList(roadList); // 不一起存到演出详情
        }
        return (KylinPerformanceVo) redisUtil.get(KylinRedisConst.PERFORMANCES + performanceId);
    }

    public void setOrderList(String userId, List<KylinOrderListVo> vo) {
        redisUtil.set(KylinRedisConst.ORDER_LIST + userId, vo);
    }

    public List<KylinOrderListVo> getOrderList(String userId) {
        if (redisUtil.hasKey(KylinRedisConst.ORDER_LIST + userId)) {
        } else {
            List<KylinOrderListVo> voList = mongoTemplate.find(Query.query(Criteria.where("userId").is(userId))
                            .with(Sort.by(Sort.Direction.DESC, "createdAt")).limit(40),
                    KylinOrderListVo.class, KylinOrderTicketVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.ORDER_LIST + userId, voList);
        }
        return (List<KylinOrderListVo>) redisUtil.get(KylinRedisConst.ORDER_LIST + userId);
    }

    /**
     * 根据订单id 获取 订单vo 详情
     *
     * @param orderId
     * @return
     */
    public KylinOrderTicketVo getOrderTicketVo(String orderId) {
        if (redisUtil.hasKey(KylinRedisConst.ORDER + orderId)) {
        } else {
            KylinOrderTicketVo ticketData = mongoTemplate.findOne(Query.query(Criteria.where("orderTicketsId").is(orderId)), KylinOrderTicketVo.class, KylinOrderTicketVo.class.getSimpleName());
            List<KylinOrderTicketEntitiesVo> kylinOrderTicketEntitiesVoList = mongoTemplate.find(Query.query(Criteria.where("orderId").is(orderId)), KylinOrderTicketEntitiesVo.class, KylinOrderTicketEntitiesVo.class.getSimpleName());
            ticketData.setEntitiesVoList(kylinOrderTicketEntitiesVoList);
            redisUtil.set(KylinRedisConst.ORDER + orderId, ticketData);
        }
        return (KylinOrderTicketVo) redisUtil.get(KylinRedisConst.ORDER + orderId);
    }

    /**
     * 删除订单redis
     *
     * @param orderId
     */
    public void delOrderTicketRedis(String orderId) {
        redisUtil.del(KylinRedisConst.ORDER + orderId);
    }

    /**
     * 获取bannerVo
     *
     * @param bannerId
     * @return
     */
    public KylinBannersVo getBannersVo(String bannerId) {
        if (redisUtil.hasKey(KylinRedisConst.BANNERS + bannerId)) {
        } else {
            KylinBannersVo ticketData = mongoTemplate.findOne(Query.query(Criteria.where("bannersId").is(bannerId)), KylinBannersVo.class, KylinBannersVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.BANNERS + bannerId, ticketData);
        }
        return (KylinBannersVo) redisUtil.get(KylinRedisConst.BANNERS + bannerId);
    }

    /**
     * 删除 banner redis
     *
     * @param bannerId
     */
    public void delBannersRedis(String bannerId) {
        redisUtil.del(KylinRedisConst.BANNERS + bannerId);
    }

    /**
     * 获取 推荐演出vo
     *
     * @param recommendId
     * @return
     */
    public KylinPerformanceVo getPerformanceRecommendVo(String recommendId) {
        if (redisUtil.hasKey(KylinRedisConst.PERFORMANCES_RECOMMEND + recommendId)) {
        } else {
            KylinPerformanceVo ticketData = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(recommendId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.PERFORMANCES_RECOMMEND + recommendId, ticketData);
        }
        return (KylinPerformanceVo) redisUtil.get(KylinRedisConst.PERFORMANCES_RECOMMEND + recommendId);
    }

    /**
     * 删除 推荐演出 redis
     *
     * @param recommendId
     */
    public void delPerformanceRecommendRedis(String recommendId) {
        redisUtil.del(KylinRedisConst.PERFORMANCES_RECOMMEND + recommendId);
    }

    /**
     * 获取 验票账号 vo
     *
     * @param checkUserId
     * @return
     */
    public KylinCheckUserVo getCheckUserVo(String checkUserId) {
        if (redisUtil.hasKey(KylinRedisConst.CHECK_USER + checkUserId)) {
        } else {
            KylinCheckUserVo ticketData = mongoTemplate.findOne(Query.query(Criteria.where("checkUserId").is(checkUserId)), KylinCheckUserVo.class, KylinCheckUserVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.CHECK_USER + checkUserId, ticketData);
        }
        return (KylinCheckUserVo) redisUtil.get(KylinRedisConst.CHECK_USER + checkUserId);
    }

    /**
     * 删除 验票账号 redis
     *
     * @param checkUserId
     */
    public void delCheckUserRedis(String checkUserId) {
        redisUtil.del(KylinRedisConst.CHECK_USER + checkUserId);
    }

    /**
     * 获取 验票账号关系 vo
     *
     * @param checkUserId
     * @return
     */
    public KylinCheckUserPerformanceVo getCheckUserRelationVo(String checkUserId) {
        if (redisUtil.hasKey(KylinRedisConst.CHECK_USER_RELATION + checkUserId)) {
        } else {
            KylinCheckUserPerformanceVo ticketData = mongoTemplate.findOne(Query.query(Criteria.where("checkUserId").is(checkUserId)), KylinCheckUserPerformanceVo.class, KylinCheckUserPerformanceVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.CHECK_USER_RELATION + checkUserId, ticketData);
        }
        return (KylinCheckUserPerformanceVo) redisUtil.get(KylinRedisConst.CHECK_USER_RELATION + checkUserId);
    }

    /**
     * 删除 验票账号关系 vo
     *
     * @param checkUserId
     */
    public void delCheckUserRelationRedis(String checkUserId) {
        redisUtil.del(KylinRedisConst.CHECK_USER_RELATION + checkUserId);
    }

    /**
     * 获取入场须知
     *
     * @param enterInfoId
     * @return
     */
    public String getEnterInfo(String enterInfoId) {
        if (redisUtil.hasKey(KylinRedisConst.ENTER_INFO + enterInfoId)) {
        } else {
            return "入场须知";
        }
        return (String) redisUtil.get(KylinRedisConst.ENTER_INFO + enterInfoId);
    }


    public void updatePerformanceMongo(String performanceIds, KylinPerformanceVo paramVo) {
        //查询 mysql 数据
        KylinPerformanceVo vo;
        if (null == paramVo) {
             vo = mongoVoUtils.combinePerformanceVoData(performanceIds);
        } else {
             vo = paramVo;
        }
        if (vo != null) {
            try {
                //删除 mongo数据
                mongoTemplate.remove(Query.query(Criteria.where("performancesId").is(performanceIds)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                //新增 mongo数据
                mongoTemplate.insert(vo, KylinPerformanceVo.class.getSimpleName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                //删除redis
                redisUtil.del(KylinRedisConst.PERFORMANCES + performanceIds);
                // 大龙相关 演出列表
                redisUtil.del(KylinRedisConst.PERFORMANCES_LIST_CITYNAME + vo.getCityName());
                redisUtil.del(KylinRedisConst.PERFORMANCES_LIST_RECOMMEND);
                redisUtil.del(KylinRedisConst.PERFORMANCES_ROADLIST + vo.getRoadShowId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("创建Vo异常");
        }
    }

    /**
     * @param performanceId 演出id
     * @param ticketId      票种id
     * @param buyCount      购买数量 大于 0 增加 小于 0 减少 对应 支付 退款表
     */
    public void changeBuyInfo(String userId, String idCard, String performanceId, String ticketId, int buyCount) {
        String redisKey;

        KylinPerformanceVo vo = getPerformanceVo(performanceId);
        int isTrueName = vo.getIsTrueName();
        int ticketType = 0;
        String useTime = "";
        HashMap<String, ArrayList<String>> allTicketId = new HashMap<>();
        for (int x = 0; x < vo.getTicketTimeList().size(); x++) {
            KylinTicketTimesVo timeItem = vo.getTicketTimeList().get(x);
            ArrayList<String> ticketList = new ArrayList<>();
            for (int y = 0; y < timeItem.getTicketList().size(); y++) {
                KylinTicketVo ticketItem = timeItem.getTicketList().get(y);
                if (ticketItem.getType() == 1) {
                    ticketList.add(ticketItem.getTicketsId());
                }
                if (ticketItem.getTicketsId().equals(ticketId)) {
                    useTime = ticketItem.getUseStart();
                    ticketType = ticketItem.getType();
                }
            }
            allTicketId.put(timeItem.getUseStart(), ticketList);
        }

        if (0 == isTrueName) {
            redisKey = KylinRedisConst.USERID_BUY_INFO + userId;
        } else {
            redisKey = KylinRedisConst.IDCARD_BUY_INFO + idCard;
        }
        String performanceIdKey = redisKey + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId;
        String ticketIdKey = redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId;
        String ticketUseTimeKey = ticketIdKey + ":" + KylinRedisConst.USE_TIME;
        redisUtil.set(ticketUseTimeKey, useTime);
        if (buyCount > 0) {
            redisUtil.incr(ticketIdKey, buyCount);
            if (1 == ticketType) {
                int count = 0;
                for (int i = 0; i < allTicketId.get(useTime).size(); i++) {
                    String item = allTicketId.get(useTime).get(i);
                    if (allTicketId.get(useTime).size() == 1) {
                        redisUtil.incr(performanceIdKey, buyCount);
                        break;
                    }
                    if (null == redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item)) {
                        redisUtil.set(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item, 0);
                    }
                    if (i == 0) {
                        count = (int) redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item);
                    } else {
                        if (count != (int) redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item)) {
                            redisUtil.incr(performanceIdKey, buyCount);
                            break;
                        }
                    }
                }
            } else {
                redisUtil.incr(performanceIdKey, buyCount);
            }
        } else {
            redisUtil.decr(ticketIdKey, Math.abs(buyCount));
            if (1 == ticketType) {
                int count = 0;
                for (int i = 0; i < allTicketId.get(useTime).size(); i++) {
                    String item = allTicketId.get(useTime).get(i);
                    if (allTicketId.get(useTime).size() == 1) {
                        redisUtil.decr(performanceIdKey, Math.abs(buyCount));
                        break;
                    }
                    if (null == redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item)) {
                        redisUtil.set(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item, 0);
                    }
                    if (i == 0) {
                        count = (int) redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item);
                    } else {
                        if (count != (int) redisUtil.get(redisKey + ":" + KylinRedisConst.TICKET_ID + ":" + item)) {
                            redisUtil.decr(performanceIdKey, Math.abs(buyCount));
                            break;
                        }
                    }
                }
            } else {
                redisUtil.decr(performanceIdKey, Math.abs(buyCount));
            }
        }
    }


    // 获取 用户维度 演出购买数量
    public int getUserPBuyCount(String userId, String performanceId) {
        try {
            return (int) redisUtil.get(KylinRedisConst.USERID_BUY_INFO + userId + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId);
        } catch (Exception e) {
            return 0;
        }
    }

    // 获取 用户维度 票种购买数量
    public int getUserTBuyCount(String userId, String ticketId) {
        try {
            return (int) redisUtil.get(KylinRedisConst.USERID_BUY_INFO + userId + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId);
        } catch (Exception e) {
            return 0;
        }
    }

    // 获取 证件维度 演出购买数量
    public int getIdCardPBuyCount(String idCard, String performanceId) {
        try {
            return (int) redisUtil.get(KylinRedisConst.USERID_BUY_INFO + idCard + ":" + KylinRedisConst.PERFORMANCE_ID + ":" + performanceId);
        } catch (Exception e) {
            return 0;
        }
    }

    // 获取 证件维度 票种购买数量
    public int getIdCardTBuyCount(String idCard, String ticketId) {
        try {
            return (int) redisUtil.get(KylinRedisConst.USERID_BUY_INFO + idCard + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId);
        } catch (Exception e) {
            return 0;
        }
    }

    // 获取 证件维度 票种适用时间
    public String getIdCardTUseTime(String idCard, String ticketId) {
        try {
            return (String) redisUtil.get(KylinRedisConst.USERID_BUY_INFO + idCard + ":" + KylinRedisConst.TICKET_ID + ":" + ticketId + ":" + KylinRedisConst.USE_TIME);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 删除订单redis
     *
     * @param orderEntitiesId
     */
    public void delOrderTicketEntitiesRedis(String orderEntitiesId) {
        redisUtil.del(KylinRedisConst.ORDER_ENTITIES + orderEntitiesId);
    }

    /**
     * 获取演出列表redis
     *
     * @param cityName
     */
    public List<KylinPerformanceVo> getPerformancesListOfcityName(String cityName) {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_CITYNAME.concat(cityName);
        if (!redisUtil.hasKey(redisKey)) {
            // 固定查询条件
            Query query = new Query();
            LocalDateTime nowTime = LocalDateTime.now();
            String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
            query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));
            // 其他条件
            Pattern cityNameCompile = Pattern.compile("^.*" + cityName + ".*$", Pattern.CASE_INSENSITIVE);
            query.addCriteria(Criteria.where("cityName").regex(cityNameCompile));
            // 排序
            Sort sortName = Sort.by(Sort.Direction.ASC, "timeStart");
            query.with(sortName);
            // 不要查询的字段
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            List<KylinPerformanceVo> performancesList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, performancesList);
        }
        return (List<KylinPerformanceVo>) redisUtil.get(redisKey);
    }

    /**
     * 删除演出列表redis
     *
     * @param cityName
     */
    public void delPerformancesListOfcityName(String cityName) {
        redisUtil.del(KylinRedisConst.ORDER_ENTITIES.concat(cityName));
    }

    /**
     * 获取推荐演出列表redis
     */
    public List<KylinPerformanceVo> getPerformancesListIsRecommend() {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_RECOMMEND;
        if (!redisUtil.hasKey(redisKey)) {
            // 固定条件
            Query query = new Query();
            LocalDateTime nowTime = LocalDateTime.now();
            String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
            query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));
            // 排序
            Sort sortName = Sort.by(Sort.Direction.ASC, "timeStart");
            query.with(sortName);
            // 不要查询的字段
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            // 推荐
            query.addCriteria(Criteria.where("isRecommend").is(1));
            List<KylinPerformanceVo> recommendList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, recommendList);
        }
        return (List<KylinPerformanceVo>) redisUtil.get(redisKey);
    }

    /**
     * 删除演出列表redis
     */
    public void delPerformancesListIsRecommend() {
        redisUtil.del(KylinRedisConst.PERFORMANCES_LIST_RECOMMEND);
    }

    /**
     * 获取所有城市演出列表redis
     */
    public List<KylinPerformanceVo> getPerformancesListAll() {
        List<KylinPerformanceVo> list = new ArrayList<>();
        Set<String> keys = redisTemplate.keys(KylinRedisConst.PERFORMANCES_LIST_ALL);
        for (String key : keys) {
            List<KylinPerformanceVo> OneCityList = (List<KylinPerformanceVo>) redisUtil.get(key);
            list.addAll(OneCityList);
        }
        return list;
    }

    /**
     * 获取巡演列表redis
     */
    public List<KylinPerformanceVo> getRoadList(String roadShowId) {
        String redisKey = KylinRedisConst.PERFORMANCES_ROADLIST.concat(roadShowId);
        if (!redisUtil.hasKey(redisKey)) {
            List<KylinPerformanceVo> roadList = mongoTemplate.find(
                    Query.query(Criteria.where("roadShowId").is(roadShowId)),
                    KylinPerformanceVo.class,
                    KylinPerformanceVo.class.getSimpleName()
            );
            redisUtil.set(redisKey, roadList);
        }
        return (List<KylinPerformanceVo>) redisUtil.get(redisKey);
    }

    /**
     * 删除巡演列表redis
     */
    public void delRoadList(String roadShowId) {
        redisUtil.del(KylinRedisConst.PERFORMANCES_ROADLIST.concat(roadShowId));
    }

}
