#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "mqtt_client.h"
#include "esp_system.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include "cJSON.h"
#include "certs.h"
#include "mqtt_comandos.h"
#include "led_driver.h"
#include "esp_timer.h"
#include "esp_event.h"
#include "eeprom_virtual.h"

static const char *TAG = "MQTT";

// -------- CONFIG --------
#define BROKER_HOST      "mtqq.xupas.mywire.org"
#define BROKER_PORT_TLS  8883
#define BROKER_PORT_TCP  1883
#define MQTT_USER        "xupa"
#define MQTT_PASS        "xupa"

esp_mqtt_client_handle_t mqtt_client = NULL;
static esp_timer_handle_t mqtt_watchdog = NULL;
static bool mqtt_connected = false;

static char topic_status[64];
static char topic_cmd[64];
static char topic_resp[64];
static char topic_lwt[64];

// ======================================================
//                HEARTBEAT / STATUS
// ======================================================
static void send_status(void) {
    if (!mqtt_client || !mqtt_connected) return;

    char buf[160];
    snprintf(buf, sizeof(buf),
             "{\"uptime\":%lu,\"heap\":%lu}",
             (unsigned long)(esp_log_timestamp() / 1000),
             (unsigned long)esp_get_free_heap_size());

    esp_mqtt_client_publish(mqtt_client, topic_status, buf, 0, 1, true);
    ESP_LOGI(TAG, "📤 STATUS -> %s", buf);
}

// ======================================================
//                WATCHDOG CALLBACK
// ======================================================
static void mqtt_watchdog_cb(void *arg) {
    if (!mqtt_connected) {
        ESP_LOGE(TAG, "⏱️ 2 minutos sem MQTT, reiniciando ESP...");
        esp_restart();
    }
}

// ======================================================
//                EVENT HANDLER
// ======================================================
static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
                               int32_t event_id, void *event_data) {
    esp_mqtt_event_handle_t event = event_data;

    switch (event->event_id) {
        case MQTT_EVENT_CONNECTED:
            mqtt_connected = true;
            led_set(0, 0, 50, 0);
            led_show();
            ESP_LOGI(TAG, "✅ MQTT conectado");
            esp_mqtt_client_publish(mqtt_client, topic_status, "online", 0, 1, true);
            esp_mqtt_client_subscribe(mqtt_client, topic_cmd, 1);
            send_status();

            if (mqtt_watchdog) esp_timer_stop(mqtt_watchdog);
            break;

        case MQTT_EVENT_DISCONNECTED:
            mqtt_connected = false;
            led_set(0, 50, 0, 0);
            led_show();
            ESP_LOGW(TAG, "⚠️ MQTT desconectado");
            if (mqtt_watchdog) esp_timer_start_periodic(mqtt_watchdog, 120000000);
            break;

        case MQTT_EVENT_DATA: {
            ESP_LOGI(TAG, "📩 [%.*s] %.*s",
                     event->topic_len, event->topic,
                     event->data_len, event->data);

            cJSON *root = cJSON_ParseWithLength(event->data, event->data_len);
            if (root) {
                mqtt_comandos_handle(root);
                cJSON_Delete(root);
            } else {
                ESP_LOGE(TAG, "❌ JSON inválido");
            }
            break;
        }

        case MQTT_EVENT_ERROR:
            ESP_LOGE(TAG, "❌ Erro MQTT");
            break;

        default:
            break;
    }
}

// ======================================================
//                HEARTBEAT TASK
// ======================================================
static void mqtt_heartbeat_task(void *arg) {
    while (1) {
        send_status();
        vTaskDelay(pdMS_TO_TICKS(30000)); // envia status a cada 30s
    }
}

