package com.zcloud.personnel.positioning.integration.kafka;

import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.common.TopicPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.event.EventListener;
import org.springframework.kafka.event.ConsumerFailedToStartEvent;
import org.springframework.kafka.event.ConsumerStartedEvent;
import org.springframework.kafka.event.ConsumerStartingEvent;
import org.springframework.kafka.event.ConsumerStoppedEvent;
import org.springframework.kafka.event.KafkaEvent;
import org.springframework.kafka.event.ListenerContainerIdleEvent;
import org.springframework.kafka.event.NonResponsiveConsumerEvent;
import org.springframework.kafka.listener.ConsumerAwareRebalanceListener;
import org.springframework.kafka.listener.MessageListenerContainer;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collection;

@Component
@ConditionalOnProperty(
        prefix = "personnel-positioning.kafka.location",
        name = "enabled",
        havingValue = "true"
)
public class KafkaConsumerLifecycleLogger implements ConsumerAwareRebalanceListener {
    private static final Logger LOGGER = LoggerFactory.getLogger(KafkaConsumerLifecycleLogger.class);
    private static final String LOCATION_LISTENER_ID = "personnelPositionLocationProbeListener";

    private final String bootstrapServers;
    private final String securityProtocol;
    private final String saslMechanism;

    public KafkaConsumerLifecycleLogger(
            @Value("${spring.kafka.bootstrap-servers}") String bootstrapServers,
            @Value("${spring.kafka.consumer.properties.security.protocol:PLAINTEXT}") String securityProtocol,
            @Value("${spring.kafka.consumer.properties.sasl.mechanism:PLAIN}") String saslMechanism) {
        this.bootstrapServers = bootstrapServers;
        this.securityProtocol = securityProtocol;
        this.saslMechanism = saslMechanism;
    }

    @EventListener
    public void onConsumerStarting(ConsumerStartingEvent event) {
        MessageListenerContainer container = locationContainer(event);
        if (container == null) {
            return;
        }
        LOGGER.info(
                "Kafka定位消息消费者开始启动，listenerId={}, broker={}, topics={}, groupId={}, "
                        + "securityProtocol={}, saslMechanism={}",
                container.getListenerId(),
                bootstrapServers,
                Arrays.toString(container.getContainerProperties().getTopics()),
                container.getGroupId(),
                securityProtocol,
                saslMechanism
        );
    }

    @EventListener
    public void onConsumerStarted(ConsumerStartedEvent event) {
        MessageListenerContainer container = locationContainer(event);
        if (container != null) {
            LOGGER.info(
                    "Kafka定位消息消费者已启动，等待连接Broker并分配分区，"
                            + "listenerId={}, groupId={}",
                    container.getListenerId(),
                    container.getGroupId()
            );
        }
    }

    @Override
    public void onPartitionsAssigned(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
        LOGGER.info(
                "Kafka定位消息订阅成功，broker={}, groupId={}, partitions={}",
                bootstrapServers,
                consumer.groupMetadata().groupId(),
                partitions
        );
    }

    @Override
    public void onPartitionsRevokedBeforeCommit(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
        LOGGER.warn(
                "Kafka定位消息分区已回收，groupId={}, partitions={}",
                consumer.groupMetadata().groupId(),
                partitions
        );
    }

    @Override
    public void onPartitionsLost(Consumer<?, ?> consumer, Collection<TopicPartition> partitions) {
        LOGGER.error(
                "Kafka定位消息分区意外丢失，groupId={}, partitions={}",
                consumer.groupMetadata().groupId(),
                partitions
        );
    }

    @EventListener
    public void onConsumerFailedToStart(ConsumerFailedToStartEvent event) {
        MessageListenerContainer container = locationContainer(event);
        if (container != null) {
            LOGGER.error(
                    "Kafka定位消息消费者启动失败，listenerId={}, broker={}, groupId={}",
                    container.getListenerId(),
                    bootstrapServers,
                    container.getGroupId()
            );
        }
    }

    @EventListener
    public void onConsumerStopped(ConsumerStoppedEvent event) {
        MessageListenerContainer container = locationContainer(event);
        if (container == null) {
            return;
        }
        if (ConsumerStoppedEvent.Reason.NORMAL.equals(event.getReason())) {
            LOGGER.info(
                    "Kafka定位消息消费者已正常停止，listenerId={}, groupId={}",
                    container.getListenerId(),
                    container.getGroupId()
            );
            return;
        }
        LOGGER.error(
                "Kafka定位消息消费者异常停止，listenerId={}, broker={}, groupId={}, reason={}",
                container.getListenerId(),
                bootstrapServers,
                container.getGroupId(),
                event.getReason()
        );
    }

    @EventListener
    public void onNonResponsiveConsumer(NonResponsiveConsumerEvent event) {
        if (!isLocationListener(event.getListenerId())) {
            return;
        }
        LOGGER.warn(
                "Kafka定位消息消费者无响应，listenerId={}, timeSinceLastPollMs={}, partitions={}",
                event.getListenerId(),
                event.getTimeSinceLastPoll(),
                event.getTopicPartitions()
        );
    }

    @EventListener
    public void onIdle(ListenerContainerIdleEvent event) {
        if (!isLocationListener(event.getListenerId())) {
            return;
        }
        Collection<TopicPartition> partitions = event.getTopicPartitions();
        if (partitions == null || partitions.isEmpty()) {
            LOGGER.warn(
                    "Kafka定位消息订阅尚未分配分区，listenerId={}, broker={}, idleMs={}",
                    event.getListenerId(),
                    bootstrapServers,
                    event.getIdleTime()
            );
            return;
        }
        LOGGER.info(
                "Kafka定位消息订阅正常，但暂未收到新消息，listenerId={}, "
                        + "idleMs={}, partitions={}",
                event.getListenerId(),
                event.getIdleTime(),
                partitions
        );
    }

    private MessageListenerContainer locationContainer(KafkaEvent event) {
        MessageListenerContainer container = event.getContainer(MessageListenerContainer.class);
        return container != null && isLocationListener(container.getListenerId()) ? container : null;
    }

    private boolean isLocationListener(String listenerId) {
        return listenerId != null && listenerId.startsWith(LOCATION_LISTENER_ID);
    }
}
