// =========================
// network_api.c
// =========================

#include "network_api.h"
#include "esp_log.h"
#include "cJSON.h"
#include "network.h"
#include "mqtt.h"

#include <string.h>
#include <stdlib.h>

static const char *TAG = "network_api";

static bool mqtt_host_is_invalid(const char *host)
{
    if (!host || host[0] == '\0')
        return true;

    if (strcmp(host, "localhost") == 0)
        return true;

    if (strcmp(host, "127.0.0.1") == 0)
        return true;

    if (strcmp(host, "0.0.0.0") == 0)
        return true;

    return false;
}

typedef struct
{
    bool enabled;
    char ssid[33];
    char password[65];
} wifi_task_data_t;

static void wifi_apply_config_task(void *param)
{
    wifi_task_data_t *data = (wifi_task_data_t *)param;
    ESP_LOGD("wifi_task", "Applying Wi-Fi config in background task");
    wifi_set_config(data->enabled, data->ssid, data->password);
    free(data);
    vTaskDelete(NULL);
}

static esp_err_t wifi_get_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "Handling GET /api/v1/config/wifi");

    httpd_resp_set_type(req, "application/json");

    bool enabled = wifi_get_enabled();
    char ssid[33] = {0};
    char password[65] = {0};

    wifi_get_ssid(ssid);
    wifi_get_password(password);

    cJSON *json = cJSON_CreateObject();
    cJSON_AddBoolToObject(json, "enabled", enabled);
    cJSON_AddStringToObject(json, "ssid", ssid);
    cJSON_AddStringToObject(json, "password", password);

    char *response = cJSON_Print(json);
    httpd_resp_sendstr(req, response);

    free(response);
    cJSON_Delete(json);

    return ESP_OK;
}

static esp_err_t wifi_post_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "Handling POST /api/v1/config/wifi");

    char buf[512];
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0)
        return ESP_FAIL;
    buf[len] = '\0';

    cJSON *json = cJSON_Parse(buf);
    if (!json)
        return ESP_FAIL;

    bool enabled = false;
    const char *ssid = NULL;
    const char *password = NULL;

    cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
    if (cJSON_IsBool(j_enabled))
        enabled = j_enabled->valueint;

    cJSON *j_ssid = cJSON_GetObjectItem(json, "ssid");
    if (cJSON_IsString(j_ssid))
        ssid = j_ssid->valuestring;

    cJSON *j_password = cJSON_GetObjectItem(json, "password");
    if (cJSON_IsString(j_password))
        password = j_password->valuestring;

    // Resposta imediata
    httpd_resp_sendstr(req, "Wi-Fi config atualizada com sucesso");

    wifi_task_data_t *task_data = (wifi_task_data_t *)malloc(sizeof(wifi_task_data_t));
    if (!task_data)
    {
        cJSON_Delete(json);
        ESP_LOGE(TAG, "Memory allocation failed for Wi-Fi task");
        return ESP_ERR_NO_MEM;
    }

    task_data->enabled = enabled;

    // Copias seguras (garante null-termination)
    strncpy(task_data->ssid, ssid ? ssid : "", sizeof(task_data->ssid) - 1);
    task_data->ssid[sizeof(task_data->ssid) - 1] = '\0';

    strncpy(task_data->password, password ? password : "", sizeof(task_data->password) - 1);
    task_data->password[sizeof(task_data->password) - 1] = '\0';

    xTaskCreate(
        wifi_apply_config_task,
        "wifi_config_task",
        4096,
        task_data,
        3,
        NULL);

    cJSON_Delete(json);
    return ESP_OK;
}

static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "Handling GET /api/v1/config/mqtt");

    httpd_resp_set_type(req, "application/json");

    bool enabled = mqtt_get_enabled();
    char server[64] = {0};
    char base_topic[32] = {0};
    char username[32] = {0};
    char password[64] = {0};
    uint16_t periodicity = mqtt_get_periodicity();

    mqtt_get_server(server);
    mqtt_get_base_topic(base_topic);
    mqtt_get_user(username);
    mqtt_get_password(password);

    ESP_LOGD(TAG, "MQTT Config:");
    ESP_LOGD(TAG, "  Enabled: %s", enabled ? "true" : "false");
    ESP_LOGD(TAG, "  Server: %s", server);
    ESP_LOGD(TAG, "  Topic: %s", base_topic);
    ESP_LOGD(TAG, "  Username: %s", username);
    ESP_LOGD(TAG, "  Password: %s", password);
    ESP_LOGD(TAG, "  Periodicity: %d", periodicity);

    cJSON *config = cJSON_CreateObject();
    cJSON_AddBoolToObject(config, "enabled", enabled);
    cJSON_AddStringToObject(config, "host", server);
    cJSON_AddNumberToObject(config, "port", 1883); // fixo (se não usas no mqtt_set_config)
    cJSON_AddStringToObject(config, "username", username);
    cJSON_AddStringToObject(config, "password", password);
    cJSON_AddStringToObject(config, "topic", base_topic);
    cJSON_AddNumberToObject(config, "periodicity", periodicity);

    char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    free(config_str);
    cJSON_Delete(config);
    return ESP_OK;
}