// ======================================================
//                START / CONFIG
// ======================================================
void mqtt_handler_start(void) {
    esp_mqtt_client_config_t mqtt_cfg = {0};

    // -------- IDENTIFICADOR AUTOMÁTICO --------
    char device_id[16];
    uint8_t mac[6];
    esp_read_mac(mac, ESP_MAC_WIFI_STA);
    snprintf(device_id, sizeof(device_id), "esp_%02X%02X%02X", mac[3], mac[4], mac[5]);

    esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
    if (netif) esp_netif_set_hostname(netif, device_id);
    ESP_LOGI(TAG, "🆔 ID do dispositivo: %s", device_id);

    snprintf(topic_status, sizeof(topic_status), "esp/%s/status", device_id);
    snprintf(topic_cmd,    sizeof(topic_cmd),    "esp/%s/cmd",    device_id);
    snprintf(topic_resp,   sizeof(topic_resp),   "esp/%s/resp",   device_id);
    snprintf(topic_lwt,    sizeof(topic_lwt),    "esp/%s/lwt",    device_id);

    mqtt_cfg.credentials.client_id = device_id;
    mqtt_cfg.credentials.username = MQTT_USER;
    mqtt_cfg.credentials.authentication.password = MQTT_PASS;

    // ======================================================
    //     TENTA CARREGAR CERTIFICADO E USAR TLS
    // ======================================================
    bool tls_ok = false;
    static char cert_buf[4096];
    size_t cert_len = sizeof(cert_buf) - 1;

    if (eeprom_virtual_read_bin("cert", cert_buf, &cert_len) == ESP_OK && cert_len > 0) {
        cert_buf[cert_len] = '\0';
        mqtt_cfg.broker.verification.certificate = strdup(cert_buf);
        mqtt_cfg.broker.address.hostname = BROKER_HOST;
        mqtt_cfg.broker.address.port = BROKER_PORT_TLS;
        mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_SSL;
        tls_ok = true;
        ESP_LOGI(TAG, "🔐 Certificado TLS carregado da EEPROM (%d bytes)", (int)cert_len);
    } else {
        ESP_LOGW(TAG, "⚠️ Certificado TLS não encontrado — vai tentar padrão embutido...");
        mqtt_cfg.broker.verification.certificate = (const char *)ca_cert_pem;
        mqtt_cfg.broker.address.hostname = BROKER_HOST;
        mqtt_cfg.broker.address.port = BROKER_PORT_TLS;
        mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_SSL;
        tls_ok = true;
    }

    // ======================================================
    //      TESTE: se TLS falhar, cai para TCP (sem SSL)
    // ======================================================
    if (!tls_ok) {
        ESP_LOGW(TAG, "⚠️ TLS indisponível — a usar MQTT sem SSL.");
        mqtt_cfg.broker.address.hostname = BROKER_HOST;
        mqtt_cfg.broker.address.port = BROKER_PORT_TCP;
        mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
    }

    // -------- LWT --------
    mqtt_cfg.session.last_will.topic  = topic_lwt;
    mqtt_cfg.session.last_will.msg    = "offline";
    mqtt_cfg.session.last_will.qos    = 1;
    mqtt_cfg.session.last_will.retain = true;

    // ======================================================
    //      INICIALIZAÇÃO DO CLIENTE
    // ======================================================
    mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
    if (mqtt_client == NULL) {
        ESP_LOGE(TAG, "❌ Falha a inicializar MQTT — a tentar fallback TCP...");
        mqtt_cfg.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
        mqtt_cfg.broker.address.port = BROKER_PORT_TCP;
        mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
    }

    esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
    esp_mqtt_client_start(mqtt_client);

    ESP_LOGI(TAG, "🚀 MQTT inicializado em %s:%lu (%s)",
         mqtt_cfg.broker.address.hostname,
         (unsigned long)mqtt_cfg.broker.address.port,
         mqtt_cfg.broker.address.transport == MQTT_TRANSPORT_OVER_SSL ? "TLS" : "TCP");

    // -------- WATCHDOG MQTT --------
    const esp_timer_create_args_t wd_args = {
        .callback = &mqtt_watchdog_cb,
        .name = "mqtt_watchdog"
    };
    esp_timer_create(&wd_args, &mqtt_watchdog);

    // -------- HEARTBEAT TASK --------
    xTaskCreate(mqtt_heartbeat_task, "mqtt_heartbeat", 12288, NULL, 5, NULL);
}
