package com.spot.mq;

import com.alibaba.fastjson.JSON;
import com.spot.config.MatchingEngine;
import com.spot.dto.mq.OrderMessage;
import com.spot.dto.mq.TradeResult;
import com.spot.entity.ExOrder;
import com.spot.enums.OrderStatus;
import com.spot.enums.OrderType;
import com.spot.service.NewMatchingEngine;
import com.spot.utils.MessageIdFilter;
import com.spot.utils.OrderProcessedFilter;
import com.spot.utils.TimeUtils;
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.math.BigDecimal;

/**
 * 现货撮合订单 Kafka 消费者
 * 监听所有以 SPOT_MATCH_ 开头的交易对 Topic，处理 init 订单撮合和撤单
 *
 * @author jean
 * @date 2026-05-07
 */
@Slf4j
@Component
public class SpotMatchConsumer {

    @Autowired
    private MatchingEngine matchingEngine;

    @Autowired
    private NewMatchingEngine newMatchingEngine;

    @Autowired
    private MessageIdFilter messageIdFilter;

    /**
     * 消费撮合订单消息
     * topicPattern 匹配所有以 SPOT_MATCH_ 开头的 Topic
     *
     * @param record         Kafka 消息
     * @param acknowledgment 手动确认对象
     */
    @KafkaListener(
            topicPattern = "SPOT_MATCH_.*",
            groupId = "${spring.kafka.consumer.group-id:spot-match-group}",
            containerFactory = "kafkaListenerContainerFactory"
    )
    public void consume(ConsumerRecord<String, String> record, Acknowledgment acknowledgment) {
        String topic = record.topic();
        String value = record.value();
        try {
            if (value == null || value.trim().isEmpty()) {
                acknowledgment.acknowledge();
                return;
            }

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

            // 2. 幂等检查（消息级别）
            String msgId = record.key();
            if (msgId != null && messageIdFilter.isProcessed(msgId)) {
                log.debug("消息已处理过，跳过 - MsgId: {}", msgId);
                acknowledgment.acknowledge();
                return;
            }

            // 3. 处理消息
            processOrderMessage(orderMessage, topic);

            // 4. 标记消息已处理
            if (msgId != null) {
                messageIdFilter.markAsProcessed(msgId);
            }
            acknowledgment.acknowledge();

        } catch (Exception e) {
            log.error("处理撮合订单消息失败 - Topic: {}", topic, e);
            // 不 ack，触发重试
        }
    }

    /**
     * 处理单个订单消息
     *
     * @param orderMessage 订单消息
     * @param topic        来源 Topic
     */
    private void processOrderMessage(OrderMessage orderMessage, String topic) {
        Integer status = orderMessage.getStatus();
        if (status == null || (!OrderStatus.INIT.getCode().equals(status)
                && !OrderStatus.PENDING_CANCEL.getCode().equals(status))) {
            log.warn("订单状态不符合要求，仅接受状态0和5 - Topic: {}, OrderId: {}, Status: {}",
                    topic, orderMessage.getId(), status);
            return;
        }

        // 订单级别幂等检查
        if (OrderProcessedFilter.isProcessed(orderMessage.getId(), status)) {
            log.debug("订单已处理过，跳过 - OrderId: {}, Status: {}", orderMessage.getId(), status);
            return;
        }

        boolean canProcess = OrderProcessedFilter.markAsProcessing(orderMessage.getId(), status);
        if (!canProcess) {
            log.debug("订单正在处理中，跳过 - OrderId: {}, Status: {}", orderMessage.getId(), status);
            return;
        }

        try {
            if (OrderStatus.INIT.getCode().equals(status)) {
                handleInitOrder(orderMessage);
            } else {
                handlePendingCancel(orderMessage);
            }
            OrderProcessedFilter.markAsProcessed(orderMessage.getId(), status);
        } catch (Exception e) {
            OrderProcessedFilter.clearProcessing(orderMessage.getId(), status);
            log.error("处理订单失败，已清除正在处理标记 - OrderId: {}, Status: {}", orderMessage.getId(), status, e);
            throw e;
        }
    }

