package com.liquidnet.service.kylin.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.liquidnet.commons.lang.CommonConst;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.UserPathDto;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.NoticeGoblinMixDetailsVo;
import com.liquidnet.service.goblin.dto.vo.SmileUserVO;
import com.liquidnet.service.kylin.constant.KylinPerformanceStatusEnum;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dto.param.KylinCandyItemParam;
import com.liquidnet.service.kylin.dto.param.KylinPerformanceSubscribeParam;
import com.liquidnet.service.kylin.dto.vo.KylinPerformanceSubscribeUpushVo;
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.KylinCandyVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketExpressModuleVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketPartnerVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketTimesPartnerVo;
import com.liquidnet.service.kylin.dto.vo.returns.PayDetailVo;
import com.liquidnet.service.kylin.service.IKylinPerformancesService;
import com.liquidnet.service.kylin.utils.DataUtils;
import com.liquidnet.service.kylin.utils.ObjectUtil;
import com.liquidnet.service.kylin.utils.QueueUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端 演出 服务实现类
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-05-11
 */
@Service
@Slf4j
public class KylinPerformancesServiceImpl implements IKylinPerformancesService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private DataUtils dataUtils;
    @Autowired
    private QueueUtils queueUtils;

    @Value("${liquidnet.service.smile.url}")
    private String smileUrl;

    public HashMap<String, Object> localList(
            int days, String cityName, Integer adCode, int type,
            Integer isDiscount, Integer isAdvance, Integer isExclusive,
            String orderBy, String sort
    ) {
        List<KylinPerformanceVo> performancesList = dataUtils.getPerformancesListOfcityNameOradCode(cityName, adCode);

        // 是否启用推荐
        Integer isRecommend = 1;

        // 判断搜索 处理新数据
        List<KylinPerformanceVo> performancesListNew = ObjectUtil.getKylinPerformanceVoArrayList();
        List<String> performancesIds = CollectionUtil.arrayListString();
        for (KylinPerformanceVo info : performancesList) {
            boolean isShow = true;
            if (type > 0) {
                isRecommend = 0;
                if (info.getType() != type) {
                    isShow = false;
                }
            }
            if (null != isExclusive || null != isDiscount || null != isAdvance) {
                isRecommend = 0;
                if (info.getIsExclusive() != isExclusive && info.getIsDiscount() != isDiscount && info.getIsAdvance() != isAdvance) {
                    isShow = false;
                }
            }
            if (days > 0) {
                isRecommend = 0;

                HashMap toDayTime = DateUtil.oneDayStartEnd();
                String nowTimeTStr = (String) toDayTime.get("startStr");

                String timeStart = info.getTimeStart();

                // 今天的0点到几天后的0点
                Calendar cal = Calendar.getInstance();
                cal.setTime((Date) toDayTime.get("start"));
                Date beforeDayEnd = DateUtil.getBeforeDayBegin(cal, days);
                String daysLaterStr = DateUtil.SDF_YMD_HMS.format(beforeDayEnd);
                if (-1 == DateUtil.compareStrDay(timeStart, nowTimeTStr) || -1 == DateUtil.compareStrDay(daysLaterStr, timeStart)) {
                    isShow = false;
                }
            }
            if (isShow) {
                performancesIds.add(info.getPerformancesId());
                performancesListNew.add(info);
            }
        }


        // 推荐
        int is_native = 1;
        int recommend = performancesListNew.size();
        if (recommend <= 2 && 1 == isRecommend) {
            List<KylinPerformanceVo> performancesListRecommend = dataUtils.getPerformancesListIsSystemRecommend();

            if (!CollectionUtils.isEmpty(performancesListRecommend)) {
                is_native = 0;
                if (recommend > 0) {// 去重
                    List<KylinPerformanceVo> collect = performancesListRecommend.stream().filter(r -> !performancesIds.contains(r.getPerformancesId())).collect(Collectors.toList());
                    performancesListNew.addAll(collect);
                } else {
                    performancesListNew.addAll(performancesListRecommend);
                }
            }
        }
        performancesListNew = checkAppStatus(performancesListNew);

        // 组合数据
        HashMap<String, Object> info = CollectionUtil.mapStringObject();
        info.put("is_native", is_native); // 本地演出少是否推荐了其他演出 0有推荐 1没有
        info.put("recommend", recommend); // 从第几个开始是其他推荐演出 后台设置的那个推荐
        info.put("total", 0);
        info.put("list", performancesListNew);

        log.info(UserPathDto.setData("本地演出列表", "cityName=" + cityName + " type=" + type + " isDiscount=" + isDiscount + " isAdvance =" + isAdvance + " isExclusive=" + isExclusive + " days=" + days, info));
        return info;
    }

    public HashMap<String, Object> noticeList(Integer type) {
        /*if (-1 != DateUtil.compareStrDay(timeStart, toDayEndTimeStr) && -1 == DateUtil.compareStrDay(timeStart, threeDaysLaterStr)) {
            threeDaysList.add(info);
        }*/
        HashMap<String, Object> performancesListNotice = dataUtils.getPerformancesListNotice();
        List<KylinPerformanceVo> toDayList = (List<KylinPerformanceVo>) performancesListNotice.get("toDayList");
        List<KylinPerformanceVo> threeDaysList = (List<KylinPerformanceVo>) performancesListNotice.get("threeDaysList");
        List<GoblinGoodsSkuInfoVo> toDaysNftList = (List<GoblinGoodsSkuInfoVo>) performancesListNotice.get("toDaysNftList");
        List<GoblinGoodsSkuInfoVo> threeDayNftList = (List<GoblinGoodsSkuInfoVo>) performancesListNotice.get("threeDayNftList");
        List<NoticeGoblinMixDetailsVo> toDayCombinationList = (List<NoticeGoblinMixDetailsVo>) performancesListNotice.get("toDayCombinationList");
        List<NoticeGoblinMixDetailsVo> threeDayCombinationList = (List<NoticeGoblinMixDetailsVo>) performancesListNotice.get("threeDayCombinationList");
        /*List<NoticeGoblinGoodsSkuInfoVo> toDaysNftList = (List<NoticeGoblinGoodsSkuInfoVo>) performancesListNotice.get("toDaysNftList");
        List<NoticeGoblinGoodsSkuInfoVo> threeNftList = (List<NoticeGoblinGoodsSkuInfoVo>) performancesListNotice.get("threeNftList");
        List<NoticeGoblinMixDetailsVo> toDayCombinationList = (List<NoticeGoblinMixDetailsVo>) performancesListNotice.get("toDayCombinationList");
        List<NoticeGoblinMixDetailsVo> threeDayCombinationList = (List<NoticeGoblinMixDetailsVo>) performancesListNotice.get("threeDayCombinationList");*/

        toDayList = checkAppStatus(toDayList);
        threeDaysList = checkAppStatus(threeDaysList);
        if (null != type && type > 0) {
            toDayList = mergeRoadList(toDayList);
            threeDaysList = mergeRoadList(threeDaysList);
        }

        HashMap<String, Object> newList = CollectionUtil.mapStringObject();
        newList.put("toDayList", toDayList);
        newList.put("threeDaysList", threeDaysList);
        newList.put("toDaysNftList", toDaysNftList);
        newList.put("threeDayNftList", threeDayNftList);
        newList.put("toDayCombinationList", toDayCombinationList);
        newList.put("threeDayCombinationList", threeDayCombinationList);
        return newList;
    }

    public HashMap<String, Object> noticeListOld(Integer type) {
        /*if (-1 != DateUtil.compareStrDay(timeStart, toDayEndTimeStr) && -1 == DateUtil.compareStrDay(timeStart, threeDaysLaterStr)) {
            threeDaysList.add(info);
        }*/
        HashMap<String, Object> performancesListNotice = dataUtils.getPerformancesListNoticeOld();
        List<KylinPerformanceVo> toDayList = (List<KylinPerformanceVo>) performancesListNotice.get("toDayList");
        List<KylinPerformanceVo> threeDaysList = (List<KylinPerformanceVo>) performancesListNotice.get("threeDaysList");
        List<GoblinGoodsSkuInfoVo> toDaysNftList = ObjectUtil.getGoblinGoodsSkuInfoVoList();
        List<GoblinGoodsSkuInfoVo> threeDayNftList = ObjectUtil.getGoblinGoodsSkuInfoVoList();
        List<NoticeGoblinMixDetailsVo> toDayCombinationList = ObjectUtil.getNoticeGoblinMixDetailsVoList();
        List<NoticeGoblinMixDetailsVo> threeDayCombinationList = ObjectUtil.getNoticeGoblinMixDetailsVoList();

        toDayList = checkAppStatus(toDayList);
        threeDaysList = checkAppStatus(threeDaysList);
        if (null != type && type > 0) {
            toDayList = mergeRoadList(toDayList);
            threeDaysList = mergeRoadList(threeDaysList);
        }

        HashMap<String, Object> newList = CollectionUtil.mapStringObject();
        newList.put("toDayList", toDayList);
        newList.put("threeDaysList", threeDaysList);
        newList.put("toDaysNftList", toDaysNftList);
        newList.put("threeDayNftList", threeDayNftList);
        newList.put("toDayCombinationList", toDayCombinationList);
        newList.put("threeDayCombinationList", threeDayCombinationList);
        newList.put("isVip", isVip());
        return newList;
    }

    private Integer isVip() {
        final String currentUid = CurrentUtil.getCurrentUid();
        if (!StringUtils.isBlank(currentUid)) {
            try {
                return dataUtils.isMemberByUser(currentUid);
            } catch (Exception e) {
                log.error("获取用户会员状态错误。", e);
            }
        }
        return 0;
    }

    public HashMap<String, Object> setNoticeIds() {
        return dataUtils.setNoticeIds();
    }

    private List<KylinPerformanceVo> mergeRoadList(List<KylinPerformanceVo> performanceList) {
        List<String> roadIdList = new ArrayList<>();
        List<KylinPerformanceVo> newList = ObjectUtil.getKylinPerformanceVoArrayList();
        for (KylinPerformanceVo info : performanceList) {
            String roadShowId = info.getRoadShowId();
            if (null != roadShowId && !roadShowId.isEmpty() && !roadShowId.equals("0")) {
                if (!roadIdList.contains(info.getRoadShowId())) {
                    newList.add(info);
                    roadIdList.add(roadShowId);
                }
            } else if (roadShowId.equals("0")) {
                newList.add(info);
            }
        }
        return newList;
    }

    public List<KylinPerformanceVo> recommendList() {
        List<KylinPerformanceVo> performancesListRecommend = dataUtils.getPerformancesListIsRecommend();
        performancesListRecommend = checkAppStatus(performancesListRecommend);
        return performancesListRecommend;
    }

    public List<KylinPerformanceVo> exclusiveList() {
        List<KylinPerformanceVo> performancesListExclusive = dataUtils.getPerformancesListIsExclusive();
        performancesListExclusive = checkAppStatus(performancesListExclusive);
        return performancesListExclusive;
    }

    public KylinPerformanceVo detail(String performancesId, double latitudeFrom, double longitudeFrom, String agentId) {
        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        if (null == performancesInfo) {
            return null;
        }
        String uid = CurrentUtil.getCurrentUid();
        //记录演出详情浏览次数
        queueUtils.pushPvUv(uid, KylinTableStatusConst.PvUv.TK_DETAILS.getKey(), performancesId, null, null, CurrentUtil.getCliIpAddr());
        if (StringUtil.isNotEmpty(agentId)) {
            try {
                MultiValueMap<String, String> params = new LinkedMultiValueMap();
                params.add("userId", agentId);
                MultiValueMap<String, String> headers = CollectionUtil.linkedMultiValueMapStringString();
                headers.add("Accept", "application/json;charset=UTF-8");
                String returnData = HttpUtil.post(smileUrl + "/smile/frontNoLogin/getUserById", params, headers);
                ResponseDto<SmileUserVO> responseDto = JsonUtils.fromJson(returnData, new TypeReference<ResponseDto<SmileUserVO>>() {
                });
                String agentName = responseDto.getData().getName();
                performancesInfo.setAgentName(agentName);
                Integer state = responseDto.getData().getState();
                performancesInfo.setState(state);
            } catch (Exception e) {
                log.error("演出详情 获取小家伙名称异常 eMsg:{}", e.getMessage());
                performancesInfo.setAgentName("");
            }
        }

        try {
            performancesInfo = checkAppStatusInfo(performancesInfo);
            performancesInfo.setMessage(KylinPerformanceStatusEnum.getName(performancesInfo.getAppStatus()));
        } catch (Exception e) {
            log.error(" ERROR PERFORMANCE DETAILS PERFORMANCE_ID : " + performancesId);
        }

        // 处理距离
        if (longitudeFrom != CommonConst.DFT_DOUBLE_VAL) {
            try {
                String diffDistance = DistanceUtil.getDistance(longitudeFrom, latitudeFrom, Double.parseDouble(performancesInfo.getLongitude()), Double.parseDouble(performancesInfo.getLatitude()));
                performancesInfo.setDiffDistance(diffDistance);
            } catch (Exception e) {
                log.error("演出详情 经纬度处理距离异常 e:{}", e);
            }
        }

        log.info(UserPathDto.setData("演出详情", "performancesId=" + performancesId + " latitudeFrom=" + latitudeFrom + " longitudeFrom=" + longitudeFrom, performancesInfo));
        //默认普通用户
        performancesInfo.setIsVip(0);
        //判断当前用户是否预约演出
        if (!StringUtils.isEmpty(uid)) {
            performancesInfo.setIsSubscribe(dataUtils.getPerformanceSubscribe(uid, performancesInfo.getPerformancesId()));
            //判断是否是vip用户
            performancesInfo.setIsVip(dataUtils.isMemberByUser(uid));
        }
        performancesInfo.setIsInvoiceReminder(dataUtils.getPerformanceInvoiceReminder(performancesId));
        return performancesInfo;
    }

    public List<KylinPerformanceVo> roadList(String roadShowId) {
        List<KylinPerformanceVo> performancesList = dataUtils.getRoadList(roadShowId);
        performancesList = checkAppStatusRoad(performancesList);
        for (KylinPerformanceVo item : performancesList) {
            item.setPIsAgent();
        }
        return performancesList;
    }

    public HashMap<String, Object> ticketTimesPartner(String performancesId, Integer isAgent) {
        KylinPerformanceVo vo = dataUtils.getPerformanceVo(performancesId);
        if (null == vo) {
            return null;
        }
        vo = checkAppStatusInfo(vo);
        //记录票种选择详情页
        queueUtils.pushPvUv(CurrentUtil.getCurrentUid(), KylinTableStatusConst.PvUv.TK_TICKET.getKey(), performancesId, null, null, CurrentUtil.getCliIpAddr());
        List<KylinTicketTimesVo> ticketTimesList = vo.getTicketTimeList();
        if (null != ticketTimesList) {

            for (int i = 0; i < ticketTimesList.size(); i++) {
                KylinTicketTimesVo partner = ticketTimesList.get(i);
                List<KylinTicketVo> ticketList = partner.getTicketList();
                List<KylinTicketVo> ticketListNew = ObjectUtil.getKylinTicketVoArrayList();
                for (KylinTicketVo ticket : ticketList) {
                    int status = checkTicketStatus(ticket);
                    ticket.setStatus(status);

                    int statusExchange = checkTicketStatusExchange(ticket);
                    ticket.setStatusExchange(statusExchange);

                    // 会员状态
                    Integer isMemberStatus = getIsMemberStatus(ticket);
                    ticket.setIsMemberStatus(isMemberStatus);
                    if (null == isAgent || 0 == isAgent) {
                        ticketListNew.add(ticket);
                    } else if (1 >= isAgent) {
                        if (1 == ticket.getIsAgent()) {
                            ticketListNew.add(ticket);
                        }
                    }
                }
                partner.setTicketList(ticketListNew);
                if (ticketListNew.size() == 0) {
                    ticketTimesList.remove(i);
                    i--;
                }
            }
        }

        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        HashMap<String, Object> info = CollectionUtil.mapStringObject();
        info.put("city_name", performancesInfo.getCityName());
        info.put("field_name", performancesInfo.getFieldName());
        info.put("title", performancesInfo.getTitle());
        info.put("appStatus", performancesInfo.getAppStatus());
        info.put("imgPoster",performancesInfo.getImgPoster());
        info.put("fieldName",performancesInfo.getFieldName());
        info.put("longitude",performancesInfo.getLongitude());
        info.put("latitude",performancesInfo.getLatitude());
        HashMap<String, Object> result = CollectionUtil.mapStringObject();
        result.put("performancesInfo", info);
        result.put("ticketTimesList", ticketTimesList);

        return result;
    }

    public List<KylinPerformanceVo> performanceList(String... performancesIds) {
        List<KylinPerformanceVo> performanceList = ObjectUtil.getKylinPerformanceVoArrayList();
        for (String id : performancesIds) {
            KylinPerformanceVo info = dataUtils.getPerformanceVo(id);
            performanceList.add(info);
        }
        performanceList = checkAppStatus(performanceList);
        return performanceList;
    }

    public List performanceCalendar(String yearMonth, String cityName, Integer adCode) {
        List<KylinPerformanceVo> performancesList = dataUtils.getPerformancesListOfcityNameOradCode(cityName, adCode);

        // 获取此月开始结束时间
        String[] split = yearMonth.split("-");
        String monthStart = "";
        if (split.length > 2) {
            monthStart = DateUtil.getMonthFirst(split[0].concat("-").concat(split[1]));
        } else {
            monthStart = DateUtil.getMonthFirst(yearMonth);
        }
        String monthEnd = "";
        monthEnd = DateUtil.getMonthLast(monthStart);

        List date = new ArrayList();
        for (KylinPerformanceVo info : performancesList) {
            String timeStart = info.getTimeStart();
            if (-1 != DateUtil.compareStrDay(timeStart, monthStart) && 1 != DateUtil.compareStrDay(timeStart, monthEnd)) {
                String[] timeStartArr = timeStart.split(" ");
                date.add(timeStartArr[0]);
            }
        }
        //  去重
        List newList = (List) date.stream().distinct().collect(Collectors.toList());

        return newList;
    }

    public List calendarPerformances(String yearMonthDay, String cityName, Integer adCode) {
        List<KylinPerformanceVo> performancesList = dataUtils.getPerformancesListOfcityNameOradCode(cityName, adCode);

        String yearMonthDayStart = yearMonthDay.concat(" 00:00:00");
        String yearMonthDayEnd = yearMonthDay.concat(" 23:59:59");

        List<KylinPerformanceVo> performancesListNew = ObjectUtil.getKylinPerformanceVoArrayList();
        for (KylinPerformanceVo info : performancesList) {
            String timeStart = info.getTimeStart();
            if (-1 != DateUtil.compareStrDay(timeStart, yearMonthDayStart) && 1 != DateUtil.compareStrDay(timeStart, yearMonthDayEnd)) {
                performancesListNew.add(info);
            }
        }

        performancesListNew = checkAppStatus(performancesListNew);

        return performancesListNew;
    }

    public HashMap performancesSearch(String title, int page, int size) {
        Document queryObject = new Document();
        queryObject.put("title", Pattern.compile(title, Pattern.CASE_INSENSITIVE));
        Query query = new BasicQuery(queryObject);
        /*String nowTimeStr = DateUtil.getNowTime();
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));*/
        query.addCriteria(Criteria.where("appStatus").in(6, 8, 9, 10));
        query.addCriteria(Criteria.where("isShow").is(1));

        long count = mongoTemplate.count(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        query.fields().exclude("details");
        query.fields().exclude("noticeImage");
        query.fields().exclude("ticketTimeList");

        Sort sortName = Sort.by(Sort.Direction.DESC, "timeStart");
        Pageable pageable = PageRequest.of(page - 1, size, sortName);
        query.with(pageable);

        List<KylinPerformanceVo> list = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        // 这里不需要剔除一些数据 所以不能调用公共方法 可优化
        if (!CollectionUtils.isEmpty(list)) {
            String nowTimeStr = DateUtil.getNowTime();
            for (KylinPerformanceVo info : list) {
                // 当前时间大于停售时间 小于结束时间 是 停售
                String stopSellTime = info.getStopSellTime();
                String timeEnd = info.getTimeEnd();
                Integer isEnd = DateUtil.compareStrDay(nowTimeStr, timeEnd);
                if (1 == DateUtil.compareStrDay(nowTimeStr, stopSellTime) && -1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) {
                    info.setAppStatus(11);
                }

                // 票状态 3预览 6票可购买 8售罄 9未开始 10结束 11停售
                if (3 != info.getAppStatus() && info.getAppStatus() != 8 && info.getAppStatus() != 11 && 7 != info.getAppStatus() && 1 != isEnd) { // 个别状态无需再判断
                    String sellTime = info.getSellTime();
                    if (1 == DateUtil.compareStrDay(sellTime, nowTimeStr)) {// 未开始
                        info.setAppStatus(9);
                        int isMemberStatus = getPerformanceIsMemberStatus(info);
                        if (1 == isMemberStatus) {
                            info.setAppStatus(6);
                        }
                    } else { // 已开始
                        info.setAppStatus(6);
                        if (1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) { // 演出已结束
                            info.setAppStatus(10);
                        }
                    }
                }
            }
        }

        HashMap<String, Object> info = CollectionUtil.mapStringObject();
        info.put("total", count);
        info.put("list", list);

        log.info(UserPathDto.setData("演出搜索", "title=" + title + " page=" + page + " size=" + size, info));
        return info;
    }

    public PayDetailVo payDetail(String performancesId, String ticketsId) {
        KylinTicketVo ticketVo = null;
        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        if (null == performancesInfo) {
            return null;
        }
        performancesInfo = checkAppStatusInfo(performancesInfo);
        queueUtils.pushPvUv(CurrentUtil.getCurrentUid(), KylinTableStatusConst.PvUv.TK_ORDER.getKey(), performancesId, null, null, CurrentUtil.getCliIpAddr());
        for (int i = 0; i < performancesInfo.getTicketTimeList().size(); i++) {
            for (int x = 0; x < performancesInfo.getTicketTimeList().get(i).getTicketList().size(); x++) {
                KylinTicketVo ticketItem = performancesInfo.getTicketTimeList().get(i).getTicketList().get(x);
                if (ticketItem.getTicketsId().equals(ticketsId)) {
                    int status = checkTicketStatus(ticketItem);
                    ticketItem.setStatus(status);
                    int statusExchange = checkTicketStatusExchange(ticketItem);
                    ticketItem.setStatusExchange(statusExchange);
                    ticketVo = ticketItem;
                    Integer isMemberStatus = getIsMemberStatus(ticketItem);
                    ticketItem.setIsMemberStatus(isMemberStatus);
                }
            }
        }

        performancesInfo.setMessage(KylinPerformanceStatusEnum.getName(performancesInfo.getAppStatus()));

        PayDetailVo payDetailVo = new PayDetailVo();
        if (ticketVo != null && ticketVo.getIsExpress() == 1) {
            KylinTicketExpressModuleVo expressModuleVo = dataUtils.getTEMVo(ticketsId);
            payDetailVo.setExpressModuleList(expressModuleVo == null ? null : expressModuleVo.getProduceCodeList());
        } else {
            payDetailVo.setExpressModuleList(null);
        }
        payDetailVo.setPerformanceInfo(performancesInfo);
        payDetailVo.setTicketInfo(ticketVo);

        // 设置票观演人数量
        payDetailVo.setViewersNumber(getViewersNumberByTicketsId(ticketsId));

        //设置默认手机号
        Map token = CurrentUtil.getTokenClaims();
        payDetailVo.setUserMobile(StringUtils.defaultString(((String) token.get("mobile")), ""));

        log.info(UserPathDto.setData("预支付演出票种详情", "performancesId=" + performancesId + " ticketsId=" + ticketsId, payDetailVo));
        return payDetailVo;
    }

    /**
     * 设置观演人数量
     * @param ticketsId
     */
    private Integer getViewersNumberByTicketsId(String ticketsId) {
        List<KylinTicketPartnerVo> voTickets = mongoTemplate.find(Query.query(Criteria.where("ticketsId").is(ticketsId)),
                KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
        if (voTickets.isEmpty()) {
            return 0;
        }
        return voTickets.get(0).getViewersNumber();
    }

    public List<KylinPerformanceVo> checkAppStatus(List<KylinPerformanceVo> list) {
        List<KylinPerformanceVo> newList = ObjectUtil.getKylinPerformanceVoArrayList();
        if (!CollectionUtils.isEmpty(list)) {
            String nowTimeStr = DateUtil.getNowTime();
            for (KylinPerformanceVo info : list) {
                // 当前时间大于停售时间 小于结束时间 是 停售
                String stopSellTime = info.getStopSellTime();
                String timeEnd = info.getTimeEnd();
                Integer isEnd = DateUtil.compareStrDay(nowTimeStr, timeEnd);
                if (1 == DateUtil.compareStrDay(nowTimeStr, stopSellTime) && -1 == DateUtil.compareStrDay(nowTimeStr, timeEnd) && 7 != info.getAppStatus()) {
                    info.setAppStatus(11);
                }

                // 票状态 6票可购买 8售罄 9未开始 10结束 11停售
                if (3 != info.getAppStatus() && 7 != info.getAppStatus() && 1 != isEnd) { // 演出已结束、未上线 不展示
                    String sellTime = info.getSellTime();
                    if (1 == DateUtil.compareStrDay(sellTime, nowTimeStr)) {// 未开始
                        info.setAppStatus(9);
                        int isMemberStatus = getPerformanceIsMemberStatus(info);
                        if (1 == isMemberStatus) {
                            info.setAppStatus(6);
                        }
                    } else { // 已开始
                        info.setAppStatus(6);
                        if (1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) { // 演出已结束
                            info.setAppStatus(10);
                        }
                    }
                    newList.add(info);
                }
            }
        }
        return newList;
    }

    public List<KylinPerformanceVo> checkAppStatusRoad(List<KylinPerformanceVo> list) {
        List<KylinPerformanceVo> newList = ObjectUtil.getKylinPerformanceVoArrayList();
        if (!CollectionUtils.isEmpty(list)) {
            String nowTimeStr = DateUtil.getNowTime();
            for (KylinPerformanceVo info : list) {
                // 当前时间大于停售时间 小于结束时间 是 停售
                String stopSellTime = info.getStopSellTime();
                String timeEnd = info.getTimeEnd();
                Integer isEnd = DateUtil.compareStrDay(nowTimeStr, timeEnd);
                if (1 == DateUtil.compareStrDay(nowTimeStr, stopSellTime) && -1 == DateUtil.compareStrDay(nowTimeStr, timeEnd) && 7 != info.getAppStatus()) {
                    info.setAppStatus(11);
                }

                // 票状态 6票可购买 8售罄 9未开始 10结束 11停售
//                if (3 != info.getAppStatus() && 7 != info.getAppStatus() && 1 != isEnd) { // 演出已结束、未上线 不展示
                if (3 != info.getAppStatus() && 7 != info.getAppStatus()) { // 演出已结束、未上线 不展示
                    String sellTime = info.getSellTime();
                    if (1 == DateUtil.compareStrDay(sellTime, nowTimeStr)) {// 未开始
                        info.setAppStatus(9);
                        int isMemberStatus = getPerformanceIsMemberStatus(info);
                        if (1 == isMemberStatus) {
                            info.setAppStatus(6);
                        }
                    } else { // 已开始
                        info.setAppStatus(6);
                        if (1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) { // 演出已结束
                            info.setAppStatus(10);
                        }
                    }
                    newList.add(info);
                }
            }
        }
        return newList;
    }

    public KylinPerformanceVo checkAppStatusInfo(KylinPerformanceVo info) {
        if (null != info) {
            if (info.getAppStatus() == 0 || info.getAppStatus() == 1) {
                info.setAppStatus(3);
            }
            List<KylinTicketTimesVo> ticketTimeList = info.getTicketTimeList();
            List<KylinTicketTimesVo> ticketTimeListNew = ObjectUtil.getKylinTicketTimesVoArrayList();
            for (KylinTicketTimesVo ticketTime : ticketTimeList) {
                List<KylinTicketVo> ticketList = ticketTime.getTicketList();
                List<KylinTicketVo> ticketListNew = ObjectUtil.getKylinTicketVoArrayList();
                for (KylinTicketVo ticket : ticketList) {
                    int status = checkTicketStatus(ticket);
                    ticket.setStatus(status);
                    // 会员状态
                    Integer isMemberStatus = getIsMemberStatus(ticket);
                    ticket.setIsMemberStatus(isMemberStatus);
                    if (ticket.getStatus() != 7) {
                        ticketListNew.add(ticket);
                    }
                }
                if (!CollectionUtils.isEmpty(ticketListNew)) {
                    ticketTime.setTicketList(ticketListNew);
                    ticketTimeListNew.add(ticketTime);
                }
            }
            info.setTicketTimeList(ticketTimeListNew);

            if (CollectionUtils.isEmpty(ticketTimeListNew) && 7 != info.getAppStatus()) { //列表的时候无需判断 因为列表不展示状态标签
                info.setAppStatus(11); // 所有票种下架 演出停售
            }
            // 当前时间大于停售时间 小于结束时间 是 停售
            String nowTimeStr = DateUtil.getNowTime();
            String stopSellTime = info.getStopSellTime();
            String timeEnd = info.getTimeEnd();
            if (1 == DateUtil.compareStrDay(nowTimeStr, stopSellTime) && -1 == DateUtil.compareStrDay(nowTimeStr, timeEnd) && 7 != info.getAppStatus()) {
                info.setAppStatus(11);
            }

            // 票状态 6票可购买 8售罄 9未开始 10结束 11停售
            if (3 != info.getAppStatus() && info.getAppStatus() != 8 && info.getAppStatus() != 11 && 7 != info.getAppStatus()) { // 个别状态无需再判断
                String sellTime = info.getSellTime();
                if (1 == DateUtil.compareStrDay(sellTime, nowTimeStr)) {// 未开始
                    info.setAppStatus(9);
                    //老判断 不根据用户会员做判断
                    //int isMemberStatus = getPerformanceIsMemberStatus(info);
                    //新判断 根据用户会员做判断
                    int isMemberStatus = getPerformanceIsMemberStatusByIsMember(info,CurrentUtil.getCurrentUid());
                    if (1 == isMemberStatus) {
                        info.setAppStatus(6);
                    }
                } else { // 已开始
                    info.setAppStatus(6);
                    if (1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) { // 演出已结束
                        info.setAppStatus(10);
                    }
                }
            }
        }
        return info;
    }

    public int checkTicketStatus(KylinTicketVo ticketItem) {
        // 3审核通过;4审核未通过;6在售;7停售;8售罄;9未开始;10已结束
        int getStatus = ticketItem.getStatus();
        int status = getStatus;

        if (getStatus == 8) {
            getStatus = 6;
        }
        boolean isSellOut = dataUtils.ticketIsSoldOut(ticketItem.getTicketsId());
        if (isSellOut && getStatus != 7) {
            status = 8;
            getStatus = 8;
        }
        if (null != ticketItem) {
            // 判断售罄
            if (6 == getStatus || 9 == getStatus || 10 == getStatus) {
                String timeStart = ticketItem.getTimeStart();
                String timeEnd = ticketItem.getTimeEnd();
                String nowTime = DateUtil.getNowTime();

                if (1 == DateUtil.compareStrDay(timeStart, nowTime)) {// 未开始
                    status = 9;
                } else { // 已开始
                    status = 6;
                    if (1 == DateUtil.compareStrDay(nowTime, timeEnd)) { // 已结束
                        status = 10;
                    }
                }
            }
        }
        return status;
    }

    public int checkTicketStatusExchange(KylinTicketVo ticketItem) {
        int statusExchange;
        int surplusExchange = dataUtils.getSurplusExchange(ticketItem.getTicketsId());

        String timeStart = ticketItem.getTimeStart();
        String timeEnd = ticketItem.getTimeEnd();
        String nowTime = DateUtil.getNowTime();

        if (1 == DateUtil.compareStrDay(timeStart, nowTime)) {// 未开始
            statusExchange = 7;
        } else { // 已开始
            statusExchange = surplusExchange > 0 ? 6 : 7;
            if (1 == DateUtil.compareStrDay(nowTime, timeEnd)) { // 已结束
                statusExchange = 7;
            }
        }
        return statusExchange;
    }

    public Integer getIsMemberStatus(KylinTicketVo ticket) {// 会员状态
        Integer isMemberStatus = 0;
        if (null != ticket) {
            if (1 == ticket.getIsMember()) { // 有会员
                String memberTimeStart = ticket.getMemberTimeStart();
                String nowTime = DateUtil.getNowTime();
                if (1 == DateUtil.compareStrDay(memberTimeStart, nowTime)) { // 还没到会员购买时间
                    isMemberStatus = 0;
                } else { // 可以购买
                    isMemberStatus = 1;
                }
            } else {
                isMemberStatus = 0;
            }
        }
        return isMemberStatus;
    }

    public Integer getPerformanceIsMemberStatus(KylinPerformanceVo info) {// 会员状态
        Integer isMemberStatus = 0;
        if (null != info) {
            if (1 == info.getIsMember()) { // 有会员
                String memberTimeStart = info.getSellMemberTime();
                String nowTime = DateUtil.getNowTime();
                if (1 == DateUtil.compareStrDay(memberTimeStart, nowTime)) { // 还没到会员购买时间
                    isMemberStatus = 0;
                } else { // 可以购买
                    isMemberStatus = 1;
                }
            } else {
                isMemberStatus = 0;
            }
        }
        return isMemberStatus;
    }
    // 会员状态
    public Integer getPerformanceIsMemberStatusByIsMember(KylinPerformanceVo info,String uid) {
        Integer isMemberStatus = 0;
        if (null != info) {
            if (1 == info.getIsMember()) { // 有会员
                //普通用户开售时间
                String memberTimeStart = info.getSellTime();
                if(StringUtils.isNotEmpty(uid)){
                    Integer memberByUser = dataUtils.isMemberByUser(uid);
                    if(memberByUser==1){
                        //会员开售开售时间
                        memberTimeStart=info.getSellMemberTime();
                    }
                }
                String nowTime = DateUtil.getNowTime();
                if (1 == DateUtil.compareStrDay(memberTimeStart, nowTime)) { // 还没到会员购买时间
                    isMemberStatus = 0;
                } else { // 可以购买
                    isMemberStatus = 1;
                }
            } else {
                isMemberStatus = 0;
            }
        }
        return isMemberStatus;
    }
    /**
     * 获取我的已购票演出列表
     *
     * @return
     */
    public List<KylinPerformanceVo> myPerformancesList() {
        String userId = CurrentUtil.getCurrentUid();
        List<KylinPerformanceVo> performanceVoList = dataUtils.myPerformancesList(userId);
        return performanceVoList;
    }

    @Override
    public ResponseDto<String> getPerformanceIdByInfo(Integer useScope, String busiId) {
        if (useScope.equals(91)) {//场次
            List<KylinTicketTimesPartnerVo> voTimes = mongoTemplate.find(Query.query(Criteria.where("ticketTimesId").is(busiId)),
                    KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
            if (voTimes.size() <= 0) {
                return ResponseDto.failure();
            } else {
                return ResponseDto.success(voTimes.get(0).getPerformancesId());
            }
        } else if (useScope.equals(92)) {//票
            List<KylinTicketPartnerVo> voTickets = mongoTemplate.find(Query.query(Criteria.where("ticketsId").is(busiId)),
                    KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
            if (voTickets.size() <= 0) {
                return ResponseDto.failure();
            } else {
                List<KylinTicketTimesPartnerVo> voTimes = mongoTemplate.find(Query.query(Criteria.where("ticketTimesId").is(voTickets.get(0).getTimesId())),
                        KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
                if (voTimes.size() <= 0) {
                    return ResponseDto.failure();
                } else {
                    return ResponseDto.success(voTimes.get(0).getPerformancesId());
                }
            }
        } else {
            return ResponseDto.failure();
        }
    }

    @Override
    public ResponseDto<String> subscribe(String performancesId, Integer sourceType) {
        try {
            Map claims = CurrentUtil.getTokenClaims();
            String uid = StringUtils.defaultString(((String) claims.get(CurrentUtil.TOKEN_SUB)), "");
            String nickname = StringUtils.defaultString(((String) claims.get(CurrentUtil.TOKEN_NICKNAME)), "");
            String mobile = StringUtils.defaultString(((String) claims.get(CurrentUtil.TOKEN_MOBILE)), "");
            queueUtils.sendMsgByRedis(
                    MQConst.KylinQueue.SQL_PERFORMANCE_LACK.getKey(),
                    SqlMapping.get(
                            "kylin_perform_sub.insert",
                            new Object[]{
                                    IDGenerator.nextSnowId(), performancesId, uid, nickname, mobile, sourceType
                            }
                    ));
            dataUtils.setSubscribe(uid, performancesId);
            return ResponseDto.success("预约成功");
        } catch (Exception e) {
            log.error("演出预约 [performancesId:{}, uid:{}, e:{}]", performancesId, CurrentUtil.getCurrentUid(), e);
            return ResponseDto.success("预约失败");
        }
    }

    @Override
    public ResponseDto<Integer> isSubscribe(String performancesId) {
        String uid = CurrentUtil.getCurrentUid();
        Integer subscribe = dataUtils.getSubscribe(uid, performancesId);
        return ResponseDto.success(subscribe);
    }

    @Override
    public ResponseDto<List<KylinCandyVo>> kylinCandy(List<KylinCandyItemParam> data, String roadShowId) {
        List<KylinCandyVo> voList = ObjectUtil.kylinCandyVos();
        for (KylinCandyItemParam item : data) {
            List<String> roadShowIds = dataUtils.getCouponRoad(item.getCouponId());
            if (roadShowIds.size() == 0 || roadShowIds.contains(roadShowId)) {
                KylinCandyVo vo = KylinCandyVo.getNew();
                vo.setCouponId(item.getCouponId());
                vo.setUcouponId(item.getUcouponId());
                vo.setRoadShowId(roadShowIds.contains(roadShowId) ? roadShowId : "");
                voList.add(vo);
            }
        }
        return ResponseDto.success(voList);
    }

    @Override
    public ResponseDto<String> performanceSubscribe(HttpServletRequest request,KylinPerformanceSubscribeParam param) {
        try {
            //获取设备类型
            String source = request.getHeader("source");
            String uid = CurrentUtil.getCurrentUid();
            // 避免重复预约
            Integer performanceSubscribe = dataUtils.getPerformanceTicketsSubscribe(uid, param.getPerformancesId(), param.getTicketTimesId(),param.getTicketsId());
            if (performanceSubscribe != 1) {
            //先删除其他票种预约信息
            List<String> ticketsIds = param.getTicketsIds();
            if(!CollectionUtils.isEmpty(ticketsIds)){
                ticketsIds.forEach(iter->{
                    dataUtils.deleteIsSubscribe(uid,param.getPerformancesId(), param.getTicketTimesId(),iter);
                });
            }
            //删除预约记录
            queueUtils.sendMsgByRedis(
                    MQConst.KylinQueue.SQL_PERFORMANCE_SUBSCRIBE.getKey(),
                    SqlMapping.get(
                            "kylin_performance_subscribe.delete",
                            new Object[]{
                                    param.getPerformancesId(), param.getTicketTimesId(),uid
                            }
                    ));
            // 计算过期时间 演出结束时间-当前时间
            long expirationTime = DateUtil.intervalSeconds(DateUtil.parse(DateUtil.format(param.getTimeEnd(), DateUtil.Formatter.yyyyMMddHHmmss), DateUtil.DATE_FULL_STR), DateUtil.now());
            // 计算通知时间 演出开始时间-10分钟
            LocalDateTime timeStart = param.getTimeStart();
            LocalDateTime localDateTime = timeStart.minusMinutes(10);
            String pushTime = DateUtil.format(localDateTime, DateUtil.Formatter.yyyyMMddHHmmss);
            //票种预约
            dataUtils.setPerformanceTicketsSubscribe(uid, param.getPerformancesId(), param.getTicketTimesId(),param.getTicketsId(),expirationTime);
            //本场演出预约
            dataUtils.setPerformanceSubscribe(uid, param.getPerformancesId(),expirationTime);
            //push推送内容
            String title=param.getPerformancesTitle()+DateUtil.format(timeStart, DateUtil.Formatter.yyyyMMddHHmmss)+"即将开票，登登登提前"+param.getAdvanceMinuteMember()+"分钟开抢";
            // 记录预约信息
            queueUtils.sendMsgByRedis(
                    MQConst.KylinQueue.SQL_PERFORMANCE_SUBSCRIBE.getKey(),
                    SqlMapping.get(
                            "kylin_performance_subscribe.insert",
                            new Object[]{
                                    param.getPerformancesId(), param.getTicketTimesId(), param.getTicketsId(), uid,KylinTableStatusConst.SubscribeTypeEnum.TYPE1.getKey(),param.getDeviceTokens(),
                                    source,pushTime,title,0
                            }
                    ));
            //redis 用户开票提醒列表
            KylinPerformanceSubscribeUpushVo kylinPerformanceSubscribeUpushVo = new KylinPerformanceSubscribeUpushVo();
            kylinPerformanceSubscribeUpushVo.setPushTitle(param.getPerformancesTitle());
            kylinPerformanceSubscribeUpushVo.setPushContent(title);
            kylinPerformanceSubscribeUpushVo.setImg(param.getImgPoster());
            kylinPerformanceSubscribeUpushVo.setJumpType(6);
            kylinPerformanceSubscribeUpushVo.setJumpValue(param.getPerformancesId());
            kylinPerformanceSubscribeUpushVo.setPushTime(pushTime);
            kylinPerformanceSubscribeUpushVo.setTimeStart(DateUtil.format(param.getTimeStart(), DateUtil.Formatter.yyyyMMddHHmmss));
            kylinPerformanceSubscribeUpushVo.setType(KylinTableStatusConst.SubscribeTypeEnum.TYPE1.getKey());
            kylinPerformanceSubscribeUpushVo.setPerformancesId(param.getPerformancesId());
            kylinPerformanceSubscribeUpushVo.setTicketTimesId(param.getTicketTimesId());
            kylinPerformanceSubscribeUpushVo.setTicketsId(param.getTicketsId());
            //开票提醒最多存20条数据
            LinkedList<KylinPerformanceSubscribeUpushVo> performanceSubscribeList = dataUtils.getPerformanceSubscribeList(uid);
            //删除其他票种的消息提醒
            for (Iterator<KylinPerformanceSubscribeUpushVo> it = performanceSubscribeList.iterator(); it.hasNext(); ) {
                KylinPerformanceSubscribeUpushVo info = it.next();
                if(info.getPerformancesId().equals(param.getPerformancesId()) && info.getTicketTimesId().equals(param.getTicketTimesId())){
                    //移除
                    it.remove();
                }
            }
            if(performanceSubscribeList.size()>=20){
                KylinPerformanceSubscribeUpushVo last = performanceSubscribeList.getLast();
                //删除redis中已读信息
                dataUtils.deletePerformanceSubscribeRead(uid,last.getPerformancesId(), last.getTicketTimesId());
                //删除最后一条数据
                performanceSubscribeList.removeLast();
                //添加到第一条
                performanceSubscribeList.addFirst(kylinPerformanceSubscribeUpushVo);
            }else {
                //添加到第一条
                performanceSubscribeList.addFirst(kylinPerformanceSubscribeUpushVo);
            }
            //开票提醒列表存入redis中
            dataUtils.setPerformanceSubscribeList(uid,performanceSubscribeList);
            }
            return ResponseDto.success("预约成功");
        } catch (Exception e) {
            log.error("演出预约 [performancesId:{},ticketTimesId：{},ticketsId:{},uid:{}, e:{}]",param.getPerformancesId(), param.getTicketTimesId(),param.getTicketsId(), CurrentUtil.getCurrentUid(), e);
            return ResponseDto.success("预约失败");
        }
    }

    @Override
    public ResponseDto<Integer> performanceIsSubscribe(String performancesId, String ticketTimesId,String ticketsId ) {
        String uid = CurrentUtil.getCurrentUid();
        Integer performanceSubscribe = dataUtils.getPerformanceTicketsSubscribe(uid, performancesId, ticketTimesId,ticketsId);
        return ResponseDto.success(performanceSubscribe);
    }

    @Override
    public void deleteIsSubscribe(String performancesId, String ticketTimesId,String ticketsId) {
        String uid = CurrentUtil.getCurrentUid();
        //删除预约提醒
        dataUtils.deleteIsSubscribe(uid,performancesId,ticketTimesId,ticketsId);
        //删除已读
        dataUtils.deleteIsSubscribeRead(uid,performancesId,ticketTimesId);
    }
}
