package com.gxwebsoft.hjm.service;

import com.gxwebsoft.common.core.config.MqttProperties;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * MQTT服务类
 *
 * @author 科技小王子
 * @since 2025-07-02
 */
@Service
public class MqttService {

    private static final Logger logger = LoggerFactory.getLogger(MqttService.class);

    @Resource
    private MqttProperties mqttProperties;

    @Resource
    private GpsMessageCallback gpsMessageCallback;

    private MqttClient client;
    private String clientId;
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    @PostConstruct
    public void init() {
        try {
            logger.info("开始初始化MQTT服务...");

            // 检查是否启用MQTT服务
            if (!mqttProperties.isEnabled()) {
                logger.info("MQTT服务已禁用，跳过初始化");
                return;
            }

            // 验证配置属性
            validateMqttProperties();

            // 生成唯一的客户端ID
            clientId = mqttProperties.getClientIdPrefix() + System.currentTimeMillis();
            logger.info("生成客户端ID: {}", clientId);

            // 连接MQTT服务器
            connect();

            // 订阅主题
            subscribe();

            // 启动连接状态监控
            startConnectionMonitor();

            logger.info("MQTT服务初始化完成");

        } catch (Exception e) {
            logger.error("MQTT服务初始化失败", e);
            // 不要抛出异常，避免影响应用启动
            // 可以在后台定期重试连接
            scheduleReconnect();
        }
    }

    /**
     * 验证MQTT配置属性
     */
    private void validateMqttProperties() {
        if (mqttProperties == null) {
            throw new IllegalArgumentException("MQTT配置属性为null，请检查配置文件和@EnableConfigurationProperties注解");
        }

        if (gpsMessageCallback == null) {
            throw new IllegalArgumentException("GPS消息回调处理器为null，请检查@Component注解");
        }

        logger.info("MQTT配置验证:");
        logger.info("  Host: {}", mqttProperties.getHost());
        logger.info("  Username: {}", mqttProperties.getUsername());
        logger.info("  Password: {}", mqttProperties.getPassword() != null ? "***" : "null");
        logger.info("  ClientIdPrefix: {}", mqttProperties.getClientIdPrefix());
        logger.info("  Topic: {}", mqttProperties.getTopic());
        logger.info("  QoS: {}", mqttProperties.getQos());
        logger.info("  ConnectionTimeout: {}", mqttProperties.getConnectionTimeout());
        logger.info("  KeepAliveInterval: {}", mqttProperties.getKeepAliveInterval());
        logger.info("  AutoReconnect: {}", mqttProperties.isAutoReconnect());
        logger.info("  CleanSession: {}", mqttProperties.isCleanSession());

        if (mqttProperties.getHost() == null || mqttProperties.getHost().trim().isEmpty()) {
            throw new IllegalArgumentException("MQTT服务器地址不能为空");
        }

        if (mqttProperties.getClientIdPrefix() == null) {
            throw new IllegalArgumentException("MQTT客户端ID前缀不能为空");
        }

        if (mqttProperties.getTopic() == null || mqttProperties.getTopic().trim().isEmpty()) {
            throw new IllegalArgumentException("MQTT订阅主题不能为空");
        }

        logger.info("MQTT配置验证通过");
    }

    /**
     * 连接MQTT服务器
     */
    private void connect() throws MqttException {
        if (client != null && client.isConnected()) {
            logger.debug("MQTT客户端已连接，跳过连接操作");
            return;
        }

        logger.info("正在连接MQTT服务器: {}", mqttProperties.getHost());

        // 创建MQTT客户端
        client = new MqttClient(mqttProperties.getHost(), clientId, new MemoryPersistence());

        // 设置连接选项
        MqttConnectOptions options = createConnectOptions();

        // 设置回调
        client.setCallback(gpsMessageCallback);

        // 连接服务器
        client.connect(options);

        logger.info("MQTT连接成功 - 服务器: {}, 客户端ID: {}", mqttProperties.getHost(), clientId);
    }

