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

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.kylin.constant.KylinTableStatusConst;
import com.liquidnet.service.kylin.dao.KylinOrderTicketEntitiesDao;
import com.liquidnet.service.kylin.dto.param.RefundApplyParam;
import com.liquidnet.service.kylin.dto.param.RefundCallbackParam;
import com.liquidnet.service.kylin.entity.*;
import com.liquidnet.service.kylin.mapper.*;
import com.liquidnet.service.kylin.service.IKylinOrderRefundsService;
import com.liquidnet.service.kylin.utils.DataUtils;
import lombok.extern.slf4j.Slf4j;
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.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单退款表 服务实现类 处理逻辑判断
 * </p>
 *
 * @author jiangxiulong
 * @since 2021-05-26
 */
@Slf4j
@Service
public class OrderRefundsCallbackServiceImpl extends ServiceImpl<KylinOrderRefundsMapper, KylinOrderRefunds> implements IKylinOrderRefundsService {
    @Autowired
    private KylinRefundsStatusServiceImpl kylinRefundsStatusServiceImpl;

    @Autowired
    private KylinOrderRefundsMapper kylinOrderRefundsMapper;

    @Autowired
    private KylinOrderTicketsMapper kylinOrderTicketsMapper;

    @Autowired
    private KylinOrderTicketStatusMapper kylinOrderTicketStatusMapper;

    @Autowired
    private KylinOrderTicketEntitiesMapper kylinOrderTicketEntitiesMapper;

    @Autowired
    private KylinOrderTicketRelationsMapper kylinOrderTicketRelationsMapper;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private DataUtils dataUtils;

    public String refundCallback(RefundCallbackParam refundCallbackParam) {
        KylinOrderRefunds refundInfo = kylinOrderRefundsMapper.selectOne(
                new UpdateWrapper<KylinOrderRefunds>()
                        .eq("order_refund_code", refundCallbackParam.getOrder_refund_code())
        );
        if (refundInfo == null) {
            log.info("Failed:{}.RefundController refundCallback: 退款订单查询失败，编号{}", "KylinOrderRefundsServiceImplRefundCallback", refundCallbackParam.getOrder_refund_code());
            return "fail";
        }
        if (refundInfo.getStatus() == KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL) {
            log.info("Failed:{}.RefundController refundCallback: 退款订单已取消，编号{}", "KylinOrderRefundsServiceImplRefundCallback", refundCallbackParam.getOrder_refund_code());
            return "fail";
        }
        if (refundInfo.getStatus() == KylinTableStatusConst.ORDER_REFUND_STATUS_REFUNDED) {
            log.info("Failed:{}.RefundController refundCallback: 退款订单已退款，编号{}", "KylinOrderRefundsServiceImplRefundCallback", refundCallbackParam.getOrder_refund_code());
            return "success";
        }

        Integer status = refundCallbackParam.getStatus();
        if (1 == status) { // 退款成功
            boolean res = kylinRefundsStatusServiceImpl.orderTicketRefunded(refundCallbackParam, refundInfo);
            if (res) {
                return "success";
            } else {
                return "fail";
            }
        }
        if (0 == status) { // 退款失败
            KylinOrderRefunds kylinOrderRefunds = new KylinOrderRefunds();
            kylinOrderRefunds.setStatus(KylinTableStatusConst.ORDER_REFUND_STATUS_ERROR);
            kylinOrderRefunds.setRefundCode(refundCallbackParam.getRefund_code());
            kylinOrderRefunds.setRefundType(refundCallbackParam.getRefund_type());
            kylinOrderRefunds.setRefundId(refundCallbackParam.getRefund_id());
            kylinOrderRefunds.setRefundAt(refundCallbackParam.getRefund_at());
            kylinOrderRefunds.setRefundError(refundCallbackParam.getRefund_error());
            kylinOrderRefunds.setUpdatedAt(LocalDateTime.now());

            kylinOrderRefundsMapper.update(
                    kylinOrderRefunds,
                    new UpdateWrapper<KylinOrderRefunds>().eq("order_refund_code", refundCallbackParam.getOrder_refund_code())
            );
        }
        return "success";
    }

