package com.tsi.sig.server.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.admin.AdminClient;
import org.apache.kafka.clients.admin.AdminClientConfig;
import org.apache.kafka.clients.admin.KafkaAdminClient;
import org.apache.kafka.clients.admin.TopicDescription;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.KafkaMessageListenerContainer;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.ExecutionException;

@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "application.kafka.evp.consumer")
public class KafkaEvpConsumerConfig {
    //기존
    //private String groupId = "tsi-sig-server";
    //변경
    private String groupId;
    private String bootstrapServers;
    private String topic;
    public List<Map<String, String>> props = new ArrayList<Map<String, String>>();

    @PostConstruct
    private void init() throws UnknownHostException {

        log.info("[{}] --------------------", this.getClass().getSimpleName());
        log.info("[{}]          groupId: {}", this.getClass().getSimpleName(), this.groupId);
        log.info("[{}] bootstrapServers: {}", this.getClass().getSimpleName(), this.bootstrapServers);
        log.info("[{}]            topic: {}", this.getClass().getSimpleName(), this.topic);
        log.info("[{}]            props: {}", this.getClass().getSimpleName(), this.props.toArray());
        String hostName;
        try {
            InetAddress localhost = InetAddress.getLocalHost();
            hostName = localhost.getHostName();
        } catch (UnknownHostException e) {
            hostName = UUID.randomUUID().toString();
        }
        this.groupId = this.groupId + hostName;
    }

    public Properties getConsumerProperties() {
        return getConsumerProperties(this.groupId);
    }

    public Properties getConsumerProperties(String groupId) {
        Properties properties = new Properties();

        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);
        properties.put(ConsumerConfig.GROUP_ID_CONFIG, groupId);
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
        properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
        properties .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringDeserializer.class);
        properties .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.ByteBufferDeserializer.class);

        for (Map<String, String> prop : this.props) {
            for (Map.Entry<String, String> elem : prop.entrySet()) {
                String key = elem.getKey();
                String val = elem.getValue();
                if (val != null) {
                    if (val.equals("true") || val.equals("false")) {
                        properties.put(key, val.equals("true"));
                    } else {
                        properties.put(key, val);
                    }
                }
            }
        }
        return properties;
    }

    public Map<String, Object> getConsumerPropertiesMap() {
        Map<String, Object> properties = new HashMap();
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);
        properties.put(ConsumerConfig.GROUP_ID_CONFIG, this.groupId);
        properties.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
        properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
        properties .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.StringDeserializer.class);
        properties .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, org.apache.kafka.common.serialization.ByteArrayDeserializer.class);

        for (Map<String, String> prop : this.props) {
            for (Map.Entry<String, String> elem : prop.entrySet()) {
                String key = elem.getKey();
                String val = elem.getValue();
                if (val != null) {
                    if (val.equals("true") || val.equals("false")) {
                        properties.put(key, val.equals("true"));
                    } else {
                        properties.put(key, val);
                    }
                }
            }
        }
        return properties;
    }

    private  <K,V> ConsumerFactory<K,V> consumerFactory(){
        DefaultKafkaConsumerFactory<K,V> consumerFactory = new DefaultKafkaConsumerFactory<K,V>(getConsumerPropertiesMap());
        return consumerFactory;
    }

    public <K,V> KafkaMessageListenerContainer<K, V> createKafkaConsumer(ContainerProperties containerProps) {

        DefaultKafkaConsumerFactory<K, V> consumerFactory = new DefaultKafkaConsumerFactory(getConsumerPropertiesMap());
        KafkaMessageListenerContainer<K, V> listenerContainer = new KafkaMessageListenerContainer((ConsumerFactory)consumerFactory, containerProps);
        return listenerContainer;
    }

    public <T,V> ConcurrentMessageListenerContainer<T, V> createKafkaConsumerListener(ContainerProperties containerProps) {

        DefaultKafkaConsumerFactory<T, V> consumerFactory = new DefaultKafkaConsumerFactory(getConsumerPropertiesMap());
        ConcurrentMessageListenerContainer<T, V> listenerContainer = new ConcurrentMessageListenerContainer((ConsumerFactory)consumerFactory, containerProps);
        return listenerContainer;
    }

    public int getPartitionCount(String topicName) throws ExecutionException, InterruptedException {
        Properties properties = new Properties();
        properties.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, this.bootstrapServers);

        AdminClient adminClient = KafkaAdminClient.create(properties);

        Map<String, TopicDescription> topics = adminClient.describeTopics(Collections.singletonList(topicName)).all().get();
        log.error("{}", topics.get(topicName).partitions().size());
        adminClient.close();
        return topics.get(topicName).partitions().size();
    }
}
