package com.liquidnet.service.platform.service.impl.partner;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.UserPathDto;
import com.liquidnet.service.kylin.dto.param.PerformancePartnerVo;
import com.liquidnet.service.kylin.dto.param.TicketCreateParam;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketPartnerVo;
import com.liquidnet.service.kylin.dto.vo.partner.KylinTicketTimesPartnerVo;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.mapper.*;
import com.liquidnet.service.kylin.service.partner.IKylinTicketsPartnerService;
import com.liquidnet.service.platform.utils.ObjectUtil;
import com.liquidnet.service.platform.utils.PerformanceVoTask;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import io.github.classgraph.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
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.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;

/**
 * <p>
 * 票 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-05-06
 */
@Service
@Slf4j
public class KylinTicketsPartnerServiceImpl extends ServiceImpl<KylinTicketsMapper, KylinTickets> implements IKylinTicketsPartnerService {

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private MongoConverter mongoConverter;

    @Autowired
    private KylinPerformanceStatusMapper performanceStatusMapper;

    @Autowired
    private KylinTicketTimeRelationMapper ticketTimeRelationMapper;


    @Autowired
    private KylinTicketStatusMapper ticketStatusMapper;

    @Autowired
    private KylinTicketRelationsMapper ticketRelationsMapper;
    @Autowired
    private PerformanceVoTask performanceVoTask;

