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

import com.liquidnet.commons.lang.CommonConst;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.DistanceUtil;
import com.liquidnet.service.kylin.constant.KylinPerformanceStatusEnum;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
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.returns.PayDetailVo;
import com.liquidnet.service.kylin.entity.KylinPerformances;
import com.liquidnet.service.kylin.mapper.KylinPerformancesMapper;
import com.liquidnet.service.kylin.service.IKylinPerformancesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.service.kylin.timerTask.PerformanceVoTask;
import com.liquidnet.service.kylin.utils.DataUtils;
import org.bson.Document;
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.BasicQuery;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

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

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private DataUtils dataUtils;

    @Autowired
    private PerformanceVoTask task;

    public HashMap<String, Object> localList(
            String timeStart, int days, String title, String cityName, int type,
            Integer isDiscount, Integer isAdvance, Integer isExclusive,
            int page, int size,
            String orderBy, String sort
    ) {
        HashMap<String, Object> info = new HashMap<>();

        // 排序 分页
        Sort sortName = Sort.by(Sort.Direction.ASC, "timeStart"); // 默认开票越早的在上面
        if (sort.equals("DESC")) {
            if (!orderBy.isEmpty()) {
                sortName = Sort.by(Sort.Direction.DESC, orderBy);
            }
        } else if (sort.equals("ASC")) {
            if (!orderBy.isEmpty()) {
                sortName = Sort.by(Sort.Direction.ASC, orderBy);
            }
        }

        Pageable pageable = PageRequest.of(page - 1, size, sortName);

        //条件
        Document queryObject = new Document();

        if (!title.isEmpty()) {
            queryObject.put("title", Pattern.compile(title, Pattern.CASE_INSENSITIVE));
        }
        if (!cityName.isEmpty()) {
            queryObject.put("cityName", Pattern.compile(cityName, Pattern.CASE_INSENSITIVE));
        }
        if (type > 0) {
            queryObject.put("type", type);
        }
        if (isExclusive != null) {
            queryObject.put("isExclusive", isExclusive);
        }
        if (isDiscount != null) {
            queryObject.put("isDiscount", isDiscount);
        }
        if (isAdvance != null) {
            queryObject.put("isAdvance", isAdvance);
        }

        Query query = new BasicQuery(queryObject);
        if (!timeStart.isEmpty()) {
            String timeStartEnd = timeStart + " 23:59:59";
            query.addCriteria(Criteria.where("timeStart").gte(timeStart).lte(timeStartEnd));
        }
        if (days > 0) {
            LocalDateTime nowTime = LocalDateTime.now();
            String nowTimeStr = nowTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            LocalDateTime OtherTime = nowTime.plusDays(days);
            String OtherTimeStr = OtherTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            query.addCriteria(Criteria.where("timeStart").gte(nowTimeStr).lte(OtherTimeStr));
        }

        // 固定查询条件
        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));

        // 查询总数
        long count = mongoTemplate.count(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        query.with(pageable);
        // 要查询的字段
        query.fields().exclude("details");
        query.fields().exclude("noticeImage");

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

        // 推荐其他地区演出
        List<KylinPerformanceVo> otherlist = null;
        int is_native = 1;
        int recommend = list.size();
        if (count < size && !cityName.isEmpty()) {
            /*Document newQueryObject = query.getQueryObject();
            queryObject.put("cityName", "上海");
            Query queryOther = new BasicQuery(newQueryObject);*/
            Query queryOther = new Query();

            String regex = String.format("%s%s%s","^((?!" , cityName , ").)*$");
            Pattern cityNameCompile = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
            queryOther.addCriteria(Criteria.where("cityName").regex(cityNameCompile));

            queryOther.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));

            long newSize = size - count;
            Pageable newPageable = PageRequest.of(0, (int) newSize, sortName);
            queryOther.with(newPageable);
            query.fields().exclude("details");
            query.fields().exclude("noticeImage");

            otherlist = mongoTemplate.find(queryOther, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
            if (otherlist.size() > 0) {
                is_native = 0;
                list.addAll(otherlist);
            }
        }

        // 组合数据
        info.put("is_native", is_native); // 本地演出少是否推荐了其他演出 0有推荐 1没有
        info.put("recommend", recommend); // 从第几个开始是其他推荐演出 （非后台设置的那个推荐）
        info.put("total", count);
        info.put("list", list);

        return info;
    }

    public HashMap<String, Object> noticeList() {
        // 固定条件
        Query query = new Query();
        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));

        // 今天的
        LocalDateTime toDayTime = LocalDateTime.now();
        String toDayTimeStr = toDayTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDateTime toDayEndTime = toDayTime.plusDays(1);
        String toDayEndTimeStr = toDayEndTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        query.addCriteria(Criteria.where("timeStart").gte(toDayTimeStr).lt(toDayEndTimeStr));
        query.fields().exclude("details");
        query.fields().exclude("noticeImage");
        List<KylinPerformanceVo> toDayList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        // 三天的
        Query queryT = new Query();
        LocalDateTime nowTimeT = LocalDateTime.now();
        String nowTimeStrT = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTimeT);
        queryT.addCriteria(Criteria.where("timeEnd").gte(nowTimeStrT));

        LocalDateTime threeDaysLater = toDayTime.plusDays(3);
        String threeDaysLaterStr = threeDaysLater.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        queryT.addCriteria(Criteria.where("timeStart").gte(toDayEndTimeStr).lt(threeDaysLaterStr));
        queryT.fields().exclude("details");
        queryT.fields().exclude("noticeImage");
        List<KylinPerformanceVo> threeDaysList = mongoTemplate.find(queryT, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        HashMap<String, Object> info = new HashMap<>();
        info.put("toDayList", toDayList);
        info.put("threeDaysList", threeDaysList);
        return info;
    }

    public List<KylinPerformanceVo> recommendList() {
        // 固定条件
        Query query = new Query();
        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));

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

        // 推荐
        query.addCriteria(Criteria.where("isRecommend").is(1));
        List<KylinPerformanceVo> recommendList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        return recommendList;
    }

    public List<KylinPerformanceVo> exclusiveList(Integer page, Integer size) {
        // 固定条件
        Query query = new Query();
        LocalDateTime nowTime = LocalDateTime.now();
        String nowTimeStr = DateUtil.Formatter.yyyyMMddHHmmss.format(nowTime);
        query.addCriteria(Criteria.where("timeEnd").gte(nowTimeStr));

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

        Pageable pageable = PageRequest.of(page - 1, size);
        query.with(pageable);

        query.addCriteria(Criteria.where("isExclusive").is(1));
        List<KylinPerformanceVo> recommendList = mongoTemplate.find(query, KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());

        return recommendList;
    }

    public KylinPerformanceVo detail(String performancesId, double latitudeFrom, double longitudeFrom) {

        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        String roadShowId = performancesInfo.getRoadShowId();

        List<KylinPerformanceVo> roadList = new ArrayList();
        if (Integer.parseInt(roadShowId) > 0) {
            roadList = mongoTemplate.find(
                    Query.query(Criteria.where("roadShowId").is(roadShowId)),
                    KylinPerformanceVo.class,
                    KylinPerformanceVo.class.getSimpleName()
            );
        }

        // 处理状态 购买 未开始 结束可更改   下架 售馨不可更改
        if (performancesInfo.getAppStatus() == 6 || performancesInfo.getAppStatus() == 9 || performancesInfo.getAppStatus() == 10) {
            String stopSellTime = performancesInfo.getStopSellTime();
            String sellTime = performancesInfo.getSellTime();
            String nowTime = DateUtil.getNowTime();

            if (1 == DateUtil.compareStrDay(sellTime, nowTime)) {// 未开始
                performancesInfo.setAppStatus(9);
            } else { // 购买
                performancesInfo.setAppStatus(6);
            }
            if (1 == DateUtil.compareStrDay(stopSellTime, nowTime)) { // 购买
                performancesInfo.setAppStatus(6);
            } else {// 已结束
                performancesInfo.setAppStatus(10);
            }
        }
        performancesInfo.setMessage(KylinPerformanceStatusEnum.getName(performancesInfo.getAppStatus()));

        // 处理距离
        if (longitudeFrom != CommonConst.DFT_DOUBLE_VAL) {
            String diffDistance = DistanceUtil.getDistance(longitudeFrom, latitudeFrom, Double.parseDouble(performancesInfo.getLongitude()), Double.parseDouble(performancesInfo.getLatitude()));
            performancesInfo.setDiffDistance(diffDistance);
            for (KylinPerformanceVo road : roadList) {
                String diffDistanceRoad = DistanceUtil.getDistance(longitudeFrom, latitudeFrom, Double.parseDouble(performancesInfo.getLongitude()), Double.parseDouble(performancesInfo.getLatitude()));
                road.setDiffDistance(diffDistanceRoad);
            }
        }

        performancesInfo.setRoadList(roadList);
        return performancesInfo;
    }

    public HashMap<String, Object> ticketTimesPartner(String performancesId, Integer isAgent) {
        KylinPerformanceVo vo = dataUtils.getPerformanceVo(performancesId);

        List<KylinTicketTimesVo> ticketTimesList = vo.getTicketTimeList();
        for (KylinTicketTimesVo partner : ticketTimesList) {
            Query query = Query.query(Criteria.where("timeId").is(partner.getTimeId()));
            if (isAgent > 0) {
                query.addCriteria(Criteria.where("isAgent").is(isAgent));
            }
            List<KylinTicketVo> ticketList = partner.getTicketList();
//                    mongoTemplate.find(
//                    query,
//                    KylinTicketVo.class,
//                    KylinTicketVo.class.getSimpleName()
//            );

            for (KylinTicketVo ticket : ticketList) {
                // 处理状态 购买 未开始 结束可更改   下架 售馨不可更改
                if (ticket.getStatus() == 6 || ticket.getStatus() == 9 || ticket.getStatus() == 10) {
                    String timeStart = ticket.getTimeStart();
                    String timeEnd = ticket.getTimeEnd();
                    String nowTime = DateUtil.getNowTime();

                    if (1 == DateUtil.compareStrDay(timeStart, nowTime)) {// 未开始
                        ticket.setStatus(9);
                    } else { // 已开始
                        ticket.setStatus(6);
                        if (1 == DateUtil.compareStrDay(nowTime, timeEnd)) { // 已结束
                            ticket.setStatus(10);
                        }
                    }
                }
                // 会员状态
                Integer isMemberStatus = 0;
                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;
                }
                ticket.setIsMemberStatus(isMemberStatus);
            }

            partner.setTicketList(ticketList);
        }

        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        HashMap<String, Object> info = new HashMap();
        info.put("city_name", performancesInfo.getCityName());
        info.put("field_name", performancesInfo.getFieldName());
        info.put("title", performancesInfo.getTitle());

        HashMap result = new HashMap();
        result.put("performancesInfo", info);
        result.put("ticketTimesList", ticketTimesList);

        return result;
    }

    public List<KylinPerformanceVo> performanceList(String... performancesIds) {
        Query query = new Query();
        query.addCriteria(Criteria.where("performancesId").in(performancesIds));

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

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

        return list;
    }

    public List performanceCalendar(String yearMonth, String cityName) throws ParseException {
        Document queryObject = new Document();
        if (!cityName.isEmpty()) {
            queryObject.put("cityName", Pattern.compile(cityName, Pattern.CASE_INSENSITIVE));
        }
        Query query = new BasicQuery(queryObject);

        // 处理成正常格式
        yearMonth = yearMonth.concat("-01 00:00:00");
        // 获取此月开始结束时间
        String monthStart = DateUtil.getMonthFirst(yearMonth);
        String monthEnd = DateUtil.getMonthLast(yearMonth);

        query.addCriteria(Criteria.where("timeStart").gte(monthStart).lte(monthEnd));
        query.fields().include("timeStart");

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

        List date = new ArrayList();
        for (KylinPerformanceVo v : list) {
            String timeStart = v.getTimeStart();
            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) {
        Document queryObject = new Document();
        queryObject.put("cityName", Pattern.compile(cityName, Pattern.CASE_INSENSITIVE));
        Query query = new BasicQuery(queryObject);

        String yearMonthDayEnd = yearMonthDay.concat(" 23:59:59");
        query.addCriteria(Criteria.where("timeStart").gte(yearMonthDay).lte(yearMonthDayEnd));
        query.fields().exclude("details");
        query.fields().exclude("noticeImage");

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

        return list;
    }

    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);

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

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

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

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

        HashMap info = new HashMap();
        info.put("total", count);
        info.put("list", list);

        return info;
    }

    public PayDetailVo payDetail(String performancesId, String ticketsId) {
        KylinTicketVo ticketVo = null;
        KylinPerformanceVo performancesInfo = dataUtils.getPerformanceVo(performancesId);
        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)){
                    String timeStart = ticketItem.getTimeStart();
                    String timeEnd = ticketItem.getTimeEnd();
                    String nowTime = DateUtil.getNowTime();

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

        if (performancesInfo.getAppStatus() == 6 || performancesInfo.getAppStatus() == 9 || performancesInfo.getAppStatus() == 10) {
            String stopSellTime = performancesInfo.getStopSellTime();
            String sellTime = performancesInfo.getSellTime();
            String nowTime = DateUtil.getNowTime();

            if (1 == DateUtil.compareStrDay(sellTime, nowTime)) {// 未开始
                performancesInfo.setAppStatus(9);
            } else { // 购买
                performancesInfo.setAppStatus(6);
            }
            if (1 == DateUtil.compareStrDay(stopSellTime, nowTime)) { // 购买
                performancesInfo.setAppStatus(6);
            } else {// 已结束
                performancesInfo.setAppStatus(10);
            }
        }
        performancesInfo.setMessage(KylinPerformanceStatusEnum.getName(performancesInfo.getAppStatus()));

        PayDetailVo payDetailVo = new PayDetailVo();
        payDetailVo.setPerformanceInfo(performancesInfo);
        payDetailVo.setTicketInfo(ticketVo);
        return payDetailVo;
    }

    public String checkPerformanceTime(String performancesId){
        try {
            task.performanceVoStatus(performancesId);
            return "成功";
        }catch (Exception e){
            e.printStackTrace();
            return "失败";
        }
    }
}
