package com.liquidnet.service.merchant.util;

import com.liquidnet.service.kylin.dao.PerformancePartnerListDao;
import com.liquidnet.service.kylin.dto.param.PerformancePartnerListParam;
import com.liquidnet.service.kylin.dto.param.PerformancePartnerVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinPerformanceVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketPartnerVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketTimesPartnerVo;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
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.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.LookupOperation;
import org.springframework.data.mongodb.core.convert.MongoConverter;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Component
public class MongoMerchantUtils {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private MongoConverter mongoConverter;
    @Autowired
    private RedisMerchantUtils redisMerchantUtils;


    public PerformancePartnerVo getPerformancePartnerVo(String performanceId,String merchantId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId).and("merchantId").is(merchantId)), PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
    }

    public PerformancePartnerVo getPerformancePartnerVoNoMerchant(String performanceId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)), PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
    }

    public long getPerformancePartnerCount(Query query) {
        return mongoTemplate.count(query, PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
    }

    public List<PerformancePartnerVo> getPerformancePartnerList(Query query) {
        return mongoTemplate.find(query, PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
    }

    public PerformancePartnerVo insertPerformancePartnerVo(PerformancePartnerVo data) {
        return mongoTemplate.insert(data, PerformancePartnerVo.class.getSimpleName());
    }

    public KylinTicketTimesPartnerVo insertTicketTimesPartnerVo(KylinTicketTimesPartnerVo data) {
        return mongoTemplate.insert(data, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public KylinTicketTimesPartnerVo getTicketTimesPartnerVo(String ticketTimesId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(ticketTimesId)), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public List<KylinTicketTimesPartnerVo> getTicketTimesPartnerVoList(String performancesId) {
        return mongoTemplate.find(Query.query(Criteria.where("performancesId").is(performancesId)), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public void updateTicketTimesPartnerVo(KylinTicketTimesPartnerVo data) {
        Query query = Query.query(Criteria.where("ticketTimesId").is(data.getTicketTimesId()));
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(data));
        mongoTemplate.getCollection(KylinTicketTimesPartnerVo.class.getSimpleName()).updateOne(
                query.getQueryObject(),
                objectTicketVo
        );
    }

    public Object delTicketTimesPartnerVo(String ticketTimesId) {
        return mongoTemplate.remove(Query.query(Criteria.where("ticketTimesId").is(ticketTimesId)), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public KylinTicketPartnerVo insertTicketPartnerVo(KylinTicketPartnerVo data) {
        return mongoTemplate.insert(data, KylinTicketPartnerVo.class.getSimpleName());
    }

    public void updateTicketPartnerVo(KylinTicketPartnerVo data) {
        Query query = Query.query(Criteria.where("ticketsId").is(data.getTicketsId()));
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(data));
        mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                query.getQueryObject(),
                objectTicketVo
        );
    }

    public void submitTicketByTimes(KylinTicketPartnerVo data) {
        Query query = Query.query(Criteria.where("timesId").is(data.getTimesId()).and("status").nin(-2, 7));
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(data));
        mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                query.getQueryObject(),
                objectTicketVo
        );
    }

    public long getCountTicketPartnerByTimes(String timesId) {
        return mongoTemplate.count((Query.query(Criteria.where("timesId").is(timesId))), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public List<KylinTicketPartnerVo> getTicketMongoList(String timesId) {
        return mongoTemplate.find(Query.query(Criteria.where("timesId").is(timesId).and("status").ne(-1))
                        .with(Sort.by(Sort.Direction.ASC, "createdAt")),
                KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public KylinTicketPartnerVo getTicketsMongo(String ticketsId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("ticketsId").is(ticketsId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public KylinTicketPartnerVo getTicketPartnerVo(String ticketsId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("ticketsId").is(ticketsId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public List<KylinTicketPartnerVo> getTicketPartnerVoList(String timesId) {
        return mongoTemplate.find(Query.query(Criteria.where("timesId").is(timesId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public void updatePerformancePartnerVoById(PerformancePartnerVo data) {
        Query query = Query.query(Criteria.where("performancesId").is(data.getPerformancesId()));
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(data));
        mongoTemplate.getCollection(PerformancePartnerVo.class.getSimpleName()).updateOne(
                query.getQueryObject(),
                objectTicketVo
        );
    }

    public void updateSubmitTicketVoById(KylinTicketPartnerVo data) {
        Query query = Query.query(Criteria.where("ticketsId").is(data.getTicketsId()).and("status").in(3, 6, 8, 9, 10));
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(data));
        mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                query.getQueryObject(),
                objectTicketVo
        );
    }

    public void deleteTicketPartnerVo(String ticketsId) {
        mongoTemplate.remove(Query.query(Criteria.where("ticketsId").is(ticketsId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public boolean isExistsSubmitPerformancePartner(String performanceId,String merchantId) {
        return mongoTemplate.exists(Query.query(Criteria.where("performancesId").is(performanceId).and("merchantId").is(merchantId).and("auditStatus").is(0)),
                PerformancePartnerVo.class,
                PerformancePartnerVo.class.getSimpleName());
    }

    public boolean isExistsAddTicket(String timesId) {
        return mongoTemplate.exists(Query.query(Criteria.where("status").is(-2).and("timesId").is(timesId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

    public boolean isExistsAddTime(String performanceId) {
        return mongoTemplate.exists(Query.query(Criteria.where("status").is(-1).and("performancesId").is(performanceId)), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public List<KylinTicketTimesPartnerVo> getTimesMongoList(String performanceId) {
        return mongoTemplate.find(Query.query(Criteria.where("performancesId").is(performanceId)).with(Sort.by(Sort.Direction.ASC, "createdAt")),
                KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public KylinTicketTimesPartnerVo getTimesMongo(String timesId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(timesId).and("status")), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
    }

    public KylinPerformanceVo insertPerformanceVo(KylinPerformanceVo data) {
        return mongoTemplate.insert(data, KylinPerformanceVo.class.getSimpleName());
    }

    public Object delPerformanceVo(String performanceId) {
        redisMerchantUtils.delPerformanceVo(performanceId);
        return mongoTemplate.remove(Query.query(Criteria.where("performancesId").is(performanceId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
    }

    public KylinPerformanceVo getPerformanceVo(String performanceId,String merchantId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId).and("merchantId").is(merchantId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
    }

    public KylinPerformanceVo getPerformanceVoNoMerchant(String performanceId) {
        return mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
    }

    public List<KylinPerformanceVo> getPerformanceVoOnlineList() {
        return mongoTemplate.find(Query.query(Criteria.where("appStatus").in(6, 8, 9)), KylinPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
    }

    public Document getObjectTicketVo(HashMap<String, Object> map, String ticketsId) {
        BasicDBObject objectTicketVo = new BasicDBObject("$set", mongoConverter.convertToMongoType(map));
        Document docTicket = mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).findOneAndUpdate(
                Query.query(Criteria.where("ticketsId").is(ticketsId)).getQueryObject(),
                objectTicketVo,
                new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
        );
        return docTicket;
    }

    public List<PerformancePartnerListDao> getPerformanceList(PerformancePartnerListParam performancePartnerListParam) {
        performancePartnerListParam.setOrderType(performancePartnerListParam.getOrderType());
        //分页排序
        Sort.Direction orderBy = Sort.Direction.DESC;
        if (performancePartnerListParam.getOrderSc().equals("asc")) {
            orderBy = Sort.Direction.ASC;
        }
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.project("performancesId", "title", "timeStart", "timeEnd", "timeSell", "timeStop", "totalGeneral", "saleGeneral", "totalSalePrice",
                        "surplusGeneral", "status", "type", "auditStatus", "rejectTxt", "createdAt","payCountdownMinute",
                        "ticketTimeList", "ticketList","appStatus",
                        "performanceId", "couponType", "transferStatus", "number", "refundNumber", "priceActual", "priceRefund"),
                Aggregation.lookup(KylinOrderTicketVo.class.getSimpleName(),"performanceId","performancesId","o"),
                Aggregation.match(Criteria.where("o.status").in(0, 1, 3, 6).and("o.couponType").is("no").and("o.transferStatus").in(0, 1, 2, 5)),
                Aggregation.unwind("ticketTimeList"),
                Aggregation.unwind("ticketTimeList.ticketList"),
                Aggregation.group("performancesId").first("performancesId").as("performancesId")
                        .first("title").as("title")
                        .first("timeStart").as("timeStart")
                        .first("timeEnd").as("timeEnd")
                        .first("type").as("type")
                        .first("rejectTxt").as("rejectTxt")
                        .first("createdAt").as("createdAt")
                        .first("appStatus").as("status")
                        .first("auditStatus").as("auditStatus")
                        .first("payCountdownMinute").as("payCountdownMinute")
                        .min("ticketTimeList.ticketList.timeStart").as("timeSell")
                        .sum("totalGeneral").as("totalGeneral")
                        .sum("o.number").as("number")
                        .sum("o.refundNumber").as("refundNumber")
                        .sum("o.priceActual").as("priceActual")
                        .sum("o.priceRefund").as("priceRefund")
                        .max("ticketTimeList.ticketList.timeEnd").as("timeStop"),
                Aggregation.skip((performancePartnerListParam.getPage() - 1) * performancePartnerListParam.getSize()),
                Aggregation.limit(performancePartnerListParam.getSize()),
                Aggregation.sort(orderBy,performancePartnerListParam.getOrderItem())
        );
        AggregationResults<PerformancePartnerListDao> outputType = mongoTemplate.aggregate(aggregation, KylinPerformanceVo.class.getSimpleName(), PerformancePartnerListDao.class);
        List<PerformancePartnerListDao> list = outputType.getMappedResults();
        return list;
    }
}
