package tech.easyflow.common.mq.redis;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.connection.stream.StreamRecords;
import org.springframework.data.redis.core.StringRedisTemplate;
import tech.easyflow.common.mq.config.MQProperties;
import tech.easyflow.common.mq.core.MQMessage;
import tech.easyflow.common.mq.core.MQProducer;
import tech.easyflow.common.mq.core.MQMessageConverter;
import tech.easyflow.common.mq.exception.MQException;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

public class RedisMQProducer implements MQProducer {

    private static final Logger LOG = LoggerFactory.getLogger(RedisMQProducer.class);

    private final StringRedisTemplate stringRedisTemplate;
    private final MQProperties properties;
    private final MQMessageConverter messageConverter;
    private final RedisStreamKeySupport keySupport;

    public RedisMQProducer(StringRedisTemplate stringRedisTemplate,
                           MQProperties properties,
                           MQMessageConverter messageConverter,
                           RedisStreamKeySupport keySupport) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.properties = properties;
        this.messageConverter = messageConverter;
        this.keySupport = keySupport;
    }

    @Override
    public String send(MQMessage message) {
        if (message == null) {
            throw new MQException("MQ 消息不能为空");
        }
        if (message.getTopic() == null || message.getTopic().isBlank()) {
            throw new MQException("MQ topic 不能为空");
        }
        if (message.getMessageId() == null || message.getMessageId().isBlank()) {
            message.setMessageId(UUID.randomUUID().toString());
        }
        if (message.getCreatedAt() == null) {
            message.setCreatedAt(new Date());
        }
        int shardCount = Math.max(properties.getRedis().getChatPersistShardCount(), 1);
        int shard = keySupport.resolveShard(message.getKey(), shardCount);
        String streamKey = keySupport.streamKey(message.getTopic(), shard);
        LOG.info("MQ 开始投递消息: topic={}, messageId={}, key={}, shard={}, streamKey={}",
            message.getTopic(), message.getMessageId(), message.getKey(), shard, streamKey);
        RecordId recordId = stringRedisTemplate.opsForStream().add(
                StreamRecords.string(Map.of("payload", messageConverter.serialize(message))).withStreamKey(streamKey)
        );
        if (recordId == null) {
            throw new MQException("MQ 消息投递失败");
        }
        LOG.info("MQ 消息投递完成: topic={}, messageId={}, key={}, shard={}, streamKey={}, recordId={}",
            message.getTopic(), message.getMessageId(), message.getKey(), shard, streamKey, recordId.getValue());
        return recordId.getValue();
    }
}
