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

import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.adam.dto.vo.AdamAddressesVo;
import com.liquidnet.service.adam.dto.vo.AdamEntersVo;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.feign.adam.api.FeignAdamBaseClient;
import com.liquidnet.service.kylin.dto.param.PayOrderParam;
import com.liquidnet.service.kylin.dto.vo.*;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.mapper.KylinOrderTicketsMapper;
import com.liquidnet.service.kylin.service.IKylinOrderTicketsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.service.kylin.utils.DataUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author liquidnet
 * @since 2021-05-20
 */
@Service
public class KylinOrderTicketsServiceImpl extends ServiceImpl<KylinOrderTicketsMapper, KylinOrderTickets> implements IKylinOrderTicketsService {

    @Autowired
    private DataUtils dataUtils;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private FeignAdamBaseClient feignAdamBaseClient;

    @Override
    public ResponseDto<String> checkCanOrder(PayOrderParam payOrderParam) {
        boolean isDownGeneral = false;
        try {
            String uid = CurrentUtil.getCurrentUid();
            KylinPerformanceVo performanceData = dataUtils.getPerformanceVo(payOrderParam.getPerformanceId());
            KylinTicketTimesVo ticketTimesData = dataUtils.getTicketTimesVo(payOrderParam.getTimeId());
            KylinTicketVo ticketData = dataUtils.getTicketVo(payOrderParam.getTicketId());
            if (performanceData == null || ticketTimesData == null || ticketData == null) {
                return ResponseDto.failure("参数错误");//参数错误
            }
            if (!ticketData.getTimeId().equals(payOrderParam.getTimeId()) || !ticketTimesData.getPerformanceId().equals(payOrderParam.getPerformanceId())) {
                return ResponseDto.failure("参数错误");//参数错误List<AdamEntersVo> entersVoList
            }
            //会员时间获取
            String memberTimeStart = ticketData.getMemberTimeStart(); // 会员开售时间
            String timeStart = ticketData.getTimeStart(); // 普通开售时间
            String timeEnd = ticketData.getTimeEnd(); // 购票停售时间
            String timeExpressEnd = ticketData.getTimeEndExpress(); // 快递停售时间
            int performanceBuyCount; //演出下所有票种购买数量
            int ticketBuyCount;// 单一票种购买数量
            boolean isMember = feignAdamBaseClient.isMember(uid).getData();//获取是否是会员
//            boolean isMember = false;
            int memberType; //会员状态 不需要判断会员 1判断会员逻辑 2会员专属
            if (ticketData.getIsExclusive() == 1) {
                memberType = 2;
                if (!isMember) {
                    return ResponseDto.failure("非会员用户暂不可购买");//没有会员权限
                }
            } else {
                if (DateUtil.compareStrDay(DateUtil.getNowTime(), memberTimeStart) == 1 && DateUtil.compareStrDay(DateUtil.getNowTime(), timeStart) == -1 && ticketData.getIsMember() == 1) {
                    // 会员购买逻辑
                    memberType = 1;
                    if (!isMember) {
                        return ResponseDto.failure("非会员用户暂不可购买");//没有会员权限
                    }
                } else {
                    // 普通用户购买逻辑
                    memberType = 0;
                }
            }

            // 获取限购 实名
            int ticketLimit = ticketData.getLimitCount();//普通票种限购
            int ticketMemberLimit = ticketData.getLimitCountMember();//会员票种限购
            int performanceLimit = performanceData.getLimitCount();//普通演出限购
            int performanceMemberLimit = performanceData.getLimitCountMember();//会员演出限购
            int isTrueName = ticketData.getIsTrueName();//是否演出实名

            //通用判断时间
            if (isMember) {
                if (DateUtil.compareStrDay(DateUtil.getNowTime(), memberTimeStart) == -1) {
                    return ResponseDto.failure("未开始售卖");//未开始
                }
            } else {
                if (DateUtil.compareStrDay(DateUtil.getNowTime(), timeStart) == -1) {
                    return ResponseDto.failure("未开始售卖");//未开始
                }
            }
            if (DateUtil.compareStrDay(DateUtil.getNowTime(), timeEnd) == 1) {
                return ResponseDto.failure("售卖已结束");//已结束
            }

            //快递票判断
            if (payOrderParam.getIsExpress() == 1 && DateUtil.compareStrDay(DateUtil.getNowTime(), timeExpressEnd) == 1) {
                return ResponseDto.failure("已超过快递票截止时间");//快递票不卖
            }
            if (payOrderParam.getIsExpress() == 1 && payOrderParam.getAddressId().isEmpty()) {
                return ResponseDto.failure("快递票未填写收货地址");//快递票未填写收货地址
            }
            //实名判断
            if (isTrueName == 1 && payOrderParam.getEnterIdList().size() <= 0) {
                return ResponseDto.failure("入场人数量错误");//需要实名 未实名
            }
            if (isTrueName == 1 && payOrderParam.getEnterIdList().size() != payOrderParam.getNumber()) {
                return ResponseDto.failure("入场人数量错误");//入场人数量错误
            }

            // 判断库存
            int surplusGeneral = dataUtils.changeSurplusGeneral(payOrderParam.getTicketId(), -payOrderParam.getNumber());
            if (surplusGeneral < 0) {//库存回滚
                dataUtils.changeSurplusGeneral(payOrderParam.getTicketId(), payOrderParam.getNumber());
                return ResponseDto.failure("该票种已售罄");//没抢到
            } else {
                isDownGeneral = true;
                //限购判断 如果实名 则身份证维度限购 如果不实名则数量限购
                if (isTrueName == 1) {
                    //已购买数量 身份证
                    performanceBuyCount = 0 + payOrderParam.getNumber(); //演出下所有票种购买数量 TODO
                    ticketBuyCount = 0 + payOrderParam.getNumber(); // 单一票种购买数量 TODO
                } else {
                    //已购买数量 数量
                    performanceBuyCount = 0 + payOrderParam.getNumber(); //演出下所有票种购买数量 TODO
                    ticketBuyCount = 0 + payOrderParam.getNumber(); // 单一票种购买数量 TODO
                }
                //会员区间
                if (memberType == 1 || memberType == 2) {
                    if (performanceBuyCount >= performanceMemberLimit && performanceMemberLimit != 0) {
                        return ResponseDto.failure("该演出只能购买" + performanceMemberLimit + "张");//超过演出维度购买量
                    }
                    if (ticketBuyCount >= ticketMemberLimit && ticketMemberLimit != 0) {
                        return ResponseDto.failure("该票种只能购买" + ticketMemberLimit + "张");//超过票维度购买量
                    }
                } else {//非会员区间
                    if (performanceBuyCount >= performanceLimit && performanceLimit != 0) {
                        return ResponseDto.failure("该演出只能购买" + performanceLimit + "张");//超过演出维度购买量
                    }
                    if (ticketBuyCount >= ticketLimit && ticketLimit != 0) {
                        return ResponseDto.failure("该票种只能购买" + ticketLimit + "张");//超过票维度购买量
                    }
                }
                return order(payOrderParam, uid, isMember, isTrueName, performanceData, ticketData);
            }
        } catch (Exception e) {
            if (isDownGeneral) {
                dataUtils.changeSurplusGeneral(payOrderParam.getTicketId(), payOrderParam.getNumber());
            }
            e.printStackTrace();
            return ResponseDto.failure("下单失败");//乱七八糟异常
        }
    }

