package com.liquidnet.service.slime.service.impl;

import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import com.liquidnet.service.feign.platform.api.FeignPlatformTicketSystemClient;
import com.liquidnet.service.kylin.constant.KylinRedisConst;
import com.liquidnet.service.kylin.dto.vo.middle.KylinTicketVo;
import com.liquidnet.service.kylin.dto.vo.mongo.KylinOrderTicketEntitiesVo;
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.ticketSystem.CheckVo;
import com.liquidnet.service.slime.constant.SlimeAuthorizationConst;
import com.liquidnet.service.slime.dto.param.SlimeStationUploadParam;
import com.liquidnet.service.slime.dto.vo.*;
import com.liquidnet.service.slime.util.ObjectUtil;
import com.liquidnet.service.slime.util.QueueUtil;
import com.mongodb.bulk.BulkWriteResult;
import com.mongodb.client.model.UpdateOneModel;
import com.mongodb.client.model.WriteModel;
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.data.mongodb.core.MongoTemplate;
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.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SlimeStationService {
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    QueueUtil queueUtil;
    @Autowired
    RedisUtil redisUtil;

//    @Autowired
//    FeignPlatformTicketSystemClient feignPlatformTicketSystemClient;

    /**
     * 查取用户存在权限的演出
     *
     * @param checkUserId UID
     * @return List<SlimeAuthorizationPerformanceVo>
     */
    public List<SlimeAuthorizationPerformanceVo> getCheckUserRelationVo(String checkUserId) {
        return mongoTemplate.find(
                Query.query(Criteria.where("uid").is(checkUserId).and("permissionIds").in(
                        SlimeAuthorizationConst.PerformancePermission.SALES.getId(),
                        SlimeAuthorizationConst.PerformancePermission.CHECK.getId())
                ),
                SlimeAuthorizationPerformanceVo.class, SlimeAuthorizationPerformanceVo.class.getSimpleName());
    }

    /**
     * 销售统计数据整理
     *
     * @param r                               演出基础信息
     * @param performanceTicketEntitiesVoList 演出订单票明细：Map<performanceId, List<KylinOrderTicketEntitiesVo>>
     */
    public void salesStatisticsSetter(SlimeStationPerformanceVo r, List<KylinOrderTicketEntitiesVo> performanceTicketEntitiesVoList) {
        try {
            List<KylinTicketVo> performanceTicketVoList = ObjectUtil.getKylinTicketVoArrayList();
            r.getTicketTimeList().forEach(tt -> performanceTicketVoList.addAll(tt.getTicketList()));// 提取演出对应票种信息

            // 转换票种信息结构为Map<ticketsId, ticketVo>
            Map<String, KylinTicketVo> performanceTicketMap = performanceTicketVoList.stream().collect(Collectors.toMap(KylinTicketVo::getTicketsId, Function.identity(), (k1, k2) -> k2));
            if (log.isDebugEnabled()) {
                log.debug("performanceTicketMap:{}", JsonUtils.toJson(performanceTicketMap));
            }

            // 订单票明细按票种分组
            Map<String, List<KylinOrderTicketEntitiesVo>> performanceTicketEntitiesVoMap =
                    performanceTicketEntitiesVoList.stream().collect(Collectors.groupingBy(KylinOrderTicketEntitiesVo::getTicketId));

            List<SlimeStationTicketVo> ticketVoList = ObjectUtil.getSlimeStationTicketVoArrayList();

            BigDecimal priceSum = BigDecimal.ZERO;
            int number = 0, checkedNum = 0, remainderNum = 0;
            for (Map.Entry<String, List<KylinOrderTicketEntitiesVo>> entry : performanceTicketEntitiesVoMap.entrySet()) {
                KylinTicketVo ticketVo = performanceTicketMap.get(entry.getKey());

                SlimeStationTicketVo stationTicketVo = SlimeStationTicketVo.getNew();
                stationTicketVo.setTicketId(ticketVo.getTicketsId());
                stationTicketVo.setTitle(ticketVo.getTitle());
                stationTicketVo.setPrice(ticketVo.getPrice());
                stationTicketVo.setUseStart(ticketVo.getUseStart());
                stationTicketVo.setUseEnd(ticketVo.getUseEnd());

                List<KylinOrderTicketEntitiesVo> subPerformanceTicketEntitiesVoList = entry.getValue();
                // 订单票明细按出票状态分组
                Map<Integer, List<KylinOrderTicketEntitiesVo>> subStatusPerformanceTicketEntitiesVoMap
                        = subPerformanceTicketEntitiesVoList.stream().collect(Collectors.groupingBy(KylinOrderTicketEntitiesVo::getStatus));

                stationTicketVo.setNumber(subPerformanceTicketEntitiesVoList.size());
                stationTicketVo.setPriceSum(stationTicketVo.getPrice().multiply(BigDecimal.valueOf(stationTicketVo.getNumber())));
                List<KylinOrderTicketEntitiesVo> checkedEntitiesVoList = subStatusPerformanceTicketEntitiesVoMap.get(1);
                stationTicketVo.setCheckedNum(CollectionUtils.isEmpty(checkedEntitiesVoList) ? 0 : checkedEntitiesVoList.size());
                List<KylinOrderTicketEntitiesVo> remainderEntitiesVoList = subStatusPerformanceTicketEntitiesVoMap.get(0);
                stationTicketVo.setRemainderNum(CollectionUtils.isEmpty(remainderEntitiesVoList) ? 0 : remainderEntitiesVoList.size());

                number += stationTicketVo.getNumber();
                checkedNum += stationTicketVo.getCheckedNum();
                remainderNum += stationTicketVo.getRemainderNum();
                priceSum = priceSum.add(stationTicketVo.getPriceSum());

                ticketVoList.add(stationTicketVo);
            }
            r.setPriceSum(priceSum);
            r.setNumber(number);
            r.setCheckedNum(checkedNum);
            r.setRemainderNum(remainderNum);
            r.setTicketVoList(ticketVoList);
        } catch (Exception e) {
            log.error("验票:整合销售统计异常[station/performances],performancesId:{}", r.getPerformancesId(), e);
        }
    }

    /**
     * 上载验票数据
     *
     * @param parameter SlimeStationUploadParam
     */
    public void updateByStation(SlimeStationUploadParam parameter) {
//        // 根据验票用户ID分组
//        Map<String, List<KylinStationCheckOrderParam>> checkOrderByUserIdMap = checkOrderParamList.stream().collect(Collectors.groupingBy(KylinStationCheckOrderParam::getCheckUserId));
//
//        for (Map.Entry<String, List<KylinStationCheckOrderParam>> entry : checkOrderByUserIdMap.entrySet()) {
//            List<KylinStationCheckOrderParam> checkOrderByUserList = entry.getValue();
//
//            // 根据验票类型分组
//            Map<String, List<KylinStationCheckOrderParam>> checkOrderByCheckTypeMap = checkOrderByUserList.stream().collect(Collectors.groupingBy(KylinStationCheckOrderParam::getCheckType));
//        }

        LocalDateTime nowDt = LocalDateTime.now();
        String nowDtStr = DateUtil.format(nowDt, DateUtil.Formatter.yyyyMMddHHmmss);
        LinkedList<Object[]> paramsList = CollectionUtil.linkedListObjectArr();
        List<String> orderTicketEntitiesIdList = CollectionUtil.arrayListString();
        List<WriteModel<Document>> list = ObjectUtil.getWriteModelDocumentArrayList();
        parameter.getCheckOrderParamList().forEach(r -> {
            if (StringUtils.isNotBlank(r.getTicketEntitiesId())) {
                KylinOrderTicketEntitiesVo updateVo = KylinOrderTicketEntitiesVo.getNew();
                updateVo.setStatus(1);// 出票状态: 0未出票 1已出票
                updateVo.setCheckClient(parameter.getCheckClient());
                updateVo.setUpdatedAt(nowDtStr);
                updateVo.setCheckType(r.getCheckType());
                updateVo.setCheckedAt(r.getCheckedAt());
                updateVo.setCheckUserId(r.getCheckUserId());

                paramsList.add(new Object[]{1, updateVo.getCheckClient() + updateVo.getCheckType(), nowDt, r.getTicketEntitiesId()});
                Document updateQuery = Query.query(Criteria.where("orderTicketEntitiesId").is(r.getTicketEntitiesId())).getQueryObject();
                Document updateDoc = new Document("status", updateVo.getStatus())
                        .append("checkClient", updateVo.getCheckClient())
                        .append("updatedAt", updateVo.getUpdatedAt())
                        .append("checkType", updateVo.getCheckType())
                        .append("checkedAt", updateVo.getCheckedAt())
                        .append("checkUserId", updateVo.getUserId());
                list.add(new UpdateOneModel<>(updateQuery, new Document("$set", updateDoc)));

                orderTicketEntitiesIdList.add(r.getTicketEntitiesId());
            }
        });
        BulkWriteResult bulkWriteResult = mongoTemplate.getCollection(KylinOrderTicketEntitiesVo.class.getSimpleName()).bulkWrite(list);
        log.info("验票:上载验票数据[bulkWriteResult:{}]", JsonUtils.toJson(bulkWriteResult));
        if (bulkWriteResult.getModifiedCount() > 0) {
            queueUtil.sendMsgByRedis(MQConst.KylinQueue.SQL_STATION.getKey(),
                    SqlMapping.get("kylin_order_ticket_entities.update_status_bystation", paramsList));


            /* ====================================== 同步票务系统 */
//            ArrayList<CheckVo> checkVos = ObjectUtil.getCheckVoArrayList();
//            Query orderTicketEntitiesVoQuery = Query.query(Criteria.where("orderTicketEntitiesId").in(orderTicketEntitiesIdList));
//            orderTicketEntitiesVoQuery.fields().include("ticketId").include("timeId").include("enterIdCode").include("checkedAt");
//            List<KylinOrderTicketEntitiesVo> checkOrderVos = mongoTemplate.find(orderTicketEntitiesVoQuery, KylinOrderTicketEntitiesVo.class, KylinOrderTicketEntitiesVo.class.getSimpleName());
//            checkOrderVos.forEach(r -> {
//                CheckVo checkVo = CheckVo.getNew();
//                checkVo.setTicketId(r.getTicketId());
//                checkVo.setPriceId(this.getPriceId(r.getTicketId()));
//                checkVo.setSessionId(r.getTimeId());
//                checkVo.setSessionCode(this.getSessionCode(r.getTimeId()));
//                checkVo.setCheckingTime(DateUtil.Formatter.yyyyMMddHHmmss.parse(r.getCheckedAt()));
//                checkVo.setCheckingType(1);
//                checkVo.setAuthType(StringUtils.isEmpty(r.getEnterIdCode()) ? 2 : 1);
//
//                checkVos.add(checkVo);
//            });
//            if (!CollectionUtils.isEmpty(checkVos)) {
//                try {
//                    feignPlatformTicketSystemClient.insertCheck(checkVos);
//                } catch (Exception e) {
//                    log.error("验票:上载验票数据:同步票务系统请求异常");
//                }
//            }
            /* ====================================== ========== */
        }
    }

    /* ====================================== 同步票务系统使用:同Klin逻辑 ====================================== */

    private String getSessionCode(String ticketTimeId) {
        return (String) redisUtil.get(KylinRedisConst.TIMES_SESSION_CODE.concat(ticketTimeId));
    }

    private String getPriceId(String ticketId) {
        return ticketId.concat("01");
    }

    /* ====================================== ======================= ====================================== */

    /**
     * 下载、更新验票数据
     *
     * @param authorizationPerformanceVo 用户演出权限
     * @param performanceId              演出ID
     * @param latestUpdateAt             最近更新时间（仅当更新时必传，下载时传null）
     * @return SlimeStationCheckRefreshVo
     */
    public SlimeStationCheckRefreshVo downloadRefreshTicketData(SlimeAuthorizationPerformanceVo authorizationPerformanceVo, String performanceId, String latestUpdateAt) {
        Criteria criteria = Criteria.where("performanceId").is(performanceId);
        if (StringUtils.isNotEmpty(latestUpdateAt)) {
            criteria.and("updatedAt").gte(latestUpdateAt).and("isPayment").in(1, 2, 3);
        } else {
            criteria.and("isPayment").is(1);
        }
        // 查取演出对应的订单票明细
        Query orderTicketEntitiesVoQuery = Query.query(criteria);
        List<SlimeStationCheckOrderVo> checkOrderVos = mongoTemplate.find(orderTicketEntitiesVoQuery, SlimeStationCheckOrderVo.class, KylinOrderTicketEntitiesVo.class.getSimpleName());
        // 查取订单信息(orderTicketsId,userMobile,userName,qrCode)
        Query query = Query.query(Criteria.where("orderTicketsId").in(checkOrderVos.stream().map(SlimeStationCheckOrderVo::getOrderId).toArray()));
        query.fields().include("orderTicketsId").include("userMobile").include("userName").include("qrCode");
        List<KylinOrderTicketVo> orderTicketVoList = mongoTemplate.find(query, KylinOrderTicketVo.class, KylinOrderTicketVo.class.getSimpleName());
        for (KylinOrderTicketVo t : orderTicketVoList) {
            for (SlimeStationCheckOrderVo r : checkOrderVos) {
                if (r.getOrderId().equals(t.getOrderTicketsId())) {
                    r.setQrCode(t.getQrCode());
                    r.setUserMobile(t.getUserMobile());
                    r.setUserName(t.getUserName());
                }
            }
        }

        // 查取演出信息
        SlimeStationPerformanceVo performanceVo = mongoTemplate.findOne(Query.query(Criteria.where("performancesId").is(performanceId)),
                SlimeStationPerformanceVo.class, KylinPerformanceVo.class.getSimpleName());
        // 提取演出对应票种信息
        List<KylinTicketVo> performanceTicketVoList = ObjectUtil.getKylinTicketVoArrayList();
        performanceVo.getTicketTimeList().forEach(tt -> performanceTicketVoList.addAll(tt.getTicketList()));

        List<SlimeStationTicketVo> ticketVoList = ObjectUtil.getSlimeStationTicketVoArrayList();
        for (KylinTicketVo r : performanceTicketVoList) {
            SlimeStationTicketVo stationTicketVo = SlimeStationTicketVo.getNew();
            stationTicketVo.setTicketId(r.getTicketsId());
            stationTicketVo.setTitle(r.getTitle());
            stationTicketVo.setPrice(r.getPrice());
            stationTicketVo.setUseStart(r.getUseStart());
            stationTicketVo.setUseEnd(r.getUseEnd());

            ticketVoList.add(stationTicketVo);
        }
        performanceVo.setPermissionIds(StringUtils.join(authorizationPerformanceVo.getPermissionIds().toArray(), "."));
        performanceVo.setTicketTimeList(null);
        performanceVo.setTicketVoList(ticketVoList);

        SlimeStationCheckRefreshVo stationCheckRefreshVo = SlimeStationCheckRefreshVo.getNew();
        stationCheckRefreshVo.setCheckOrderVos(checkOrderVos);
        stationCheckRefreshVo.setPerformanceVo(performanceVo);
        return stationCheckRefreshVo;
    }
}
