package com.xxfc.platform.order.mqhandler;

import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.rabbitmq.client.Channel;
import com.xxfc.platform.order.biz.ShuntApplyBiz;
import com.xxfc.platform.order.biz.SpecialRentBiz;
import com.xxfc.platform.order.biz.inner.OrderCancelBiz;
import com.xxfc.platform.order.entity.BaseOrder;
import com.xxfc.platform.order.entity.ShuntApply;
import com.xxfc.platform.order.entity.SpecialRent;
import com.xxfc.platform.order.pojo.order.RentVehicleBO;
import com.xxfc.platform.order.service.OrderRentVehicleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;

import static com.xxfc.platform.order.config.RabbitDelayConfig.*;

/**
 * activeMq消费者类
 * @author zhanghang
 * @date 2017/12/19
 */
@Slf4j
@Component
public class RabbitConsumer {

    @Autowired
    OrderCancelBiz orderCancelBiz;

    @Autowired
    ShuntApplyBiz shuntApplyBiz;

    @Autowired
    SpecialRentBiz specialRentBiz;

    @Autowired
    OrderRentVehicleService orderRentVehicleService;


    /**
     * 默认情况下,如果没有配置手动ACK, 那么Spring Data AMQP 会在消息消费完毕后自动帮我们去ACK
     * 存在问题：如果报错了,消息不会丢失,但是会无限循环消费,一直报错,如果开启了错误日志很容易就吧磁盘空间耗完
     * 解决方案：手动ACK,或者try-catch 然后在 catch 里面将错误的消息转移到其它的系列中去
     * spring.rabbitmq.listener.simple.acknowledge-mode = manual
     */
    @RabbitListener(queues = ORDER_CANCEL_QUE)
    public void orderCancelReceiveDealy(BaseOrder baseOrder, Message message, Channel channel) throws IOException {
        log.info("===============接收队列接收消息====================");
        log.info("接收时间:{},接受内容:{}", LocalDateTime.now(), baseOrder.toString());
        //通知 MQ 消息已被接收,可以ACK(从队列中删除)了
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        try {
            //设置自动取消标识
            baseOrder.setCancelReason("超时未付款，系统自动取消订单");
            orderCancelBiz.cancel(baseOrder, null);
        }catch (BaseException e) {
            if(ResultCode.DB_OPERATION_FAIL_CODE == e.getStatus()) {
                log.info("取消操作被取消;订单id："+ baseOrder.getId());
            }
        }catch (Exception e) {
            log.error("============消费失败,尝试消息补发再次消费!==============");
            log.error(e.getMessage());
            /**
             * basicRecover方法是进行补发操作，
             * 其中的参数如果为true是把消息退回到queue但是有可能被其它的consumer(集群)接收到，
             * 设置为false是只补发给当前的consumer
             */
            channel.basicRecover(true);
        }
    }

    @RabbitListener(queues = APPLY_CANCEL_QUE)
    public void applyCancelReceiveDealy(ShuntApply shuntApply, Message message, Channel channel) throws IOException {
        log.info("===============接收队列接收消息====================");
        log.info("接收时间:{},接受内容:{}", LocalDateTime.now(), shuntApply.toString());
        //通知 MQ 消息已被接收,可以ACK(从队列中删除)了
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        try {

            //判断updateTime 是否一致（即乐观锁）
            ShuntApply dbApply = shuntApplyBiz.selectById(shuntApply.getId());
            if(dbApply.getUpdTime().equals(shuntApply.getUpdTime())) {
                shuntApplyBiz.updateSelectiveById(new ShuntApply(){{
                    setId(shuntApply.getId());
                    setStatus(ShuntApply.STATUS_AUTOCNL_ORDER);
                }});
            }
            //取消预订
            orderRentVehicleService.errorRejectVehicle(new RentVehicleBO(){{
                setBookRecordId(shuntApply.getBookRecordId());
            }});
        }catch (BaseException e) {
            if(ResultCode.DB_OPERATION_FAIL_CODE == e.getStatus()) {
                log.info("取消操作被取消;订单id："+ shuntApply.getId());
            }
        }catch (Exception e) {
            log.error("============消费失败,尝试消息补发再次消费!==============");
            log.error(e.getMessage());
            /**
             * basicRecover方法是进行补发操作，
             * 其中的参数如果为true是把消息退回到queue但是有可能被其它的consumer(集群)接收到，
             * 设置为false是只补发给当前的consumer
             */
            channel.basicRecover(true);
        }
    }

    @RabbitListener(queues = APPLY_REQUIRE_CANCEL_QUE)
    public void applyRequireCancelReceiveDealy(ShuntApply shuntApply, Message message, Channel channel) throws IOException {
        log.info("===============接收队列接收消息====================");
        log.info("接收时间:{},接受内容:{}", LocalDateTime.now(), shuntApply.toString());
        //通知 MQ 消息已被接收,可以ACK(从队列中删除)了
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        try {

            //判断updateTime 是否一致（即乐观锁）
            ShuntApply dbApply = shuntApplyBiz.selectById(shuntApply.getId());
            if(dbApply.getUpdTime().equals(shuntApply.getUpdTime())) {
                shuntApplyBiz.updateSelectiveById(new ShuntApply(){{
                    setId(shuntApply.getId());
                    setStatus(ShuntApply.STATUS_AUTOCNL_REQUIRE);
                }});
            }
        }catch (BaseException e) {
            if(ResultCode.DB_OPERATION_FAIL_CODE == e.getStatus()) {
                log.info("取消操作被取消;订单id："+ shuntApply.getId());
            }
        }catch (Exception e) {
            log.error("============消费失败,尝试消息补发再次消费!==============");
            log.error(e.getMessage());
            /**
             * basicRecover方法是进行补发操作，
             * 其中的参数如果为true是把消息退回到queue但是有可能被其它的consumer(集群)接收到，
             * 设置为false是只补发给当前的consumer
             */
            channel.basicRecover(true);
        }
    }

    @RabbitListener(queues = SPECIAL_CANCEL_QUE)
    public void specialCancelReceiveDealy(SpecialRent specialRent, Message message, Channel channel) throws IOException {
        log.info("===============接收队列接收消息====================");
        log.info("接收时间:{},接受内容:{}", LocalDateTime.now(), specialRent.toString());
        //通知 MQ 消息已被接收,可以ACK(从队列中删除)了
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        try {

            //判断updateTime 是否一致（即乐观锁）
            SpecialRent dbSpecialRent = specialRentBiz.selectById(specialRent.getId());
            if(dbSpecialRent.getUpdTime().equals(specialRent.getUpdTime())) {
                specialRentBiz.updateSelectiveById(new SpecialRent(){{
                    setId(specialRent.getId());
                    setStatus(SpecialRent.STATUS_AUTOCNL_ORDER);
                }});
            }
        }catch (BaseException e) {
            if(ResultCode.DB_OPERATION_FAIL_CODE == e.getStatus()) {
                log.info("取消操作被取消;订单id："+ specialRent.getId());
            }
        }catch (Exception e) {
            log.error("============消费失败,尝试消息补发再次消费!==============");
            log.error(e.getMessage());
            /**
             * basicRecover方法是进行补发操作，
             * 其中的参数如果为true是把消息退回到queue但是有可能被其它的consumer(集群)接收到，
             * 设置为false是只补发给当前的consumer
             */
            channel.basicRecover(true);
        }
    }

}