    public Boolean refundApply(String orderTicketsId) {
        KylinOrderTickets orderInfo = kylinOrderTicketsMapper.selectOne(
                new QueryWrapper<KylinOrderTickets>().eq("order_tickets_id", orderTicketsId)
        );
        KylinOrderTicketRelations orderRelations = kylinOrderTicketRelationsMapper.selectOne(
                new QueryWrapper<KylinOrderTicketRelations>().eq("order_id", orderTicketsId)
        );
        // 传的快递费不能大于实际的快递费=（支付的快递费-已退的快递费）
        Double refundPriceExpressSum = kylinOrderRefundsMapper.RefundPriceExpressSum(// 已退快递费
                orderTicketsId,
                KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL
        );
        if (null == refundPriceExpressSum) {
            refundPriceExpressSum = 0.0;
        }
        Double RefundPriceExpress = orderInfo.getPriceExpress().doubleValue() - refundPriceExpressSum;

        // 查询订单入场人
        List<KylinOrderTicketEntitiesDao> entitiesListTemp = kylinOrderTicketEntitiesMapper.getRefundEntitiesList(orderTicketsId);
        List<KylinOrderTicketEntitiesDao> entitiesList = new ArrayList<>();

        if(entitiesListTemp.size() > 0) {
            double priceActual = orderInfo.getPriceActual().doubleValue();
            double priceExpress = orderInfo.getPriceExpress().doubleValue();
            int allEntitiesCount = kylinOrderTicketEntitiesMapper.selectCount(// 总入场人数量 排出未付款的 用来计算单入场人的价格
                    new QueryWrapper<KylinOrderTicketEntities>()
                            .eq("order_id", orderInfo.getOrderTicketsId())
                            .ne("is_payment", KylinTableStatusConst.ENTITIES_IS_PAYMENT0)
            );
            double onePrice = (priceActual - priceExpress) / allEntitiesCount;//单价
            for (KylinOrderTicketEntitiesDao entities : entitiesListTemp) {
                Double refundedPrice = kylinOrderTicketEntitiesMapper.getRefundEntitiesPrice(//已退 包含退款中
                        orderInfo.getOrderTicketsId(),
                        KylinTableStatusConst.ORDER_REFUND_STATUS_CANCEL,
                        entities.getOrderTicketEntitiesId()
                );
                double canRefundedPrice;
                if (null != refundedPrice) {
                    canRefundedPrice = onePrice - refundedPrice;
                } else {
                    canRefundedPrice = onePrice;
                }
                entities.setCanRefundedPrice(BigDecimal.valueOf(canRefundedPrice));
                if (canRefundedPrice > 0) { // 退款中但是可退款金额为0不展示
                    entitiesList.add(entities);
                }
            }
        }

        List<String> ticketEntityIds = entitiesList.stream().map(KylinOrderTicketEntities -> KylinOrderTicketEntities.getOrderTicketEntitiesId()).collect(Collectors.toList());
        List<Double> entitiesPrice = entitiesList.stream().map(KylinOrderTicketEntities -> KylinOrderTicketEntities.getCanRefundedPrice().doubleValue()).collect(Collectors.toList());


        boolean res = kylinRefundsStatusServiceImpl.orderTicketRefunding(
                orderInfo, orderTicketsId,
                RefundPriceExpress,
                ticketEntityIds, entitiesPrice
        );
        if (res) {
                // 超时直接退还库存
                for (String entitiesId : ticketEntityIds) {
                    dataUtils.changeSurplusGeneral(entitiesId, 1);
                    KylinOrderTicketEntities entitiesInfo = kylinOrderTicketEntitiesMapper.selectOne(
                            new QueryWrapper<KylinOrderTicketEntities>().eq("order_ticket_entities_id", entitiesId)
                    );
                    dataUtils.changeBuyInfo(orderInfo.getUserId(), "", orderRelations.getPerformanceId(), entitiesInfo.getTicketId(), -1);
                }
            return true;
        } else {
            return false;
        }
    }
}
