
package com.tmerclub.cloud.order.listener;

import cn.hutool.core.collection.CollUtil;
import com.tmerclub.cloud.api.order.constant.OrderStatus;
import com.tmerclub.cloud.api.seckill.feign.SeckillFeignClient;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.SendTypeEnum;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.order.bo.OrderStatusBO;
import com.tmerclub.cloud.common.order.bo.PayNotifyBO;
import com.tmerclub.cloud.common.order.vo.SendNotifyBO;
import com.tmerclub.cloud.common.product.constant.PreSaleType;
import com.tmerclub.cloud.common.product.constant.SupplierDeliveryType;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.rocketmq.config.RocketMqConstant;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.common.util.PriceUtil;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.order.service.OrderService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author tmerclub
 * @date 2021/1/7
 */
@Component
@RocketMQMessageListener(topic = RocketMqConstant.ORDER_NOTIFY_TOPIC, consumerGroup = RocketMqConstant.ORDER_NOTIFY_TOPIC)
public class OrderNotifyConsumer implements RocketMQListener<PayNotifyBO> {

    @Autowired
    private OrderService orderService;
    @Autowired
    private RocketMQTemplate orderNotifyServiceTemplate;
    @Autowired
    private RocketMQTemplate allinPayBalanceOrderSuccessTemplate;
    @Autowired
    private RocketMQTemplate sendNotifyToShopTemplate;
    @Autowired
    private RocketMQTemplate comboOrderMqTemplate;
    @Autowired
    private RocketMQTemplate sendNotifyToUserTemplate;
    @Autowired
    private SegmentManager segmentManager;
    @DubboReference
    private SeckillFeignClient seckillFeignClient;

    private static final Logger LOG = LoggerFactory.getLogger(OrderNotifyConsumer.class);

