package com.mortals.xhx.queue.rabbitmq;

import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.Gson;
import com.mortals.xhx.queue.*;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;

@Slf4j
public class TbRabbitMqProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> {
    private String defaultTopic;
    private TbRabbitMqSettings rabbitMqSettings;
    private ListeningExecutorService producerExecutor;
    private Channel channel;
    private Connection connection;
    private final Gson gson = new Gson();

    private final Set<TopicPartitionInfo> topics = ConcurrentHashMap.newKeySet();

    public TbRabbitMqProducerTemplate(TbRabbitMqSettings rabbitMqSettings, String defaultTopic) {
        this.defaultTopic = defaultTopic;
        this.rabbitMqSettings = rabbitMqSettings;
        producerExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
        try {
            connection = rabbitMqSettings.getConnectionFactory().newConnection();
            channel = connection.createChannel();
        } catch (IOException | TimeoutException e) {
            log.error("Failed to create connection.", e);
            // throw new RuntimeException("Failed to create connection." , e);
        }

    }

    @Override
    public void init() {

    }

    @Override
    public String getDefaultTopic() {
        return defaultTopic;
    }

    @Override
    public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) {
        Boolean topicIfNotExist = createTopicIfNotExist(tpi);
        AMQP.BasicProperties properties = new AMQP.BasicProperties();
//                .builder()
//                .contentType("application/json")
//                .deliveryMode(2) // 消息是否持久化，1未持久，2持久
//                .contentEncoding("UTF-8") // 编码方式
//                .expiration("100000") // 过期时间单位毫秒
//                .build();
        try {
            if (!topicIfNotExist) {
                channel.queueDeclare(tpi.getTopic(), true, false, false, null);
            }
            //channel.basicPublish(rabbitMqSettings.getExchangeName(), tpi.getFullTopicName(), properties, gson.toJson(new DefaultTbQueueMsg(msg)).getBytes());
            channel.basicPublish(rabbitMqSettings.getExchangeName(), tpi.getFullTopicName(), properties, JSON.toJSONString(new DefaultTbQueueMsg(msg)).getBytes());
            if (callback != null) {
                callback.onSuccess(null);
            }
        } catch (
                IOException e) {
            log.error("Failed publish message: [{}].", msg, e);
            if (callback != null) {
                callback.onFailure(e);
            }
        }

    }

    @Override
    public void stop() {
        if (producerExecutor != null) {
            producerExecutor.shutdownNow();
        }
        if (channel != null) {
            try {
                channel.close();
            } catch (IOException | TimeoutException e) {
                log.error("Failed to close the channel.");
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (IOException e) {
                log.error("Failed to close the connection.");
            }
        }
    }

    private Boolean createTopicIfNotExist(TopicPartitionInfo tpi) {
        if (topics.contains(tpi)) {
            return true;
        }
        topics.add(tpi);
        return false;
    }
}
