package de.assecutor.votianlt.messaging.delivery;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.assecutor.votianlt.controller.MessageController;
import de.assecutor.votianlt.dto.AppLoginRequest;
import de.assecutor.votianlt.messaging.model.MessageEnvelope;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * Handles acknowledgments and routes incoming messages to application layer.
 * Acts as a bridge between the messaging layer and the application logic.
 */
@Component
@Slf4j
public class AcknowledgmentHandler {

    private final MessageController messageController;
    private final ObjectMapper objectMapper;

    public AcknowledgmentHandler(@Lazy MessageController messageController, ObjectMapper objectMapper) {
        this.messageController = messageController;
        this.objectMapper = objectMapper;
    }

    /**
     * Route incoming message envelope to appropriate application handler.
     * Unwraps the envelope and delegates to MessageController.
     */
    public void routeIncomingMessage(MessageEnvelope envelope) {
        try {
            String topic = envelope.getTopic();
            Object payload = envelope.getPayload();

            log.debug("[AckHandler] Routing message {} on topic {}", envelope.getMessageId(), topic);

            // Convert payload to Map for routing
            Map<String, Object> payloadMap = objectMapper.convertValue(payload, 
                    new TypeReference<Map<String, Object>>() {});

            // Route based on topic pattern
            if (topic.matches("/server/.+/task_completed")) {
                handleTaskCompleted(payloadMap);
            } else if (topic.matches("/server/.+/jobs/assigned")) {
                handleJobsAssigned(topic, payloadMap);
            } else if (topic.equals("/server/login")) {
                handleLogin(payloadMap);
            } else if (topic.matches("/server/.+/message")) {
                handleIncomingMessage(topic, payloadMap);
            } else if (topic.matches("/server/.+/pong")) {
                handlePong(topic, payloadMap);
            } else {
                log.debug("[AckHandler] No route for topic {}", topic);
            }

        } catch (Exception e) {
            log.error("[AckHandler] Error routing message {}: {}", 
                    envelope.getMessageId(), e.getMessage(), e);
        }
    }

    /**
     * Handle task completion message
     */
    private void handleTaskCompleted(Map<String, Object> payload) {
        try {
            Object tt = payload.get("taskType");
            String taskType = tt != null ? tt.toString() : null;
            messageController.handleTaskCompleted(payload, taskType);
        } catch (Exception e) {
            log.error("[AckHandler] Error handling task_completed: {}", e.getMessage(), e);
        }
    }

    /**
     * Handle jobs assigned request
     */
    private void handleJobsAssigned(String topic, Map<String, Object> payload) {
        try {
            // Extract clientId from topic: /server/{clientId}/jobs/assigned
            String[] parts = topic.split("/");
            String clientId = parts.length > 2 ? parts[2] : null;
            if (clientId != null && !clientId.isBlank()) {
                payload.put("clientId", clientId);
            } else {
                log.warn("[AckHandler] Couldn't extract clientId from topic {} for jobs/assigned", topic);
            }
            messageController.handleGetAssignedJobs(payload);
        } catch (Exception e) {
            log.error("[AckHandler] Error handling jobs/assigned: {}", e.getMessage(), e);
        }
    }

    /**
     * Handle login request
     * Topic: /server/login
     */
    private void handleLogin(Map<String, Object> payload) {
        try {
            AppLoginRequest req = objectMapper.convertValue(payload, AppLoginRequest.class);
            messageController.handleAppLogin(req);
        } catch (Exception e) {
            log.error("[AckHandler] Error handling login: {}", e.getMessage(), e);
        }
    }

    /**
     * Handle incoming chat message
     */
    private void handleIncomingMessage(String topic, Map<String, Object> payload) {
        try {
            // Extract clientId from topic: /server/{clientId}/message
            String[] parts = topic.split("/");
            String clientId = parts.length > 2 ? parts[2] : null;
            if (clientId != null && !clientId.isBlank()) {
                payload.put("clientId", clientId);
            } else {
                log.warn("[AckHandler] Couldn't extract clientId from topic {} for message", topic);
            }
            messageController.handleIncomingMessage(payload);
        } catch (Exception e) {
            log.error("[AckHandler] Error handling incoming message: {}", e.getMessage(), e);
        }
    }

    /**
     * Handle pong response from client for connection monitoring
     */
    private void handlePong(String topic, Map<String, Object> payload) {
        try {
            // Extract clientId from topic: /server/{clientId}/pong
            String[] parts = topic.split("/");
            String clientId = parts.length > 2 ? parts[2] : null;
            if (clientId != null && !clientId.isBlank()) {
                payload.put("clientId", clientId);
            } else {
                log.warn("[AckHandler] Couldn't extract clientId from topic {} for pong", topic);
            }
            messageController.handlePong(payload);
        } catch (Exception e) {
            log.error("[AckHandler] Error handling pong: {}", e.getMessage(), e);
        }
    }
}