static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "Handling POST /api/v1/config/mqtt");

    char buf[512];
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0)
    {
        ESP_LOGE(TAG, "Failed to read request body");
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0';
    ESP_LOGD(TAG, "Received JSON: %s", buf);

    cJSON *json = cJSON_Parse(buf);
    if (!json)
    {
        ESP_LOGE(TAG, "Invalid JSON format");
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // --- Ler config atual (para permitir "partial update" e evitar strings vazias)
    bool current_enabled = mqtt_get_enabled();
    char current_host[64] = {0};
    char current_topic[32] = {0};
    char current_user[32] = {0};
    char current_pass[64] = {0};
    uint16_t current_periodicity = mqtt_get_periodicity();

    mqtt_get_server(current_host);
    mqtt_get_base_topic(current_topic);
    mqtt_get_user(current_user);
    mqtt_get_password(current_pass);

    bool enabled = current_enabled;
    const char *host_in = NULL, *topic_in = NULL, *user_in = NULL, *pass_in = NULL;
    int periodicity = (int)current_periodicity;

    cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
    if (cJSON_IsBool(j_enabled))
        enabled = j_enabled->valueint;

    cJSON *j_host = cJSON_GetObjectItem(json, "host");
    if (cJSON_IsString(j_host))
        host_in = j_host->valuestring;

    cJSON *j_topic = cJSON_GetObjectItem(json, "topic");
    if (cJSON_IsString(j_topic))
        topic_in = j_topic->valuestring;

    cJSON *j_user = cJSON_GetObjectItem(json, "username");
    if (cJSON_IsString(j_user))
        user_in = j_user->valuestring;

    cJSON *j_pass = cJSON_GetObjectItem(json, "password");
    if (cJSON_IsString(j_pass))
        pass_in = j_pass->valuestring;

    cJSON *j_periodicity = cJSON_GetObjectItem(json, "periodicity");
    if (cJSON_IsNumber(j_periodicity))
        periodicity = j_periodicity->valueint;

    const char *candidate_host =
        (host_in && host_in[0] != '\0') ? host_in :
        (current_host[0] != '\0') ? current_host :
        "mqtt.plixin.com";

    const char *host = mqtt_host_is_invalid(candidate_host)
        ? "mqtt.plixin.com"
        : candidate_host;

    const char *topic =
        (topic_in && topic_in[0] != '\0') ? topic_in : (current_topic[0] != '\0') ? current_topic
                                                                                  : "";

    const char *username =
        (user_in && user_in[0] != '\0') ? user_in : (current_user[0] != '\0') ? current_user
                                                                              : "";

    const char *password =
        (pass_in && pass_in[0] != '\0') ? pass_in : (current_pass[0] != '\0') ? current_pass
                                                                              : "";

    if (periodicity <= 0)
        periodicity = (int)current_periodicity;
    if (periodicity <= 0)
        periodicity = 30;

    ESP_LOGD(TAG, "Applying MQTT config:");
    ESP_LOGD(TAG, "  Enabled: %s", enabled ? "true" : "false");
    ESP_LOGD(TAG, "  Host: %s", host);
    ESP_LOGD(TAG, "  Topic: %s", topic);
    ESP_LOGD(TAG, "  Username: %s", username);
    ESP_LOGD(TAG, "  Password: %s", password);
    ESP_LOGD(TAG, "  Periodicity: %d", periodicity);

    esp_err_t err = mqtt_set_config(enabled, host, topic, username, password, periodicity);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Failed to apply MQTT config (code %d)", err);
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to apply config");
        cJSON_Delete(json);
        return ESP_FAIL;
    }

    httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");
    cJSON_Delete(json);
    return ESP_OK;
}

void register_network_handlers(httpd_handle_t server, void *ctx)
{
    httpd_uri_t wifi_get = {
        .uri = "/api/v1/config/wifi",
        .method = HTTP_GET,
        .handler = wifi_get_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &wifi_get);

    httpd_uri_t wifi_post = {
        .uri = "/api/v1/config/wifi",
        .method = HTTP_POST,
        .handler = wifi_post_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &wifi_post);

    httpd_uri_t config_mqtt_get_uri = {
        .uri = "/api/v1/config/mqtt",
        .method = HTTP_GET,
        .handler = config_mqtt_get_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &config_mqtt_get_uri);

    httpd_uri_t config_mqtt_post_uri = {
        .uri = "/api/v1/config/mqtt",
        .method = HTTP_POST,
        .handler = config_mqtt_post_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &config_mqtt_post_uri);
}