    @Override
    public ResponseDto<KylinTicketPartnerVo> createTicketSummary(TicketCreateParam ticketCreateParam) {
        ResponseDto<KylinTicketPartnerVo> ticketPartnerVo = null;
        //获取演出状态
        KylinTicketTimesPartnerVo timesPartnerVo = mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(ticketCreateParam.getTimesId())), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());

        if (null != timesPartnerVo) {
            KylinPerformanceStatus performanceStatus = performanceStatusMapper.selectOne(
                    Wrappers.lambdaQuery(KylinPerformanceStatus.class).eq(KylinPerformanceStatus::getPerformanceId, timesPartnerVo.getPerformancesId()));
            if (null == performanceStatus) {
                ticketPartnerVo = createTicket(ticketCreateParam);
                log.info(UserPathDto.setPartnerData("0","createTicket", ticketCreateParam,ticketPartnerVo));
            } else if (performanceStatus.getStatus() >= 3 && performanceStatus.getStatus() != 4) {//未被拒绝 且 通过审核的演出
                ticketPartnerVo = addNewTicket(ticketCreateParam);
                log.info(UserPathDto.setPartnerData("0","addNewTicket", ticketCreateParam,ticketPartnerVo));
            } else {
                ticketPartnerVo = createTicket(ticketCreateParam);
                log.info(UserPathDto.setPartnerData("0","createTicket", ticketCreateParam,ticketPartnerVo));
            }
        } else {
            ticketPartnerVo = createTicket(ticketCreateParam);
            log.info(UserPathDto.setPartnerData("0","createTicket", ticketCreateParam,ticketPartnerVo));
        }
        return ticketPartnerVo;
    }

    @Override
    public ResponseDto<KylinTicketPartnerVo> createTicket(TicketCreateParam ticketCreateParam) {
        try {
            // 获取 主键id
            String ticketsId = IDGenerator.nextSnowId().toString();
            // 获取 当前时间 -> 创建时间
            LocalDateTime createdAt = LocalDateTime.now();
            ticketCreateParam.setTicketsId(ticketsId);

            // mongo 操作
            KylinTicketPartnerVo kylinTicketPartnerVo = KylinTicketPartnerVo.getNew();
            BeanUtils.copyProperties(ticketCreateParam, kylinTicketPartnerVo);
            kylinTicketPartnerVo.setTicketsId(ticketsId);
            kylinTicketPartnerVo.setCreatedAt(DateUtil.Formatter.yyyyMMddHHmmss.format(createdAt));
            kylinTicketPartnerVo.setTimeStart(DateUtil.Formatter.yyyyMMddHHmmss.format(ticketCreateParam.getTimeStart()));
            kylinTicketPartnerVo.setTimeEnd(ticketCreateParam.getTimeEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

            KylinTicketTimesPartnerVo kylinTicketTimesPartnerVo = mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(ticketCreateParam.getTimesId())), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
            kylinTicketPartnerVo.setUseStart(kylinTicketTimesPartnerVo.getUseStart());
            kylinTicketPartnerVo.setUseEnd(kylinTicketTimesPartnerVo.getUseEnd());
            kylinTicketPartnerVo.setType(kylinTicketTimesPartnerVo.getType());
            kylinTicketPartnerVo.setStatus(0);
            kylinTicketPartnerVo.setDefault();
            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setDescribeExpress(ticketCreateParam.getDescribeExpress() == null ? "" : ticketCreateParam.getDescribeExpress());
            } else {
                kylinTicketPartnerVo.setDescribeExpress("");
            }
            if (ticketCreateParam.getIsElectronic() == 1) {
                kylinTicketPartnerVo.setDescribeElectronic(ticketCreateParam.getDescribeElectronic() == null ? "" : ticketCreateParam.getDescribeElectronic());
            } else {
                kylinTicketPartnerVo.setDescribeElectronic("");
            }

            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setTimeEndExpress(ticketCreateParam.getTimeEndExpress().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }

            if (ticketCreateParam.getIsShowCode() == 1) {
                kylinTicketPartnerVo.setQrCodeShowTime(ticketCreateParam.getQrCodeShowTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }

            KylinTicketPartnerVo data = mongoTemplate.insert(
                    kylinTicketPartnerVo, KylinTicketPartnerVo.class.getSimpleName()
            );

            return ResponseDto.success(kylinTicketPartnerVo);
        } catch (Exception e) {
            return ResponseDto.failure(ErrorMapping.get(20105));
        }
    }

    @Override
    public ResponseDto<KylinTicketPartnerVo> addNewTicket(TicketCreateParam ticketCreateParam) {
        try {
            // 获取 主键id
            String ticketsId = IDGenerator.nextSnowId().toString();
            // 获取 当前时间 -> 创建时间
            LocalDateTime createdAt = LocalDateTime.now();
            ticketCreateParam.setTicketsId(ticketsId);

            // mongo 操作
            KylinTicketPartnerVo kylinTicketPartnerVo = KylinTicketPartnerVo.getNew();
            BeanUtils.copyProperties(ticketCreateParam, kylinTicketPartnerVo);
            kylinTicketPartnerVo.setTicketsId(ticketsId);
            kylinTicketPartnerVo.setCreatedAt(createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTimeStart(ticketCreateParam.getTimeStart().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTimeEnd(ticketCreateParam.getTimeEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

            KylinTicketTimesPartnerVo kylinTicketTimesPartnerVo = mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(ticketCreateParam.getTimesId())), KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());
            kylinTicketPartnerVo.setUseStart(kylinTicketTimesPartnerVo.getUseStart());
            kylinTicketPartnerVo.setUseEnd(kylinTicketTimesPartnerVo.getUseEnd());
            kylinTicketPartnerVo.setType(kylinTicketTimesPartnerVo.getType());
            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setDescribeExpress(ticketCreateParam.getDescribeExpress() == null ? "" : ticketCreateParam.getDescribeExpress());
            } else {
                kylinTicketPartnerVo.setDescribeExpress("");
            }
            if (ticketCreateParam.getIsElectronic() == 1) {
                kylinTicketPartnerVo.setDescribeElectronic(ticketCreateParam.getDescribeElectronic() == null ? "" : ticketCreateParam.getDescribeElectronic());
            } else {
                kylinTicketPartnerVo.setDescribeElectronic("");
            }

            kylinTicketPartnerVo.setStatus(-2);
            kylinTicketPartnerVo.setDefault();

            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setTimeEndExpress(ticketCreateParam.getTimeEndExpress().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }

            if (ticketCreateParam.getIsShowCode() == 1) {
                kylinTicketPartnerVo.setQrCodeShowTime(ticketCreateParam.getQrCodeShowTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }

            KylinTicketPartnerVo data = mongoTemplate.insert(
                    kylinTicketPartnerVo, KylinTicketPartnerVo.class.getSimpleName()
            );

            return ResponseDto.success(kylinTicketPartnerVo);
        } catch (Exception e) {
            return ResponseDto.failure(ErrorMapping.get(20101));
        }
    }

    @Override
    public ResponseDto<KylinTicketPartnerVo> updateTicket(TicketCreateParam ticketCreateParam) {
        try {
            KylinTicketTimesPartnerVo ticketTimeRelation = mongoTemplate.findOne(Query.query(Criteria.where("ticketTimesId").is(ticketCreateParam.getTimesId())),
                    KylinTicketTimesPartnerVo.class, KylinTicketTimesPartnerVo.class.getSimpleName());

            PerformancePartnerVo data = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(ticketTimeRelation.getPerformancesId())),
                    PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
            if (data == null || data.getAuditStatus() == null || data.getAuditStatus() == 0) {
                return ResponseDto.failure(ErrorMapping.get("20112"));
            }

            String ticketId = ticketCreateParam.getTicketsId();
            LocalDateTime updatedAt = LocalDateTime.now();
            // mongo 操作
            KylinTicketPartnerVo kylinTicketPartnerVo = KylinTicketPartnerVo.getNew();
            BeanUtils.copyProperties(ticketCreateParam, kylinTicketPartnerVo);
            kylinTicketPartnerVo.setUpdatedAt(updatedAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTimeStart(ticketCreateParam.getTimeStart().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTimeEnd(ticketCreateParam.getTimeEnd().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTimesId(null);
            kylinTicketPartnerVo.setStatus(null);
            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setDescribeExpress(ticketCreateParam.getDescribeExpress() == null ? "" : ticketCreateParam.getDescribeExpress());
            }
            if (ticketCreateParam.getIsElectronic() == 1) {
                kylinTicketPartnerVo.setDescribeElectronic(ticketCreateParam.getDescribeElectronic() == null ? "" : ticketCreateParam.getDescribeElectronic());
            }

            kylinTicketPartnerVo.setDefault();
            if (ticketCreateParam.getIsExpress() == 1) {
                kylinTicketPartnerVo.setTimeEndExpress(ticketCreateParam.getTimeEndExpress().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }
            if (ticketCreateParam.getIsShowCode() == 1) {
                kylinTicketPartnerVo.setQrCodeShowTime(ticketCreateParam.getQrCodeShowTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            }

            BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(kylinTicketPartnerVo));
            Document doc = mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).findOneAndUpdate(
                    Query.query(Criteria.where("ticketsId").is(ticketId)).getQueryObject(),
                    object,
                    new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
            );

            KylinTicketPartnerVo kylinTicketPartnerVoData = JsonUtils.fromJson(doc.toJson(), KylinTicketPartnerVo.class);
            log.info(UserPathDto.setPartnerData("0","updateTicket", ticketCreateParam,kylinTicketPartnerVoData));
            return ResponseDto.success(kylinTicketPartnerVoData);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get(20103));
        }
    }

    @Override
    public ResponseDto<String> deleteTicket(String ticketsId) {
        try {
            LocalDateTime updatedAt = LocalDateTime.now();

            KylinTicketRelations ticketRelations = ticketRelationsMapper.selectOne(
                    Wrappers.lambdaQuery(KylinTicketRelations.class).eq(KylinTicketRelations::getTicketId, ticketsId));

            if (ticketRelations == null) {
                mongoTemplate.remove(Query.query(Criteria.where("ticketsId").is(ticketsId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
                return ResponseDto.success("删除成功");
            }
            KylinTicketTimeRelation ticketTimeRelation = ticketTimeRelationMapper.selectOne(
                    Wrappers.lambdaQuery(KylinTicketTimeRelation.class).eq(KylinTicketTimeRelation::getTimesId, ticketRelations.getTimesId()));
            PerformancePartnerVo data = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(ticketTimeRelation.getPerformanceId())),
                    PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
            if (data == null || data.getAuditStatus() == null || data.getAuditStatus() == 0) {
                return ResponseDto.failure(ErrorMapping.get("20106"));
            }

            KylinPerformanceStatus performanceStatus = performanceStatusMapper.selectOne(
                    Wrappers.lambdaQuery(KylinPerformanceStatus.class).eq(KylinPerformanceStatus::getPerformanceId, ticketTimeRelation.getPerformanceId()));

            if (performanceStatus.getStatus() == 0 || performanceStatus.getStatus() == 4) {//未提审||被拒绝
                // mongo 操作
                HashMap<String, Object> map = ObjectUtil.cloneHashMapStringAndObject();
                map.put("updatedAt", updatedAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                map.put("status", -1);

                BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(map));
                mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("ticketsId").is(ticketsId)).getQueryObject(),
                        object
                );
                log.info(UserPathDto.setPartnerData("0","deleteTicket", "ticketsId="+ticketsId,"删除成功"));
                return ResponseDto.success("删除成功");
            } else {
                return ResponseDto.failure(ErrorMapping.get(20106));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get(20102));
        }
    }

    @Override
    public ResponseDto<KylinTicketPartnerVo> copyTicket(String performanceId, String ticketsId) {
        try {
            // 获取 当前时间 -> 创建时间
            LocalDateTime createdAt = LocalDateTime.now();

            PerformancePartnerVo performancePartnerVo = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)), PerformancePartnerVo.class, PerformancePartnerVo.class.getSimpleName());
            if (performancePartnerVo.getAuditStatus() == 0 || performancePartnerVo.getAuditStatus() == 1) {
                return ResponseDto.failure(ErrorMapping.get(20107));
            }

            KylinTicketPartnerVo kylinTicketPartnerVo = mongoTemplate.findOne(Query.query(Criteria.where("ticketsId").is(ticketsId)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
            kylinTicketPartnerVo.setCreatedAt(createdAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            kylinTicketPartnerVo.setTicketsId(IDGenerator.nextSnowId().toString());

            KylinTicketPartnerVo data = mongoTemplate.insert(
                    kylinTicketPartnerVo, KylinTicketPartnerVo.class.getSimpleName()
            );
            log.info(UserPathDto.setPartnerData("0","deleteTicket", "performanceId="+performanceId+",ticketsId="+ticketsId,kylinTicketPartnerVo));
            return ResponseDto.success(kylinTicketPartnerVo);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get(20107));
        }
    }

    @Override
    public boolean submitTicketByTimes(String timesId, Integer status) {
        LocalDateTime updatedAt = LocalDateTime.now();

        HashMap<String, Object> map = ObjectUtil.cloneHashMapStringAndObject();
        if (null == status) {
            map.put("status", 1);
        } else {
            map.put("status", status);
        }
        map.put("updatedAt", updatedAt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(map));
        mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateMany(
                Query.query(Criteria.where("timesId").is(timesId).and("status").nin(-2, 7)).getQueryObject(),
                object
        );

        long count = mongoTemplate.count(
                Query.query(Criteria.where("timesId").is(timesId)),
                KylinTicketPartnerVo.class,
                KylinTicketPartnerVo.class.getSimpleName()
        );
        return count <= 0;
    }

    @Override
    public List<KylinTicketPartnerVo> getTicketMongoList(String timesId) {
        return mongoTemplate.find(Query.query(Criteria.where("timesId").is(timesId).and("status").ne(-1)), KylinTicketPartnerVo.class, KylinTicketPartnerVo.class.getSimpleName());
    }

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

    @Override
    public ResponseDto<String> onLine(String ticketsId, String performancesId) {
        try {
            LocalDateTime updatedAt = LocalDateTime.now();
            KylinTicketStatus ticketStatus = ticketStatusMapper.selectOne(Wrappers.lambdaQuery(KylinTicketStatus.class).eq(KylinTicketStatus::getTicketId, ticketsId));
            if (ticketStatus.getStatus() >= 3 && ticketStatus.getStatus() != 4 && ticketStatus.getStatus() != 6) {//未提审||被拒绝
                //mysql
                KylinTicketStatus changeStatus = KylinTicketStatus.getNew();
                changeStatus.setUpdatedAt(updatedAt);
                changeStatus.setStatus(9);
                ticketStatusMapper.update(changeStatus, Wrappers.lambdaQuery(KylinTicketStatus.class).eq(KylinTicketStatus::getTicketId, ticketsId));


                HashMap<String, Object> map = ObjectUtil.cloneHashMapStringAndObject();
                map.put("status", 9);
                BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(map));
                mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("ticketsId").is(ticketsId)).getQueryObject(),
                        object
                );

                performanceVoTask.performanceVoStatus(performancesId);
                log.info(UserPathDto.setPartnerData("0","onLine", "performancesId="+performancesId+",ticketsId="+ticketsId,"上线成功"));
                return ResponseDto.success("上线成功");
            } else {
                return ResponseDto.failure(ErrorMapping.get(20110));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get(20108));
        }
    }

    @Override
    public ResponseDto<String> outLine(String ticketsId, String performancesId) {
        try {
            LocalDateTime updatedAt = LocalDateTime.now();
            KylinTicketStatus ticketStatus = ticketStatusMapper.selectOne(Wrappers.lambdaQuery(KylinTicketStatus.class).eq(KylinTicketStatus::getTicketId, ticketsId));
            if (ticketStatus.getStatus() >= 3 && ticketStatus.getStatus() != 4 && ticketStatus.getStatus() != 7) {//未提审||被拒绝
                //mysql
                KylinTicketStatus changeStatus = KylinTicketStatus.getNew();
                changeStatus.setUpdatedAt(updatedAt);
                changeStatus.setStatus(7);
                ticketStatusMapper.update(changeStatus, Wrappers.lambdaQuery(KylinTicketStatus.class).eq(KylinTicketStatus::getTicketId, ticketsId));
                // mongo 操作
                HashMap<String, Object> map = ObjectUtil.cloneHashMapStringAndObject();
                map.put("status", 7);
                BasicDBObject object = ObjectUtil.cloneBasicDBObject().append("$set", mongoConverter.convertToMongoType(map));
                mongoTemplate.getCollection(KylinTicketPartnerVo.class.getSimpleName()).updateOne(
                        Query.query(Criteria.where("ticketsId").is(ticketsId)).getQueryObject(),
                        object
                );

                performanceVoTask.performanceVoStatus(performancesId);
                log.info(UserPathDto.setPartnerData("0","outLine", "performancesId="+performancesId+",ticketsId="+ticketsId,"下线成功"));
                return ResponseDto.success("下线成功");
            } else {
                return ResponseDto.failure(ErrorMapping.get(20111));
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseDto.failure(ErrorMapping.get(20109));
        }
    }

}