    /**
     * 创建连接选项
     */
    private MqttConnectOptions createConnectOptions() {
        MqttConnectOptions options = new MqttConnectOptions();

        // 基本连接参数
        options.setCleanSession(mqttProperties.isCleanSession());
        options.setUserName(mqttProperties.getUsername());
        options.setPassword(mqttProperties.getPassword().toCharArray());

        // 超时和心跳设置
        options.setConnectionTimeout(mqttProperties.getConnectionTimeout());
        options.setKeepAliveInterval(mqttProperties.getKeepAliveInterval());

        // 自动重连设置
        options.setAutomaticReconnect(mqttProperties.isAutoReconnect());

        // 遗嘱消息设置（可选）
        // options.setWill("client/disconnect", "Client disconnected".getBytes(), 1, false);

        logger.debug("MQTT连接选项配置完成 - 自动重连: {}, 清除会话: {}",
                    options.isAutomaticReconnect(), options.isCleanSession());

        return options;
    }

    /**
     * 订阅主题
     */
    public void subscribe() throws MqttException {
        if (client == null || !client.isConnected()) {
            logger.warn("MQTT客户端未连接，无法订阅主题");
            return;
        }

        String topic = mqttProperties.getTopic();
        int qos = mqttProperties.getQos();

        client.subscribe(topic, qos);
        logger.info("MQTT主题订阅成功 - 主题: {}, QoS: {}", topic, qos);
    }

    /**
     * 发布消息
     */
    public void publish(String topic, String payload) throws MqttException {
        publish(topic, payload, mqttProperties.getQos(), false);
    }

    /**
     * 发布消息（指定QoS和保留标志）
     */
    public void publish(String topic, String payload, int qos, boolean retained) throws MqttException {
        if (client == null || !client.isConnected()) {
            throw new MqttException(MqttException.REASON_CODE_CLIENT_NOT_CONNECTED);
        }

        MqttMessage message = new MqttMessage();
        message.setPayload(payload.getBytes());
        message.setQos(qos);
        message.setRetained(retained);

        client.publish(topic, message);

        logger.debug("MQTT消息发布 - 主题: {}, QoS: {}, 保留: {}, 消息长度: {}",
                    topic, qos, retained, payload.length());

        // 可选：等待发布完成
        // token.waitForCompletion();
    }

    /**
     * 检查连接状态
     */
    public boolean isConnected() {
        return client != null && client.isConnected();
    }

    /**
     * 获取客户端信息
     */
    public String getClientInfo() {
        if (client == null) {
            return "MQTT客户端未初始化";
        }

        return String.format("客户端ID: %s, 连接状态: %s, 服务器: %s",
                           clientId,
                           client.isConnected() ? "已连接" : "未连接",
                           mqttProperties.getHost());
    }

    /**
     * 启动连接状态监控
     */
    private void startConnectionMonitor() {
        scheduler.scheduleWithFixedDelay(() -> {
            try {
                if (!isConnected()) {
                    logger.warn("检测到MQTT连接断开，尝试重新连接...");
                    reconnect();
                }
            } catch (Exception e) {
                logger.error("MQTT连接监控异常", e);
            }
        }, 30, 30, TimeUnit.SECONDS); // 每30秒检查一次连接状态

        logger.debug("MQTT连接状态监控已启动");
    }

    /**
     * 重新连接
     */
    public void reconnect() {
        try {
            if (client != null && client.isConnected()) {
                return;
            }

            logger.info("正在重新连接MQTT服务器...");

            // 先断开现有连接
            disconnect();

            // 重新连接
            connect();
            subscribe();

            logger.info("MQTT重新连接成功");

        } catch (Exception e) {
            logger.error("MQTT重新连接失败", e);
            // 安排下次重试
            scheduleReconnect();
        }
    }

    /**
     * 安排重新连接
     */
    private void scheduleReconnect() {
        scheduler.schedule(() -> {
            logger.info("执行定时重连任务...");
            reconnect();
        }, 60, TimeUnit.SECONDS); // 60秒后重试
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        try {
            if (client != null && client.isConnected()) {
                client.disconnect();
                logger.info("MQTT连接已断开");
            }
        } catch (MqttException e) {
            logger.error("断开MQTT连接失败", e);
        }
    }

    /**
     * 应用关闭时清理资源
     */
    @PreDestroy
    public void destroy() {
        logger.info("正在关闭MQTT服务...");

        try {
            // 关闭定时任务
            scheduler.shutdown();
            if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }

            // 断开MQTT连接
            if (client != null) {
                if (client.isConnected()) {
                    client.disconnect();
                }
                client.close();
            }

            logger.info("MQTT服务已关闭");

        } catch (Exception e) {
            logger.error("关闭MQTT服务时发生错误", e);
        }
    }
}
