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

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.commons.lang.CommonConst;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.DistanceUtil;
import com.liquidnet.service.base.UserPathDto;
import com.liquidnet.service.kylin.constant.KylinPerformanceStatusEnum;
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.KylinPerformanceVo;
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.liquidnet.service.kylin.timerTask.PerformanceVoTask;
import com.liquidnet.service.kylin.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
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 org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
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 extends ServiceImpl<KylinPerformancesMapper, KylinPerformances> implements IKylinPerformancesService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private DataUtils dataUtils;

    @Autowired
    private PerformanceVoTask task;

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

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

        // 判断搜索 处理新数据
        List<KylinPerformanceVo> performancesListNew = new ArrayList<>();
        List<String> performancesIds = new ArrayList<>();
        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);
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String daysLaterStr = sdf.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 = new HashMap<>();
        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() {
        /*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");

        toDayList = checkAppStatus(toDayList);
        threeDaysList = checkAppStatus(threeDaysList);

        HashMap<String, Object> newList = new HashMap<>();
        newList.put("toDayList", toDayList);
        newList.put("threeDaysList", threeDaysList);
        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);
        String agentName = dataUtils.getAgentInfoName(agentId);
        performancesInfo.setAgentName(agentName);
        try {
            performancesInfo = checkAppStatusInfo(performancesInfo);
            performancesInfo.setMessage(KylinPerformanceStatusEnum.getName(performancesInfo.getAppStatus()));
        } catch (Exception e) {
            log.debug(" ERROR PERFORMANCE DETAILS PERFORMANCE_ID : " + performancesId);
        }

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

        log.info(UserPathDto.setData("演出详情", "performancesId=" + performancesId + " latitudeFrom=" + latitudeFrom + " longitudeFrom=" + longitudeFrom, performancesInfo));
        return performancesInfo;
    }

    public List<KylinPerformanceVo> roadList(String roadShowId) {
        List<KylinPerformanceVo> performancesList = dataUtils.getRoadList(roadShowId);
        performancesList = checkAppStatus(performancesList);
        return performancesList;
    }

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

        List<KylinTicketTimesVo> ticketTimesList = vo.getTicketTimeList();
        if (null != ticketTimesList) {
            for (KylinTicketTimesVo partner : ticketTimesList) {
                List<KylinTicketVo> ticketList = partner.getTicketList();
                List<KylinTicketVo> ticketListNew = new ArrayList<>();
                for (KylinTicketVo ticket : ticketList) {
                    int status = checkTicketStatus(ticket);
                    ticket.setStatus(status);
                    // 会员状态
                    Integer isMemberStatus = getIsMemberStatus(ticket);
                    ticket.setIsMemberStatus(isMemberStatus);
                    if (null == isAgent || 0 == isAgent) {
                        if (0 == ticket.getIsAgent()) {
                            ticketListNew.add(ticket);
                        }
                    } else if (1 == isAgent) {
                        if (1 == ticket.getIsAgent()) {
                            ticketListNew.add(ticket);
                        }
                    }
                }
                partner.setTicketList(ticketListNew);
            }
        }

        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) {
        List<KylinPerformanceVo> performanceList = new ArrayList<>();
        for (String id : performancesIds) {
            KylinPerformanceVo info = dataUtils.getPerformanceVo(id);
            performanceList.add(info);
        }
        performanceList = checkAppStatus(performanceList);
        return performanceList;
    }

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

        // 获取此月开始结束时间
        String 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) {
        List<KylinPerformanceVo> performancesList = dataUtils.getPerformancesListOfcityName(cityName);

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

        List<KylinPerformanceVo> performancesListNew = new ArrayList();
        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));

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

//        list = checkAppStatus(list);
        if (!CollectionUtils.isEmpty(list)) {
            String nowTimeStr = DateUtil.getNowTime();
            for (KylinPerformanceVo info : list) {
                Integer isEnd = DateUtil.compareStrDay(nowTimeStr, info.getTimeEnd());
                if (7 != info.getAppStatus() && 3 != info.getAppStatus() && 1 != isEnd) { // 演出已结束或者未上线
                    String timeStart = info.getSellTime();
                    String timeEnd = info.getStopSellTime();

                    if (info.getAppStatus() != 8) {
                        if (1 == DateUtil.compareStrDay(timeStart, nowTimeStr)) {// 未开始
                            info.setAppStatus(9);
                        } else { // 已开始
                            info.setAppStatus(6);
                            if (1 == DateUtil.compareStrDay(nowTimeStr, timeEnd)) { // 已结束
                                info.setAppStatus(10);
                            }
                        }
                    }
                }
            }
        }

        HashMap info = new HashMap();
        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);
        performancesInfo = checkAppStatusInfo(performancesInfo);

        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);
                    ticketVo = ticketItem;
                    Integer isMemberStatus = getIsMemberStatus(ticketItem);
                    ticketItem.setIsMemberStatus(isMemberStatus);
                }
            }
        }

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

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

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

    public List<KylinPerformanceVo> checkAppStatus(List<KylinPerformanceVo> list) {
        List<KylinPerformanceVo> newList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            String nowTimeStr = DateUtil.getNowTime();
            for (KylinPerformanceVo info : list) {
                Integer isEnd = DateUtil.compareStrDay(nowTimeStr, info.getTimeEnd());
                if (7 != info.getAppStatus() && 3 != info.getAppStatus() && 1 != isEnd) { // 演出已结束或者未上线
                    String timeStart = info.getSellTime();
                    String timeEnd = info.getStopSellTime();

                    if (info.getAppStatus() != 8) {
                        if (1 == DateUtil.compareStrDay(timeStart, nowTimeStr)) {// 未开始
                            info.setAppStatus(9);
                        } 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) {
            List<KylinTicketTimesVo> ticketTimeList = info.getTicketTimeList();
            List<KylinTicketTimesVo> ticketTimeListNew = new ArrayList<>();
            for (KylinTicketTimesVo ticketTime : ticketTimeList) {
                List<KylinTicketVo> ticketList = ticketTime.getTicketList();
                List<KylinTicketVo> ticketListNew = new ArrayList<>();
                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)) {
                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)) {
                info.setAppStatus(11);
            }

            // 票状态 6票可购买 8售罄 9未开始 10结束 11停售
            // 演出状态 7下架前端不展示
            if (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);
                    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 (null != ticketItem) {
            // 判断售罄
            boolean isSellOut = dataUtils.ticketIsSoldOut(ticketItem.getTicketsId());
            if (isSellOut) {
                getStatus = 8;
                status = 8;
            }
            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 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 String checkPerformanceTime(String performancesId) {
        try {
            task.performanceVoStatus(performancesId);
            return "成功";
        } catch (Exception e) {
            e.printStackTrace();
            return "失败";
        }
    }
}
