package com.liquidnet.service.kylin.utils;

import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dto.vo.express.KylinOrderExpressRouteVo;
import com.liquidnet.service.kylin.dto.vo.express.KylinOrderExpressVo;
import com.liquidnet.service.kylin.dto.vo.mongo.*;
import com.liquidnet.service.kylin.dto.vo.returns.KylinOrderListVo;
import com.liquidnet.service.kylin.dto.vo.returns.KylinOrderRefundsVo;
import com.liquidnet.service.kylin.entity.KylinOrderCoupons;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
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.stereotype.Component;

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

@Component
@Slf4j
public class DataUtils {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisUtil redisUtil;

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

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

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

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

    public List<KylinOrderListVo> getOrderList(String userId) {
        Object obj = redisUtil.get(KylinRedisConst.ORDER_LIST + userId);
        ;
        if (obj != null) {
            return (List<KylinOrderListVo>) obj;
        } 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 voList;
        }
    }

    /**
     * 根据订单id 获取 订单vo 详情
     *
     * @param orderId
     * @return
     */
    public KylinOrderTicketVo getOrderTicketVo(String orderId) {
        Object obj = redisUtil.get(KylinRedisConst.ORDER + orderId);
        if (obj != null) {
            return (KylinOrderTicketVo) obj;
        } 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 ticketData;
        }
    }

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


    /**
     * 获取 验票账号关系 vo
     *
     * @param checkUserId
     * @return
     */
    public KylinCheckUserPerformanceVo getCheckUserRelationVo(String checkUserId) {
        Object obj = redisUtil.get(KylinRedisConst.CHECK_USER_RELATION + checkUserId);
        if (obj != null) {
            return (KylinCheckUserPerformanceVo) obj;
        } 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 ticketData;
        }
    }

    /**
     * 获取入场须知
     * 11：音乐节电子票实名 12：音乐节快递票实名 13音乐节电子票非实名 14音乐节快递票非实名 15：音乐节电子学生票实名 16：音乐节快递学生票实名 17音乐节电子学生票非实名 18音乐节快递学生票非实名
     * 21：巡演电子票实名 22：巡演快递票实名 23巡演电子票非实名 24巡演快递票非实名 25：巡演电子学生票实名 26：巡演快递学生票实名 27巡演电子学生票非实名 28巡演快递学生票非实名
     *
     * @param type       类型：101音乐节 102小型演出(livehouse演出) 103巡演
     * @param ticketType 票种类型：电子票electronic快递票express
     * @param isStudent  是否学生票：0否1是
     * @param isTrueName 是否实名：0否1是
     * @return
     */
    public String getEnterInfo(int type, String ticketType, Integer isStudent, Integer isTrueName) {
        String redisKey = KylinRedisConst.ENTER_INFO.concat(":type:" + type).concat(":ticketType:" + ticketType).concat(":isStudent:" + isStudent).concat(":isTrueName:" + isTrueName);
        Object obj = redisUtil.get(redisKey);
        if (obj != null) {
            return (String) obj;
        } else {
            String content = "";
            if (type == 101) {
                content = content.concat("音乐节");
            } else if (type == 102) {
                content = content.concat("巡演");
            } else if (type == 103) {
                content = content.concat("巡演");
            }

            if (isStudent == 0) {
                if (ticketType.equalsIgnoreCase("electronic")) {
                    content = content.concat("电子票");
                } else if (ticketType.equalsIgnoreCase("express")) {
                    content = content.concat("快递票");
                }
            } else if (isStudent == 1) {
                if (ticketType.equalsIgnoreCase("electronic")) {
                    content = content.concat("电子学生票");
                } else if (ticketType.equalsIgnoreCase("express")) {
                    content = content.concat("快递学生票");
                }
            }

            if (isTrueName == 0) {
                content = content.concat("非实名");
            } else if (isTrueName == 1) {
                content = content.concat("实名");
            }

            redisUtil.set(redisKey, content);
            return content;
        }
    }


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

    /**
     * 根据演出id 获取 演出vo 详情
     *
     * @param performanceId
     * @return
     */
    public KylinPerformanceVo getPerformanceVo(String performanceId) {
        Object obj = redisUtil.get(KylinRedisConst.PERFORMANCES + performanceId);
        if (obj != null) {
            return (KylinPerformanceVo) obj;
        } else {
            KylinPerformanceVo performanceData = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(KylinRedisConst.PERFORMANCES + performanceId, performanceData);
            return performanceData;
        }
    }

    /**
     * 获取分销用户名字
     *
     * @param agentId
     * @return
     */
    public String getAgentInfoName(String agentId) {
        String redisKey = KylinRedisConst.PERFORMANCES_AGENT_INFO.concat(agentId);
        String name = (String) redisUtil.getDB15RedisHGet(redisKey, "name");
//        String name = "";
        return name;
    }

    /**
     * 获取演出列表redis
     *
     * @param cityName
     */
    public List<KylinPerformanceVo> getPerformancesListOfcityName(String cityName) {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_CITYNAME.concat(cityName);
        Object object = redisUtil.get(redisKey);

        if (object == null) {
            // 固定查询条件
            Query query = getCommonWhere();
            // 其他条件
            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");
            query.fields().exclude("describeElectronic");
            List<KylinPerformanceVo> performancesList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, performancesList);
            return performancesList;
        }
        return (List<KylinPerformanceVo>) object;
    }

    /**
     * 获取系统推荐演出列表redis
     */
    public List<KylinPerformanceVo> getPerformancesListIsSystemRecommend() {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_SYSTEM_RECOMMEND;
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            // 固定条件
            Query query = getCommonWhere();
            // 排序
            Sort sortName = Sort.by(Sort.Direction.ASC, "timeStart");
            Pageable pageable = PageRequest.of(0, 8, sortName);
            query.with(pageable);
            // 不要查询的字段
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            query.fields().exclude("describeElectronic");
            // 推荐
            List<KylinPerformanceVo> systemRecommendList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, systemRecommendList);
            return systemRecommendList;
        }
        return (List<KylinPerformanceVo>) obj;
    }

    /**
     * 获取演出预告列表redis
     */
    public HashMap<String, Object> getPerformancesListNotice() {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_NOTICE;
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            // 固定条件
            Query query = getCommonWhere();

            // 今天的
            HashMap toDayTime = DateUtil.oneDayStartEnd();
            String nowTimeTStr = (String) toDayTime.get("startStr");
            String toDayEndTimeStr = (String) toDayTime.get("endStr");
            query.addCriteria(Criteria.where("sellTime").gte(nowTimeTStr).lt(toDayEndTimeStr));
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            query.fields().exclude("describeElectronic");
            List<KylinPerformanceVo> toDayList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

            // 固定条件
            Query queryT = getCommonWhere();

            // 三天的
            Calendar cal = Calendar.getInstance();
            cal.setTime((Date) toDayTime.get("end"));
            Date beforeDayEnd = DateUtil.getBeforeDayEnd(cal, 3);
            String threeDaysLaterStr = DateUtil.SDF_YMD_HMS.format(beforeDayEnd);

            queryT.addCriteria(Criteria.where("sellTime").gte(toDayEndTimeStr).lt(threeDaysLaterStr));
            queryT.fields().exclude("details");
            queryT.fields().exclude("noticeImage");
            queryT.fields().exclude("ticketTimeList");
            queryT.fields().exclude("describeElectronic");
            List<KylinPerformanceVo> threeDaysList = mongoTemplate.find(queryT, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

            HashMap<String, Object> info = CollectionUtil.mapStringObject();
            info.put("toDayList", toDayList);
            info.put("threeDaysList", threeDaysList);
            redisUtil.set(redisKey, info);
            return info;
        }
        return (HashMap<String, Object>) obj;
    }

    /**
     * 获取推荐演出列表redis
     */
    public List<KylinPerformanceVo> getPerformancesListIsRecommend() {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_RECOMMEND;
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            // 固定条件
            Query query = getCommonWhere();
            // 排序
            Sort sortName = Sort.by(Sort.Direction.DESC, "isRecommend");
            query.with(sortName);
            // 不要查询的字段
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            query.fields().exclude("describeElectronic");
            // 推荐
            query.addCriteria(Criteria.where("isRecommend").gte(1));
            List<KylinPerformanceVo> recommendList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, recommendList);
            return recommendList;
        }
        return (List<KylinPerformanceVo>) obj;
    }

    /**
     * 获取会员专属演出列表redis
     */
    public List<KylinPerformanceVo> getPerformancesListIsExclusive() {
        String redisKey = KylinRedisConst.PERFORMANCES_LIST_EXCLUSIVE;
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            // 固定条件
            Query query = getCommonWhere();
            // 不要查询的字段
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");
            query.fields().exclude("ticketTimeList");
            query.fields().exclude("describeElectronic");
            // 推荐
            query.addCriteria(Criteria.where("isExclusive").is(1));
            List<KylinPerformanceVo> exclusiveList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            redisUtil.set(redisKey, exclusiveList);
            return exclusiveList;
        }
        return (List<KylinPerformanceVo>) obj;
    }

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

    /**
     * 演出搜索固定参数
     */
    public Query getCommonWhere() {
        // 固定条件
        Query query = new Query();
        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));
        query.addCriteria(Criteria.where("appStatus").in(6, 8, 9, 10));
        query.addCriteria(Criteria.where("isShow").is(1));
        return query;
    }

    public KylinOrderRefundsVo getOrderRefundVo(String orderRefundsId) {
        Object obj = redisUtil.get(KylinRedisConst.ORDER_REFUND + orderRefundsId);
        if (obj != null) {
            return (KylinOrderRefundsVo) obj;
        } else {
            KylinOrderRefundsVo orderRefundsVo = mongoTemplate.findOne(Query.query(Criteria.where("orderRefundsId").is(orderRefundsId)), KylinOrderRefundsVo.class, KylinOrderRefundsVo.class.getSimpleName());
            List<KylinOrderRefundEntitiesVo> kylinOrderTicketEntitiesVoList = mongoTemplate.find(Query.query(Criteria.where("orderRefundsId").is(orderRefundsId)), KylinOrderRefundEntitiesVo.class, KylinOrderRefundEntitiesVo.class.getSimpleName());
            List<KylinOrderRefundPicVo> picVos = mongoTemplate.find(Query.query(Criteria.where("orderRefundsId").is(orderRefundsId)), KylinOrderRefundPicVo.class, KylinOrderRefundPicVo.class.getSimpleName());
            orderRefundsVo.setOrderRefundEntitiesVoList(kylinOrderTicketEntitiesVoList);
            orderRefundsVo.setOrderRefundPicVos(picVos);
            redisUtil.set(KylinRedisConst.ORDER_REFUND + orderRefundsId, orderRefundsVo);
            return orderRefundsVo;
        }
    }

    public List<KylinOrderRefundsVo> getOrderRefundVoByOrderId(String orderId) {
        Object obj = redisUtil.get(KylinRedisConst.ORDER_REFUND_BY_ORDER_ID + orderId);
        if (obj != null) {
            return (List<KylinOrderRefundsVo>) obj;
        } else {
            List<KylinOrderRefundsVo> orderRefundsVoList = ObjectUtil.getKylinOrderRefundsVoArrayList();
            List<KylinOrderRefundsVo> data = mongoTemplate.find(Query.query(Criteria.where("orderTicketsId").is(orderId)), KylinOrderRefundsVo.class, KylinOrderRefundsVo.class.getSimpleName());
            for (KylinOrderRefundsVo item : data) {
                List<KylinOrderRefundEntitiesVo> kylinOrderTicketEntitiesVoList = mongoTemplate.find(Query.query(Criteria.where("orderRefundsId").is(item.getOrderRefundsId())), KylinOrderRefundEntitiesVo.class, KylinOrderRefundEntitiesVo.class.getSimpleName());
//                if(kylinOrderTicketEntitiesVoList.size()>1){
//                    continue;
//                }
                item.setOrderRefundEntitiesVoList(kylinOrderTicketEntitiesVoList);
                List<KylinOrderRefundPicVo> picVos = mongoTemplate.find(Query.query(Criteria.where("orderRefundsId").is(item.getOrderRefundsId())), KylinOrderRefundPicVo.class, KylinOrderRefundPicVo.class.getSimpleName());
                item.setOrderRefundPicVos(picVos);
                orderRefundsVoList.add(item);
            }
            redisUtil.set(KylinRedisConst.ORDER_REFUND_BY_ORDER_ID + orderId, orderRefundsVoList);
            return orderRefundsVoList;
        }
    }

    public void delOrderRefundVo(String orderRefundsId) {
        redisUtil.del(KylinRedisConst.ORDER_REFUND + orderRefundsId);
    }

    public void delOrderRefundVoByOrderId(String orderId) {
        redisUtil.del(KylinRedisConst.ORDER_REFUND_BY_ORDER_ID + orderId);
    }

    /**
     * 获取可退款票单价格
     *
     * @param orderTicketVo         订单vo数据
     * @param orderTicketEntitiesId 票单id
     * @return
     */
    public BigDecimal getCanRefundOrderEntitiesPrice(KylinOrderTicketVo orderTicketVo, List<KylinOrderRefundsVo> kylinOrderRefundsVoBaseList, String orderTicketEntitiesId) {
        log.info("orderTicketEntitiesId = " + orderTicketEntitiesId);
        //单票实付价格
        BigDecimal singlePrice = orderTicketVo.getPriceActual().subtract(orderTicketVo.getPriceExpress()).divide(BigDecimal.valueOf(orderTicketVo.getNumber()));
        log.info("singlePrice = " + singlePrice);
        //单票剩余未退款金额
        BigDecimal canRefundSinglePrice = new BigDecimal("0.00");
        for (KylinOrderTicketEntitiesVo item : orderTicketVo.getEntitiesVoList()) {
            if (item.getOrderTicketEntitiesId().equals(orderTicketEntitiesId)) {
                log.info("item = " + item);
                canRefundSinglePrice = singlePrice.subtract(item.getRefundPrice() == null ? BigDecimal.valueOf(0.00) : item.getRefundPrice());
            }
        }
        log.info("canRefundSinglePrice = " + canRefundSinglePrice);
        //订单锁定金额
        BigDecimal orderLockPrice = new BigDecimal("0.00");
        for (KylinOrderRefundsVo refundVo : kylinOrderRefundsVoBaseList) {
            int status = refundVo.getStatus();
            if (status == 0 || status == 1 || status == 3 || status == 6 || status == 7 || status == 8) { //退款流程未完成 金额锁定
                List<KylinOrderRefundEntitiesVo> refundEntitiesVos = refundVo.getOrderRefundEntitiesVoList();
                for (KylinOrderRefundEntitiesVo refundEntitiesVo : refundEntitiesVos) {
                    if (refundEntitiesVo.getOrderTicketEntitiesId().equals(orderTicketEntitiesId)) {
                        orderLockPrice = orderLockPrice.add(refundEntitiesVo.getRefundPrice());
                    }
                }
            }
        }
        log.info("orderLockPrice = " + orderLockPrice);
        //订单可退金额
        BigDecimal refundSinglePrice = canRefundSinglePrice.subtract(orderLockPrice);
        //是否包含快递费
        if (orderTicketVo.getPriceActual().subtract(orderTicketVo.getPriceExpress()).subtract(orderTicketVo.getPriceRefund()).compareTo(canRefundSinglePrice) == 0) {
            refundSinglePrice = refundSinglePrice.add(orderTicketVo.getPriceExpress());
        }
        return refundSinglePrice;
    }

    /**
     * 获取演出订单快递状态
     */
    public Integer getOrderExpressInfo(String orderId) {
        String redisKey = KylinRedisConst.ORDER_EXPRESS_INFO.concat(orderId);
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            return 1;
        } else {
            KylinOrderExpressVo expressInfo = (KylinOrderExpressVo) obj;
            return expressInfo.getExpressStatus();
        }
    }

    public Integer getSwitch() {
        Integer i = (Integer) redisUtil.get(AdamRedisConst.SWITCH_BUY_MEMBER);
        return null == i ? 1 : i;
    }

    /**
     * 演出订单快递路由
     */
    public LinkedList<KylinOrderExpressRouteVo> getOrderExpressRoute(String orderTicketsId) { // 获取
        String redisKey = KylinRedisConst.ORDER_ROUTE_INFO.concat(orderTicketsId);
        LinkedList<KylinOrderExpressRouteVo> list = (LinkedList<KylinOrderExpressRouteVo>) redisUtil.get(redisKey);
        if (null == list || CollectionUtil.isEmpty(list)) {
            list = new LinkedList<>();
        }
        return list;
    }

    public KylinOrderExpressVo getOrderExpressInfos(String orderId) {
        String redisKey = KylinRedisConst.ORDER_EXPRESS_INFO.concat(orderId);
        return (KylinOrderExpressVo) redisUtil.get(redisKey);
    }

    // 获取订单券的使用情况
    public ArrayList<KylinOrderCoupons> getOrderCoupon(String orderId){
        String redisKey = KylinRedisConst.ORDER_COUPON.concat(orderId);
        Object obj = redisUtil.get(redisKey);
        if (obj == null) {
            return new ArrayList();
        } else {
            return (ArrayList<KylinOrderCoupons>) obj;
        }
    }

}
