package com.spot.mq;

import com.alibaba.fastjson.JSON;
import com.spot.dto.mq.AssetChangeInfo;
import com.spot.dto.mq.TradeResult;
import com.spot.entity.ExOrder;
import com.spot.enums.OrderStatus;
import com.spot.service.AssetChangeMqService;
import com.spot.service.TradeResultService;
import com.spot.utils.MessageIdFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 撮合引擎交易结果 Kafka 消费者
 * 监听 Topic 前缀为 SPOT_TRADE_ 的所有交易对结果消息（通配符匹配）
 * 支持幂等处理：消息ID已处理则跳过，防止重复消费
 *
 * @author jean
 * @date 2026-05-06
 */
@Slf4j
@Component
public class TradeResultConsumer {

    @Autowired
    private TradeResultService tradeResultService;

    @Autowired
    private AssetChangeMqService assetChangeMqService;

    @Autowired
    private MessageIdFilter messageIdFilter;

    /**
     * 消费撮合交易结果
     * Topic 使用 pattern 匹配所有以 SPOT_TRADE_ 开头的交易对 Topic
     * 手动提交 offset，确保消息处理完成后再提交
     *
     * @param record         Kafka 消息
     * @param acknowledgment 手动确认对象
     */
    @KafkaListener(
            topicPattern = "SPOT_TRADE_.*",
            groupId = "${spring.kafka.consumer.group-id:default-group}",
            containerFactory = "kafkaListenerContainerFactory"
    )
    public void consume(ConsumerRecord<String, String> record, Acknowledgment acknowledgment) {
        String topic = record.topic();
        String value = record.value();
        String key = record.key();

        try {
            if (value == null || value.trim().isEmpty()) {
                log.warn("收到空消息，跳过 - Topic: {}, Key: {}", topic, key);
                acknowledgment.acknowledge();
                return;
            }

            // 1. 解析消息
            TradeResult tradeResult = JSON.parseObject(value, TradeResult.class);
            if (tradeResult == null) {
                log.error("解析 TradeResult 失败 - Topic: {}, Value: {}", topic, value);
                acknowledgment.acknowledge();
                return;
            }

            // 2. 幂等检查
            String messageId = tradeResult.getMessageId();
            if (messageId != null && messageIdFilter.isProcessed(messageId)) {
                log.debug("消息已处理过，跳过 - MessageId: {}", messageId);
                acknowledgment.acknowledge();
                return;
            }

            // 3. 处理前先标记，防止并发重复消费
            if (messageId != null) {
                messageIdFilter.markAsProcessed(messageId);
            }

            // 4. 根据 taker 订单状态路由处理
            List<AssetChangeInfo> changeInfos;
            try {
                changeInfos = dispatchTradeResult(tradeResult, topic);
            } catch (Exception e) {
                // 业务处理失败，移除标记，等待重试
                if (messageId != null) {
                    messageIdFilter.removeProcessed(messageId);
                }
                log.error("处理撮合结果消息失败 - Topic: {}, Key: {}", topic, key, e);
                return;
            }

            // 5. 业务处理成功，立即 ack
            acknowledgment.acknowledge();

            // 6. 发送资产/订单变动通知（失败不影响 ack）
            if (changeInfos != null && !changeInfos.isEmpty()) {
                sendChangeMessages(changeInfos);
            }

        } catch (Exception e) {
            log.error("处理撮合结果消息失败 - Topic: {}, Key: {}", topic, key, e);
            // 不 ack，触发重试（依赖 Kafka 重试机制）
        }
    }

    /**
     * 根据 taker 订单状态路由到对应处理方法
     *
     * @param tradeResult 交易结果
     * @param topic       来源 Topic
     * @return 变动信息列表
     */
    private List<AssetChangeInfo> dispatchTradeResult(TradeResult tradeResult, String topic) {
        ExOrder order = tradeResult.getTakerOrder();
        if (order == null) {
            log.error("TradeResult 中 takerOrder 为空 - Topic: {}", topic);
            order = tradeResult.getMakerOrder();
            if (order == null) {
                return null;
            }
        }

        Integer orderStatus = order.getStatus();
        if (orderStatus == null) {
            log.error("takerOrder 的 status 为空 - Topic: {}", topic);
            return null;
        }

        if (OrderStatus.CANCELED.getCode().equals(orderStatus)) {
            return tradeResultService.processCancelResult(tradeResult);
        } else if (OrderStatus.FILLED.getCode().equals(orderStatus)) {
            return tradeResultService.processTradeResult(tradeResult);
        } else if (OrderStatus.NEW.getCode().equals(orderStatus)) {
            return tradeResultService.processPendingOrder(tradeResult);
        } else {
            log.warn("未知的订单状态，跳过处理 - OrderId: {}, Status: {}",
                    order.getId(), orderStatus);
            return null;
        }
    }

    /**
     * 批量发送资产/订单变动 MQ 通知
     *
     * @param changeInfos 变动信息列表
     */
    private void sendChangeMessages(List<AssetChangeInfo> changeInfos) {
        for (AssetChangeInfo info : changeInfos) {
            if (info == null || info.getUid() == null || info.getSymbols() == null) {
                continue;
            }
            try {
                assetChangeMqService.sendChangeMessage(info.getType(), info.getUid(), info.getSymbols());
            } catch (Exception e) {
                log.error("发送变动通知失败 - Type: {}, Uid: {}", info.getType(), info.getUid(), e);
            }
        }
    }
}
