package de.assecutor.votianlt.mqtt;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.assecutor.votianlt.messaging.delivery.MessageDeliveryService;
import de.assecutor.votianlt.messaging.model.DeliveryOptions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Lazy;

/**
 * Simple MQTT publishing helper to send JSON payloads.
 *
 * This implementation now uses MessageDeliveryService for reliable delivery
 * with acknowledgment tracking and retry mechanism.
 *
 * Note: In environments where Spring Integration MQTT is unavailable (e.g.,
 * offline CI), this implementation degrades to a no-op publisher that logs the
 * intended message.
 */
public interface MqttPublisher {
    void publishAsJson(String topic, Object payload);

    void publishAsJson(String topic, Object payload, boolean retained);
}

@Component
@Slf4j
class MqttPublisherImpl implements MqttPublisher {

    private final ObjectMapper objectMapper;
    private final MessageDeliveryService deliveryService;

    public MqttPublisherImpl(@Lazy MessageDeliveryService deliveryService, ObjectMapper objectMapper) {
        this.deliveryService = deliveryService;
        this.objectMapper = objectMapper;
    }

    @Override
    public void publishAsJson(String topic, Object payload) {
        publishAsJson(topic, payload, false);
    }

    @Override
    public void publishAsJson(String topic, Object payload, boolean retained) {
        try {
            // Parse topic to extract clientId and messageType
            // Expected format: /client/{clientId}/{messageType}
            String[] parts = topic.split("/");
            if (parts.length < 4 || !"client".equals(parts[1])) {
                log.warn("Invalid topic format: {}. Expected /client/{clientId}/{messageType}", topic);
                return;
            }
            String clientId = parts[2];
            String messageType = parts[3];

            // Use MessageDeliveryService for reliable delivery
            DeliveryOptions options = DeliveryOptions.builder()
                    .requiresAck(true)
                    .retained(retained)
                    .build();

            deliveryService.sendToClient(clientId, messageType, payload, options)
                    .thenAccept(receipt -> {
                        log.info("=== MESSAGE DELIVERY SUBMITTED ===");
                        log.info("Topic: {}", topic);
                        log.info("Message ID: {}", receipt.getMessageId());
                        log.info("Status: {}", receipt.getStatus());
                        log.info("Retained: {}", retained);

                        // Log payload for debugging
                        try {
                            String json = (payload instanceof String s) ? s : objectMapper.writeValueAsString(payload);
                            log.info("Payload: {}", json);
                        } catch (Exception e) {
                            log.debug("Could not serialize payload for logging: {}", e.getMessage());
                        }

                        log.info("=== END MESSAGE DELIVERY ===");
                    })
                    .exceptionally(ex -> {
                        log.error("Failed to submit message for delivery to topic {}: {}", topic, ex.getMessage(), ex);
                        return null;
                    });

        } catch (Exception e) {
            log.error("Failed to publish message for topic {}: {}", topic, e.getMessage(), e);
        }
    }
}
