package com.seamew.lottery.application.mq.consumer;

import com.alibaba.fastjson2.JSON;
import com.seamew.lottery.application.mq.producer.KafkaProducer;
import com.seamew.lottery.common.Constants;
import com.seamew.lottery.domain.activity.model.vo.InvoiceVO;
import com.seamew.lottery.domain.award.model.req.GoodsReq;
import com.seamew.lottery.domain.award.model.res.DistributionRes;
import com.seamew.lottery.domain.award.service.factory.DistributionGoodsFactory;
import com.seamew.lottery.domain.award.service.goods.IDistributionGoods;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author: seamew
 * @Title: LotteryInvoiceListener
 * @CreateTime: 2023年02月27日 11:12:00
 * @Description: 中奖发货单监听消息
 * @Version: 1.0
 */
@Component
@Slf4j
public class LotteryInvoiceListener {

    @Resource
    private DistributionGoodsFactory distributionGoodsFactory;

    @KafkaListener(topics = KafkaProducer.TOPIC_INVOICE, groupId = KafkaProducer.GROUP_NAME)
    public void onMessage(ConsumerRecord<?, ?> record, Acknowledgment ack) {
        // 1. 判断消息是否存在
        if (ObjectUtils.isEmpty(record.value())) {
            return;
        }
        // 2. 处理 MQ 消息
        try {
            // 1. 转化对象
            InvoiceVO invoiceVO = JSON.parseObject((String) record.value(), InvoiceVO.class);

            // 2. 获取发送奖品工厂，执行发奖
            IDistributionGoods distributionGoodsService = distributionGoodsFactory.getDistributionGoodsService(invoiceVO.getAwardType());
            DistributionRes distributionRes = distributionGoodsService.doDistribution(new GoodsReq(invoiceVO.getUId(), invoiceVO.getOrderId(), invoiceVO.getAwardId(), invoiceVO.getAwardName(), invoiceVO.getAwardContent()));

            if (!Constants.AwardState.SUCCESS.getCode().equals(distributionRes.getCode())) {
                throw new RuntimeException("发奖失败");
            }

            // 3. 打印日志
            log.info("消费MQ消息，完成 topic：{} message：{} 发奖结果：{}", record.topic(), JSON.toJSONString(invoiceVO), JSON.toJSONString(distributionRes));

            // 4. 消息消费完成
            ack.acknowledge();
        } catch (Exception e) {
            // 发奖环节失败，消息重试。所有到环节，发货、更新库，都需要保证幂等。
            log.error("消费MQ消息，失败 topic：{} message：{}", record.topic(), record.value());
            throw e;
        }
    }
}