    /**
     * 处理 init 状态订单（状态0）- 触发撮合
     *
     * @param orderMessage 订单消息
     */
    private void handleInitOrder(OrderMessage orderMessage) {
        ExOrder order = convertToExOrder(orderMessage);
        if (order == null) {
            return;
        }
        if (!matchingEngine.canProcess(order)) {
            log.warn("订单不符合撮合条件 - OrderId: {}", order.getId());
            return;
        }
        TradeResult tradeResult = matchingEngine.processInitOrder(order);
        if (!tradeResult.isMatched()) {
            // 市价单：无论何种原因未成交，均不加入挂单缓存（已在 processInitOrder 内发送取消结果到 Kafka）
            if (OrderType.MARKET.equals(OrderType.fromCode(order.getType()))) {
                log.info("市价单未成交，已取消 - OrderId: {}", order.getId());
                return;
            }
            // 限价单：加入挂单缓存，等待价格触发
            order.setStatus(OrderStatus.NEW.getCode());
            order.setMtime(TimeUtils.now());
            newMatchingEngine.addOrderToCache(order);
        }
    }

    /**
     * 处理 pending_cancel 状态订单（状态5）- 撤单
     * 从内存缓存移除，并发送取消结果到 Kafka，由 TradeResultConsumer 更新 DB 并退款
     *
     * @param orderMessage 订单消息
     */
    private void handlePendingCancel(OrderMessage orderMessage) {
        ExOrder order = convertToExOrder(orderMessage);
        if (order == null) {
            return;
        }
        order.setStatus(OrderStatus.CANCELED.getCode());
        order.setMtime(TimeUtils.now());
        if (order.getDealVolume() == null) { order.setDealVolume(BigDecimal.ZERO); }
        if (order.getDealMoney() == null)  { order.setDealMoney(BigDecimal.ZERO); }
        if (order.getFee() == null)        { order.setFee(BigDecimal.ZERO); }
        if (order.getAvgPrice() == null)   { order.setAvgPrice(BigDecimal.ZERO); }
        // 1. 从内存挂单缓存移除
        newMatchingEngine.removeOrderFromCache(order);
        // 2. 发送取消结果到 Kafka，触发 DB 更新和冻结余额退款
        newMatchingEngine.sendCancelResult(order);
        log.debug("撤单处理完成 - OrderId: {}", order.getId());
    }

    /**
     * 将 OrderMessage 转换为 ExOrder
     *
     * @param msg 订单消息
     * @return ExOrder 对象
     */
    private ExOrder convertToExOrder(OrderMessage msg) {
        if (msg == null) {
            return null;
        }
        ExOrder order = new ExOrder();
        order.setId(msg.getId());
        order.setUserId(msg.getUserId());
        order.setSymbol(msg.getSymbol());
        order.setSide(msg.getSide());
        order.setPrice(msg.getPrice());
        order.setVolume(msg.getVolume());
        order.setFeeRateMaker(msg.getFeeRateMaker());
        order.setFeeRateTaker(msg.getFeeRateTaker());
        order.setFee(msg.getFee() != null ? msg.getFee() : BigDecimal.ZERO);
        order.setDealVolume(msg.getDealVolume() != null ? msg.getDealVolume() : BigDecimal.ZERO);
        order.setDealMoney(msg.getDealMoney() != null ? msg.getDealMoney() : BigDecimal.ZERO);
        order.setAvgPrice(msg.getAvgPrice() != null ? msg.getAvgPrice() : BigDecimal.ZERO);
        order.setStatus(msg.getStatus());
        order.setType(msg.getType());
        order.setCtime(msg.getCtime() != null ? msg.getCtime() : TimeUtils.now());
        order.setMtime(msg.getMtime() != null ? msg.getMtime() : TimeUtils.now());
        order.setSource(msg.getSource());
        order.setRefundVolume(msg.getRefundVolume() != null ? msg.getRefundVolume() : BigDecimal.ZERO);
        return order;
    }
}
