
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.order.feign.OrderFeignClient;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.order.bo.OrderStatusBO;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.order.service.OrderService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.spring.annotation.RocketMQTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionListener;
import org.apache.rocketmq.spring.core.RocketMQLocalTransactionState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 确认收货事务监听
 *
 * @author tmerclub
 * @date 2021/1/7
 */
@Component
@RocketMQTransactionListener(rocketMQTemplateBeanName = "orderReceiptTemplate", maximumPoolSize = 20)
public class OrderReceiptTransactionListener implements RocketMQLocalTransactionListener {

    @Autowired
    private OrderService orderService;
    @DubboReference
    private OrderFeignClient orderFeignClient;

    @Override
    public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
        Long orderId = Json.parseObject((byte[]) msg.getPayload(), Long.class);
        // 众所周知，确认收货之后是不能改变状态的，
        // 但是确认收货之前是可以改变状态的，如果在确认收货之前，
        // 也就是下面这条sql执行之前进行了订单状态的改变（比如退款），那会造成不可预知的后果，
        // 所以更新订单状态的时候也要在条件当中加上订单状态，确定这条sql是原子性的
        // 这里的确认收货，条件加上订单的状态，确保这次更新是幂等的
        int updateStats = orderService.receiptOrder(orderId);
        if (updateStats == 0) {
            // 如果啥都没有更新，就检查一下
            return checkLocalTransaction(msg);
        }
        return RocketMQLocalTransactionState.COMMIT;
    }

    @Override
    public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
        Long orderId = Json.parseObject((byte[]) msg.getPayload(), Long.class);
        ServerResponseEntity<List<OrderStatusBO>> ordersStatusResponse = orderFeignClient.getOrdersStatus(Collections.singletonList(orderId));
        if (!ordersStatusResponse.isSuccess()) {
            throw new LuckException(ordersStatusResponse.getMsg());
        }
        if (CollUtil.isNotEmpty(ordersStatusResponse.getData()) &&
                !Objects.equals(ordersStatusResponse.getData().get(0).getStatus(), OrderStatus.SUCCESS.value())) {
            return RocketMQLocalTransactionState.ROLLBACK;
        }
        return RocketMQLocalTransactionState.COMMIT;
    }
}
