package com.yupi.project.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.project.mapper.MqttCommunicationLogMapper;
import com.yupi.project.model.entity.MqttCommunicationLog;
import com.yupi.project.service.MqttCommunicationLogService;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.UUID;

@Service
@Slf4j
public class MqttCommunicationLogServiceImpl extends ServiceImpl<MqttCommunicationLogMapper, MqttCommunicationLog>
        implements MqttCommunicationLogService {

    private static final String DIRECTION_UPSTREAM = "UPSTREAM";
    private static final String DIRECTION_DOWNSTREAM = "DOWNSTREAM";
    private static final String PAYLOAD_FORMAT_TEXT = "TEXT";
    private static final String PAYLOAD_FORMAT_JSON = "JSON"; // Assume JSON if parseable
    private static final String PAYLOAD_FORMAT_BINARY = "BINARY";

    @Override
    @Async("mqttLoggerThreadPoolTaskExecutor") // Ensure this bean name matches your AsyncConfigurer
    public void asyncLogMessage(String topic, MqttMessage message, String direction, String clientId,
                                String messageIdStr, String backendProcessingStatus,
                                String backendProcessingInfo, Long relatedSessionId, Long relatedTaskId) {
        try {
            MqttCommunicationLog logEntry = new MqttCommunicationLog();
            logEntry.setMessageId(messageIdStr != null ? messageIdStr : (message.getId() > 0 ? String.valueOf(message.getId()) : null) );
            logEntry.setDirection(direction);
            logEntry.setClientId(clientId);
            logEntry.setTopic(topic);

            byte[] payloadBytes = message.getPayload();
            String payloadString = new String(payloadBytes, StandardCharsets.UTF_8);
            logEntry.setPayload(payloadString); // Store as string

            // Basic payload format detection (can be enhanced)
            if (isJson(payloadString)) {
                logEntry.setPayloadFormat(PAYLOAD_FORMAT_JSON);
            } else {
                logEntry.setPayloadFormat(PAYLOAD_FORMAT_TEXT); // Default to TEXT, could be BINARY if not UTF-8 decodable well
            }
            // For true binary, would need different handling or indication

            logEntry.setQos(message.getQos());
            logEntry.setIsRetained(message.isRetained());
            logEntry.setLogTimestamp(new Date()); // Record time when log entry is created

            logEntry.setBackendProcessingStatus(backendProcessingStatus);
            logEntry.setBackendProcessingInfo(backendProcessingInfo);
            logEntry.setRelatedSessionId(relatedSessionId);
            logEntry.setRelatedTaskId(relatedTaskId);

            this.save(logEntry);
        } catch (Exception e) {
            log.error("Failed to asynchronously log MQTT message. Topic: {}, Direction: {}, ClientId: {}", topic, direction, clientId, e);
        }
    }

    @Override
    @Async("mqttLoggerThreadPoolTaskExecutor")
    public void asyncLogDownstreamMessage(String topic, String payload, Integer qos, Boolean retained, String clientId, String messageIdStr, Long relatedSessionId, Long relatedTaskId) {
        try {
            MqttCommunicationLog logEntry = new MqttCommunicationLog();
            logEntry.setMessageId(messageIdStr != null ? messageIdStr : UUID.randomUUID().toString()); // Generate UUID if not provided
            logEntry.setDirection(DIRECTION_DOWNSTREAM);
            logEntry.setClientId(clientId);
            logEntry.setTopic(topic);
            logEntry.setPayload(payload);

            if (isJson(payload)) {
                logEntry.setPayloadFormat(PAYLOAD_FORMAT_JSON);
            } else {
                logEntry.setPayloadFormat(PAYLOAD_FORMAT_TEXT);
            }

            logEntry.setQos(qos);
            logEntry.setIsRetained(retained != null ? retained : false);
            logEntry.setLogTimestamp(new Date());

            // For downstream, processing status/info is typically not set at the moment of logging send attempt
            // It might be updated later if a response is expected and tracked.
            logEntry.setRelatedSessionId(relatedSessionId);
            logEntry.setRelatedTaskId(relatedTaskId);

            this.save(logEntry);
        } catch (Exception e) {
            log.error("Failed to asynchronously log downstream MQTT message. Topic: {}, ClientId: {}", topic, clientId, e);
        }
    }

    private boolean isJson(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        String trimmedStr = str.trim();
        return (trimmedStr.startsWith("{") && trimmedStr.endsWith("}")) || (trimmedStr.startsWith("[") && trimmedStr.endsWith("]"));
    }
} 