    @Override
    public void onMessage(PayNotifyBO message) {
        LOG.info("订单回调开始... message: {}", Json.toJsonString(message));
        if (CollUtil.isEmpty(message.getOrderIds())) {
            throw new LuckException("订单回调失败，订单id为空, message: " + Json.toJsonString(message));
        }

        // 如果是秒杀订单，首先改变掉redis中的订单状态，因为这里在这里会执行很多遍，先直接改变状态就好
        // 如果不为空改变redis的订单状态
        if(Objects.nonNull(message.getShopCartOrderMergerVO())) {
            LOG.info("订单回调开始，改变秒杀订单缓存中的状态 message: {}", Json.toJsonString(message));
            seckillFeignClient.updateRedisSeckillOrderStatus(message.getOrderIds().get(0),message.getShopCartOrderMergerVO().getUserId(),OrderStatus.PAYED.value());
        }

        List<OrderStatusBO> ordersStatus = orderService.getOrdersStatus(message.getOrderIds());
        ordersStatus = orderService.updateByToPaySuccess(message, ordersStatus,message.getOrderIds());

        SendStatus comboSendStatus = comboOrderMqTemplate.syncSend(RocketMqConstant.COMBO_ORDER_TOPIC, new GenericMessage<>(message.getOrderIds()), RocketMqConstant.TIMEOUT, RocketMqConstant.COMBO_ORDER_DELAY_LEVEL).getSendStatus();
        if (!Objects.equals(comboSendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，因为订单回调会有多次，几乎不可能每次都无法发送出去，发的出去无所谓因为接口是幂等的
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        Integer orderType = ordersStatus.get(0).getOrderType();
        Integer preSaleType = ordersStatus.get(0).getPreSaleType();
        Integer status = ordersStatus.get(0).getStatus();
        message.setPreSaleType(preSaleType);
        message.setOrderStatus(status);
        message.setOrderType(orderType);

        // 定金预售订单付定金时不用全部分账
        boolean isPreSale = Objects.nonNull(preSaleType) && Objects.equals(preSaleType, PreSaleType.DEPOSIT.value()) && Objects.equals(status, OrderStatus.UNPAY.value());
        if (!isPreSale) {
            int supplierOrderNum = Long.valueOf(ordersStatus.stream().filter(orderStatusBO -> Objects.nonNull(orderStatusBO.getSupplierId())).count()).intValue();
            // 生成店铺钱包日志id列表
            List<Long> ids = segmentManager.listSegmentId(DistributedIdKey.tmerclub_SHOP_WALLET_LOG, ordersStatus.size() + (supplierOrderNum << 1));
            message.setShopWalletIds(ids);
            LOG.info("商家钱包记录ID: {}", message.getShopWalletIds());
        }

        // 发送消息，订单支付成功
        // 通知库存扣减&&通知优惠券扣减&&团购支付成功回调&&秒杀支付成功回调&&商家分账&&通知用户余额支付成功
        SendStatus sendCouponStatus = orderNotifyServiceTemplate.syncSend(RocketMqConstant.ORDER_NOTIFY_SERVICE_TOPIC, new GenericMessage<>(message)).getSendStatus();
        if (!Objects.equals(sendCouponStatus, SendStatus.SEND_OK)) {
            LOG.error("发送消息，订单支付成功，通知库存扣减&&通知优惠券扣减&&团购支付成功回调&&秒杀支付成功回调&&商家分账&&通知用户余额支付成功失败，sendCouponStatus: {}", sendCouponStatus);
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 发送消息，订单支付成功
        // 通知用户余额支付成功
        SendStatus sendBalanceStatus = allinPayBalanceOrderSuccessTemplate.syncSend(RocketMqConstant.ALLINPAY_BALANCE_ORDER_SUCCESS_TOPIC, new GenericMessage<>(message)).getSendStatus();
        if (!Objects.equals(sendBalanceStatus, SendStatus.SEND_OK)) {
            LOG.error("发送消息，订单支付成功，通知用户余额支付成功失败，sendBalanceStatus: {}", sendBalanceStatus);
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        // 发送消息，订单支付成功，推送通知给用户
        sendMsgToUser(message, isPreSale);
    }

    private void sendMsgToUser(PayNotifyBO message, boolean isPreSale) {
        List<SendNotifyBO> notifyList = orderService.listSendNotifyByOrderIds(message.getOrderIds());
        for (SendNotifyBO sendNotifyBO : notifyList) {
            sendNotifyBO.setPrice(PriceUtil.toDecimalPrice(sendNotifyBO.getActualTotal()).toString());
            sendNotifyBO.setSendType(SendTypeEnum.PAY_SUCCESS.getValue());
        }
        // 订单支付成功推送消息给用户
        if (!isPreSale) {
            SendStatus sendStockStatus = sendNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(notifyList)).getSendStatus();
            if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
            List<SendNotifyBO> shopNotifies = new ArrayList<>(Constant.INITIAL_CAPACITY);
            for (SendNotifyBO sendNotifyBO : notifyList) {
                // 代销商品为供应商发货则发送 待发货提醒给供应商
                if (Objects.nonNull(sendNotifyBO.getSupplierDeliveryType()) && Objects.equals(sendNotifyBO.getSupplierDeliveryType(), SupplierDeliveryType.SUPPLIER_DELIVERY.value())) {
                    // 改过价的供应商发货订单，支付后会变成采购订单，支付消息暂不发送给供应商，商家采购后再发送
                    if (sendNotifyBO.getShopChangeFreeAmount() != null
                            && sendNotifyBO.getShopChangeFreeAmount() != 0) {
                        continue;
                    }
                    sendNotifyBO.setSendType(SendTypeEnum.USER_PAY_SUCCESS_TO_SUPPLIER.getValue());
                    sendNotifyBO.setShopId(null);
                    LOG.info("代销商品为供应商发货则发送 待发货提醒给供应商，sendNotifyBO: {}", sendNotifyBO);
                } else {
                    sendNotifyBO.setSendType(SendTypeEnum.USER_PAY_SUCCESS.getValue());
                    LOG.info("商家发货则发送 待发货提醒给商家，sendNotifyBO: {}", sendNotifyBO);
                }
                shopNotifies.add(sendNotifyBO);
            }
            if (CollUtil.isNotEmpty(shopNotifies)) {
                // 发送消息给商家|供应商，订单支付成功（即 待发货提醒）
                for (SendNotifyBO notifyBO : shopNotifies) {
                    SendStatus sendShopMsgStatus = sendNotifyToShopTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_SHOP_TOPIC, new GenericMessage<>(notifyBO)).getSendStatus();
                    if (!Objects.equals(sendShopMsgStatus, SendStatus.SEND_OK)) {
                        LOG.error("发送消息给商家或供应商，订单支付成功（即 待发货提醒）失败，sendShopMsgStatus: {}", sendShopMsgStatus);
                        throw new LuckException(ResponseEnum.EXCEPTION);
                    }
                }
            }
        }
    }
}
