package com.market.consumer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.market.model.ManualPriceMessage;
import com.market.service.SpotDataProcessService;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;

/**
 * 行情机器人价格 Kafka 消费者
 * <p>
 * 消费 {@code SPOT_ROBOT_PRICE} Topic，对机器人自动生成的价格执行完整的行情处理：
 * <ul>
 *   <li>初始化或更新各周期 K 线缓存（open/close/high/low），并写库（5s 节流）</li>
 *   <li>推送各周期 K 线到 WebSocket 前端</li>
 *   <li>推送模拟成交记录（trade）到前端</li>
 *   <li>推送 24hrMiniTicker（无 24h 数据时 open=0，rose=0）到前端</li>
 *   <li>更新 Redis 最新成交价，并通知撮合引擎（Kafka SPOT_NEW_PRICE）</li>
 * </ul>
 * <p>
 * 消息格式：{@code {"symbol":"btcusdt","price":"95000.00"}}
 *
 * @author jean
 * @date 2026-05-11
 */
@Component
public class SpotRobotPriceConsumer {

    private static final Logger log = LoggerFactory.getLogger(SpotRobotPriceConsumer.class);

    /** 现货行情数据处理服务 */
    private final SpotDataProcessService spotDataProcessService;

    private final ObjectMapper objectMapper;

    public SpotRobotPriceConsumer(SpotDataProcessService spotDataProcessService) {
        this.spotDataProcessService = spotDataProcessService;
        this.objectMapper           = new ObjectMapper();
    }

    /**
     * 消费机器人生成价格消息，完整处理行情推送
     *
     * @param record Kafka 消息记录
     * @param ack    手动提交偏移量
     */
    @KafkaListener(
            topics      = "${spot.kafka.topic.robot-price:SPOT_ROBOT_PRICE}",
            groupId     = "${spot.kafka.consumer.robot-group-id:spot-robot-group}",
            concurrency = "1"
    )
    public void onRobotPrice(ConsumerRecord<String, String> record, Acknowledgment ack) {
        try {
            // 1. 解析消息
            ManualPriceMessage msg = objectMapper.readValue(record.value(), ManualPriceMessage.class);
            if (msg.getSymbol() == null || msg.getPrice() == null) {
                log.warn("机器人价格消息字段缺失: {}", record.value());
                return;
            }

            String symbol = msg.getSymbol().toLowerCase();
            BigDecimal price = new BigDecimal(msg.getPrice());
            BigDecimal klineHighRatio = msg.getKlineHighRatio() != null
                    ? new BigDecimal(msg.getKlineHighRatio()) : null;
            BigDecimal klineLowRatio  = msg.getKlineLowRatio()  != null
                    ? new BigDecimal(msg.getKlineLowRatio())  : null;

            log.debug("收到机器人生成价格: symbol={}, price={}", symbol, price);

            // 2. 更新 kline + 推送 trade / 24hrMiniTicker / kline + 通知撮合
            spotDataProcessService.applyRobotPrice(symbol, price, klineHighRatio, klineLowRatio);

        } catch (Exception e) {
            log.error("处理机器人价格消息失败: topic={}, offset={}, value={}",
                    record.topic(), record.offset(), record.value(), e);
        } finally {
            ack.acknowledge();
        }
    }
}