    @Override
    public ResponseDto<String> order(PayOrderParam payOrderParam, String uid, boolean isMember, int isTrueName, KylinPerformanceVo performanceData, KylinTicketVo ticketData) {
        LinkedList<String> sqls = new LinkedList<>();
        LinkedList<Object[]> paramsList = new LinkedList<>();
        String source = CurrentUtil.getCliSource();
        String version = CurrentUtil.getCliVersion();
        List<AdamEntersVo> entersVoList = new ArrayList();

        //学生票 判断
        if (null != payOrderParam.getIsStudent() && payOrderParam.getIsStudent() == 1) {
            for (String enterId : payOrderParam.getEnterIdList()) {
                AdamEntersVo adamEnters = feignAdamBaseClient.queryEnters(enterId, uid).getData();
                entersVoList.add(adamEnters);
                int age = IDCard.getAgeByIdCard(adamEnters.getIdCard());
                if (age > 25) {
                    return ResponseDto.failure("年龄不符合");//年龄超了
                }
            }
        }
        //生成订单 order_ticket
        KylinOrderTickets orderTickets = new KylinOrderTickets();
        String orderTicketId = IDGenerator.nextSnowId().toString();
        orderTickets.setOrderTicketsId(orderTicketId);
        orderTickets.setUserId(uid);
        Map token = CurrentUtil.getTokenClaims();
        orderTickets.setUserName((String) token.get("nickname"));
        orderTickets.setUserMobile((String)token.get("mobile"));
        orderTickets.setPerformanceTitle(performanceData.getTitle());
        orderTickets.setOrderCode(IDGenerator.ticketOrderCode(orderTicketId));
        orderTickets.setPayCode("");
        orderTickets.setQrCode("");
        orderTickets.setOrderType(source);
        orderTickets.setOrderVersion(version);
        orderTickets.setNumber(payOrderParam.getNumber());
        orderTickets.setPrice(ticketData.getPrice());
        orderTickets.setPriceMember(ticketData.getMemberPrice());
        if (isMember) {
            orderTickets.setPriceTotal(ticketData.getMemberPrice().multiply(new BigDecimal(payOrderParam.getNumber())).add(payOrderParam.getIsExpress() == 1 ? ticketData.getPriceExpress() : new BigDecimal("0")));
        } else {
            orderTickets.setPriceTotal(ticketData.getPrice().multiply(new BigDecimal(payOrderParam.getNumber())).add(payOrderParam.getIsExpress() == 1 ? ticketData.getPriceExpress() : new BigDecimal("0")));
        }
        orderTickets.setPriceVoucher(new BigDecimal("0.0"));
        orderTickets.setPriceActual(new BigDecimal("0.0"));
        orderTickets.setPriceExpress(ticketData.getPriceExpress());
        orderTickets.setPriceRefund(new BigDecimal("0.0"));
        orderTickets.setRefundNumber(0);
        orderTickets.setPayType(payOrderParam.getPayType());
        orderTickets.setPaymentType(null);
        orderTickets.setTimePay(null);
        if (ticketData.getIsExpress() == 1) {
            AdamAddressesVo addressesVo = feignAdamBaseClient.queryAddresses(payOrderParam.getAddressId(), uid).getData();
            orderTickets.setExpressContacts(addressesVo.getName());
            orderTickets.setExpressAddress(addressesVo.getAddress());
            orderTickets.setExpressPhone(addressesVo.getPhone());
            orderTickets.setGetTicketType("express");
        } else {
            orderTickets.setExpressContacts("");
            orderTickets.setExpressAddress("");
            orderTickets.setExpressPhone("");
            orderTickets.setGetTicketType("electronic");
        }
        orderTickets.setCouponType("no");
        orderTickets.setGetTicketDescribe("");
        orderTickets.setPayCountdownMinute(performanceData.getPayCountdownMinute());
        orderTickets.setCreatedAt(LocalDateTime.now());
        orderTickets.setUpdatedAt(null);
        //TODO mq sql
        sqls.add("kylin_order_ticket.add");
        paramsList.add(orderTickets.getAddObject());


        //生成订单 order_ticket_status
        KylinOrderTicketStatus orderTicketStatus = new KylinOrderTicketStatus();
        String orderTicketStatusId = IDGenerator.nextSnowId().toString();
        orderTicketStatus.setOrderTicketStatusId(orderTicketStatusId);
        orderTicketStatus.setOrderId(orderTicketId);
        orderTicketStatus.setExpressType(payOrderParam.getExpressType());
        orderTicketStatus.setTransferStatus(0);
        orderTicketStatus.setStatus(0);
        orderTicketStatus.setIsStudent(payOrderParam.getIsStudent());
        orderTicketStatus.setPayStatus(0);
        orderTicketStatus.setCreatedAt(LocalDateTime.now());
        orderTicketStatus.setUpdatedAt(null);
        //TODO mq sql
        sqls.add("kylin_order_ticket_status.add");
        paramsList.add(orderTicketStatus.getAddObject());

        //生成订单 order_ticket_relation
        KylinOrderTicketRelations orderTicketRelations = new KylinOrderTicketRelations();
        String orderTicketRelationId = IDGenerator.nextSnowId().toString();
        orderTicketRelations.setOrderTicketRelationsId(orderTicketRelationId);
        orderTicketRelations.setOrderId(orderTicketId);
        orderTicketRelations.setTransferId("");
        orderTicketRelations.setLiveId("");
        orderTicketRelations.setAgentId(payOrderParam.getAgentId());
        orderTicketRelations.setIsMember(isMember ? 1 : 0);
        orderTicketRelations.setPerformanceId(payOrderParam.getPerformanceId());
        orderTicketRelations.setTimeId(payOrderParam.getTimeId());
        orderTicketRelations.setTicketId(payOrderParam.getTicketId());
        orderTicketRelations.setCreatedAt(LocalDateTime.now());
        orderTicketRelations.setUpdatedAt(null);
        //TODO mq sql
        sqls.add("kylin_order_ticket_relation.add");
        paramsList.add(orderTicketRelations.getAddObject());


        //生成票
        KylinOrderTicketEntities orderTicketEntities = new KylinOrderTicketEntities();
        String orderTicketEntitiesId = IDGenerator.nextSnowId().toString();
        if (isTrueName == 1) {
            for (AdamEntersVo enters : entersVoList) {
                orderTicketEntities.setOrderTicketEntitiesId(orderTicketEntitiesId);
                orderTicketEntities.setOrderId(orderTicketId);
                orderTicketEntities.setTicketId(payOrderParam.getTicketId());
                orderTicketEntities.setUserId(uid);
                orderTicketEntities.setPerformanceId(payOrderParam.getPerformanceId());
                orderTicketEntities.setTimeId(payOrderParam.getTimeId());
                orderTicketEntities.setEnterType(enters.getType());
                orderTicketEntities.setEnterName(enters.getName());
                orderTicketEntities.setEnterMobile(enters.getMobile());
                orderTicketEntities.setEnterIdCode(enters.getIdCard());
                orderTicketEntities.setStatus(0);
                orderTicketEntities.setSysDamai(ticketData.getSysDamai());
                orderTicketEntities.setCheckClient("");
                orderTicketEntities.setIsPayment(0);
                orderTicketEntities.setComment("");
                orderTicketEntities.setCreatedAt(LocalDateTime.now());
                orderTicketEntities.setUpdatedAt(null);
                //TODO mq sql
                sqls.add("kylin_order_ticket_entities.add");
                paramsList.add(orderTicketEntities.getAddObject());
                // 生成vo
                KylinOrderTicketEntitiesVo orderTicketEntitiesVo = new KylinOrderTicketEntitiesVo();
                BeanUtils.copyProperties(orderTicketEntities, orderTicketEntitiesVo);
                mongoTemplate.insert(orderTicketEntitiesVo,KylinOrderTicketEntitiesVo.class.getSimpleName());
            }
        } else {
            for (int i = 0; i < payOrderParam.getNumber(); i++) {
                orderTicketEntities.setOrderTicketEntitiesId(orderTicketEntitiesId);
                orderTicketEntities.setOrderId(orderTicketId);
                orderTicketEntities.setTicketId(payOrderParam.getTicketId());
                orderTicketEntities.setUserId(uid);
                orderTicketEntities.setPerformanceId(payOrderParam.getPerformanceId());
                orderTicketEntities.setTimeId(payOrderParam.getTimeId());
                orderTicketEntities.setEnterType(0);
                orderTicketEntities.setEnterName("");
                orderTicketEntities.setEnterMobile("");
                orderTicketEntities.setEnterIdCode("");
                orderTicketEntities.setStatus(0);
                orderTicketEntities.setSysDamai(ticketData.getSysDamai());
                orderTicketEntities.setCheckClient("");
                orderTicketEntities.setIsPayment(0);
                orderTicketEntities.setComment("");
                orderTicketEntities.setCreatedAt(LocalDateTime.now());
                orderTicketEntities.setUpdatedAt(null);
                //TODO mq sql
                sqls.add("kylin_order_ticket_entities.add");
                paramsList.add(orderTicketEntities.getAddObject());
                // 生成vo
                KylinOrderTicketEntitiesVo orderTicketEntitiesVo = new KylinOrderTicketEntitiesVo();
                BeanUtils.copyProperties(orderTicketEntities, orderTicketEntitiesVo);
                mongoTemplate.insert(orderTicketEntitiesVo,KylinOrderTicketEntitiesVo.class.getSimpleName());
            }
        }
        // 调用支付 别忘记生成支付单号
        orderTickets.setPayCode("");
        // 生成vo
        KylinOrderTicketVo orderTicketVo = new KylinOrderTicketVo();
        orderTicketVo.setOrderTicket(orderTickets);
        orderTicketVo.setOrderTicketStatus(orderTicketStatus);
        orderTicketVo.setOrderTicketRelation(orderTicketRelations);
        mongoTemplate.insert(orderTicketVo,KylinOrderTicketVo.class.getSimpleName());
        // 执行sql
//        rabbitTemplate.convertAndSend(MQConst.EXCHANGES_LIQUIDNET_SQL, MQConst.ROUTING_KEY_SQL,
//                SqlMapping.get(sqls, paramsList));
        return ResponseDto.success("下单完成");
    }
}
