/* HTTP Restful API Server

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <fcntl.h>
#include "esp_http_server.h"
#include "esp_chip_info.h"
#include "esp_random.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "cJSON.h"
#include "rest.h"

static const char *REST_TAG = "esp-rest";
#define REST_CHECK(a, str, goto_tag, ...)                                              \
    do                                                                                 \
    {                                                                                  \
        if (!(a))                                                                      \
        {                                                                              \
            ESP_LOGE(REST_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
            goto goto_tag;                                                             \
        }                                                                              \
    } while (0)

#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
#define SCRATCH_BUFSIZE (10240)

typedef struct rest_server_context {
    char base_path[ESP_VFS_PATH_MAX + 1];
    char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;

#define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)

// Estruturas para armazenar as configurações
static struct {
    bool enabled;
    char ssid[128];
    char password[128];
} wifi_config = {false, "", ""};

static struct {
    bool enabled;
    char host[256];
    int port;
    char username[128];
    char password[128];
    char topic[128];
} mqtt_config = {false, "", 1883, "", "", ""};

// Estrutura para armazenar as configurações OCPP em memória
static struct {
    char url[256];
    char chargeBoxId[128];
    char certificate[256];
    char privateKey[256];
} ocpp_config = {"", "", "", ""};

// Estrutura para armazenar as configurações de energia
static struct {
    int currentLimit;
    int powerLimit;
    int energyLimit;
    int chargingTimeLimit;
    int temperatureLimit;
} settings_config = {32, 0, 0, 0, 60};


// Estruturas para armazenar as configurações de autenticação e usuários
static struct {
    bool RFID;
    bool App;
    bool Password;
} auth_methods = {false, false, true};

static struct {
    char username[128];
} users[10] = {{"admin"}, {"user1"}};
static int num_users = 2; // Contador de usuários cadastrados


// Set HTTP response content type according to file extension
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
{
    const char *type = "text/plain";
    if (CHECK_FILE_EXTENSION(filepath, ".html")) {
        type = "text/html";
    } else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
        type = "application/javascript";
    } else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
        type = "text/css";
    } else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
        type = "image/png";
    } else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
        type = "image/x-icon";
    } else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
        type = "text/xml";
    }
    return httpd_resp_set_type(req, type);
}

/* Send HTTP response with the contents of the requested file */
static esp_err_t rest_common_get_handler(httpd_req_t *req)
{
    char filepath[FILE_PATH_MAX];

    rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx;
    strlcpy(filepath, rest_context->base_path, sizeof(filepath));
    if (req->uri[strlen(req->uri) - 1] == '/') {
        strlcat(filepath, "/index.html", sizeof(filepath));
    } else {
        strlcat(filepath, req->uri, sizeof(filepath));
    }
    int fd = open(filepath, O_RDONLY, 0);
    if (fd == -1) {
        ESP_LOGW(REST_TAG, "Failed to open file : %s, redirecting to index", filepath);
        /* Try to serve index.html for SPA routing */
        strlcpy(filepath, rest_context->base_path, sizeof(filepath));
        strlcat(filepath, "/index.html", sizeof(filepath));
        fd = open(filepath, O_RDONLY, 0);
        if (fd == -1) {
            ESP_LOGE(REST_TAG, "Failed to open index file : %s", filepath);
            httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File not found");
            return ESP_FAIL;
        }
    }

    set_content_type_from_file(req, filepath);

    char *chunk = rest_context->scratch;
    ssize_t read_bytes;
    do {
        /* Read file in chunks into the scratch buffer */
        read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
        if (read_bytes == -1) {
            ESP_LOGE(REST_TAG, "Failed to read file : %s", filepath);
        } else if (read_bytes > 0) {
            /* Send the buffer contents as HTTP response chunk */
            if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
                close(fd);
                ESP_LOGE(REST_TAG, "File sending failed!");
                /* Abort sending file */
                httpd_resp_sendstr_chunk(req, NULL);
                /* Respond with 500 Internal Server Error */
                httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
                return ESP_FAIL;
            }
        }
    } while (read_bytes > 0);
    /* Close file after sending complete */
    close(fd);
    ESP_LOGI(REST_TAG, "File sending complete");
    /* Respond with an empty chunk to signal HTTP response completion */
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

// Manipulador para o endpoint GET /api/v1/config/electrical
static esp_err_t electrical_config_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com as configurações de rede elétrica
    cJSON *config = cJSON_CreateObject();
    cJSON *monitor = cJSON_CreateObject();
    cJSON_AddStringToObject(monitor, "voltage", "230");
    cJSON_AddStringToObject(monitor, "current", "10");
    cJSON_AddStringToObject(monitor, "quality", "1");
    cJSON_AddItemToObject(config, "monitor", monitor);
    cJSON_AddBoolToObject(config, "alerts", true);
    
    // Adicionar mais configurações (security, loadBalancing, solar) no objeto config
    // ...
    
    // Enviar a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberar memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}


// Manipulador para o endpoint POST /api/v1/config/electrical
static esp_err_t electrical_config_post_handler(httpd_req_t *req)
{
    char buf[512];
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Request body is empty");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Processar os dados recebidos e atualizar as configurações (monitor, alerts, etc.)
    // Exemplo de configuração:
    cJSON *monitor = cJSON_GetObjectItem(json, "monitor");
    if (monitor) {
        // Atualizar configurações do monitor
        // ...
    }

    // Atualizar outras configurações...

    // Responder com sucesso
    httpd_resp_sendstr(req, "Configuração gravada com sucesso!");

    cJSON_Delete(json);

    return ESP_OK;
}


// Manipulador para o endpoint /api/v1/config/load-balancing
static esp_err_t config_load_balancing_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON de configuração
    cJSON *config = cJSON_CreateObject();

    // Configuração de load balancing
    cJSON_AddBoolToObject(config, "enabled", true); // Exemplo: load balancing ativado
    cJSON_AddNumberToObject(config, "maxChargingCurrent", 32); // Exemplo: corrente máxima de 32A

    // Lista de dispositivos disponíveis
    cJSON *devices = cJSON_CreateArray();
    cJSON_AddItemToArray(devices, cJSON_CreateString("Device 1")); // Exemplo de dispositivo
    cJSON_AddItemToArray(devices, cJSON_CreateString("Device 2")); // Outro exemplo de dispositivo
    cJSON_AddItemToObject(config, "devices", devices);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/ocpp (Status do OCPP)
static esp_err_t ocpp_status_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON de status
    cJSON *status = cJSON_CreateObject();
    cJSON_AddStringToObject(status, "status", "connected");  // Status de exemplo, você pode adaptar conforme sua lógica

    // Convertendo para string e enviando a resposta
    const char *status_str = cJSON_Print(status);
    httpd_resp_sendstr(req, status_str);

    // Liberando a memória
    free((void *)status_str);
    cJSON_Delete(status);

    return ESP_OK;
}

// Manipulador para o endpoint GET /api/v1/config/ocpp (Configuração OCPP)
static esp_err_t config_ocpp_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com as configurações do OCPP
    cJSON *config = cJSON_CreateObject();
    cJSON_AddStringToObject(config, "url", ocpp_config.url);
    cJSON_AddStringToObject(config, "chargeBoxId", ocpp_config.chargeBoxId);
    cJSON_AddStringToObject(config, "certificate", ocpp_config.certificate);
    cJSON_AddStringToObject(config, "privateKey", ocpp_config.privateKey);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}

// Manipulador para o endpoint POST /api/v1/config/ocpp (Salvar configuração OCPP)
static esp_err_t config_ocpp_post_handler(httpd_req_t *req)
{
    char buf[512];  // Buffer para armazenar a requisição
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Atualizando as configurações OCPP
    cJSON *url = cJSON_GetObjectItem(json, "url");
    if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));

    cJSON *chargeBoxId = cJSON_GetObjectItem(json, "chargeBoxId");
    if (chargeBoxId) strlcpy(ocpp_config.chargeBoxId, chargeBoxId->valuestring, sizeof(ocpp_config.chargeBoxId));

    cJSON *certificate = cJSON_GetObjectItem(json, "certificate");
    if (certificate) strlcpy(ocpp_config.certificate, certificate->valuestring, sizeof(ocpp_config.certificate));

    cJSON *privateKey = cJSON_GetObjectItem(json, "privateKey");
    if (privateKey) strlcpy(ocpp_config.privateKey, privateKey->valuestring, sizeof(ocpp_config.privateKey));

    cJSON_Delete(json);

    // Responder com uma mensagem de sucesso
    httpd_resp_sendstr(req, "Configuração OCPP atualizada com sucesso");

    return ESP_OK;
}

// Manipulador para o endpoint POST /api/v1/config/settings
static esp_err_t config_settings_post_handler(httpd_req_t *req)
{
    char buf[512];  // Buffer para armazenar a requisição
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Atualizando as configurações
    cJSON *currentLimit = cJSON_GetObjectItem(json, "currentLimit");
    if (currentLimit) settings_config.currentLimit = currentLimit->valueint;

    cJSON *powerLimit = cJSON_GetObjectItem(json, "powerLimit");
    if (powerLimit) settings_config.powerLimit = powerLimit->valueint;

    cJSON *energyLimit = cJSON_GetObjectItem(json, "energyLimit");
    if (energyLimit) settings_config.energyLimit = energyLimit->valueint;

    cJSON *chargingTimeLimit = cJSON_GetObjectItem(json, "chargingTimeLimit");
    if (chargingTimeLimit) settings_config.chargingTimeLimit = chargingTimeLimit->valueint;

    cJSON *temperatureLimit = cJSON_GetObjectItem(json, "temperatureLimit");
    if (temperatureLimit) settings_config.temperatureLimit = temperatureLimit->valueint;

    cJSON_Delete(json);

    // Responder com uma mensagem de sucesso
    httpd_resp_sendstr(req, "Configurações de energia atualizadas com sucesso");

    return ESP_OK;
}


// Manipulador para o endpoint GET /api/v1/config/settings
static esp_err_t config_settings_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON para enviar as configurações atuais
    cJSON *config = cJSON_CreateObject();
    cJSON_AddNumberToObject(config, "currentLimit", settings_config.currentLimit);
    cJSON_AddNumberToObject(config, "powerLimit", settings_config.powerLimit);
    cJSON_AddNumberToObject(config, "energyLimit", settings_config.energyLimit);
    cJSON_AddNumberToObject(config, "chargingTimeLimit", settings_config.chargingTimeLimit);
    cJSON_AddNumberToObject(config, "temperatureLimit", settings_config.temperatureLimit);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}


// Manipulador para o endpoint GET /api/v1/dashboard
static esp_err_t dashboard_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com os dados do Dashboard
    cJSON *dashboard = cJSON_CreateObject();

    // Status do sistema
    cJSON_AddStringToObject(dashboard, "status", "Ativo");

    // Carregadores (exemplo)
    cJSON *chargers = cJSON_CreateArray();
    cJSON *charger1 = cJSON_CreateObject();
    cJSON_AddNumberToObject(charger1, "id", 1);
    cJSON_AddStringToObject(charger1, "status", "Ativo");
    cJSON_AddNumberToObject(charger1, "current", 12);
    cJSON_AddNumberToObject(charger1, "power", 2200);
    cJSON_AddItemToArray(chargers, charger1);

    cJSON_AddItemToObject(dashboard, "chargers", chargers);

    // Consumo de energia
    cJSON_AddNumberToObject(dashboard, "energyConsumed", 50.3);

    // Tempo de carregamento
    cJSON_AddNumberToObject(dashboard, "chargingTime", 120);

    // Alertas
    cJSON *alerts = cJSON_CreateArray();
    cJSON_AddItemToArray(alerts, cJSON_CreateString("Aviso: Carregador 1 está com erro."));
    cJSON_AddItemToObject(dashboard, "alerts", alerts);

    // Convertendo para string e enviando a resposta
    const char *dashboard_str = cJSON_Print(dashboard);
    httpd_resp_sendstr(req, dashboard_str);

    // Liberando a memória
    free((void *)dashboard_str);
    cJSON_Delete(dashboard);

    return ESP_OK;
}


static esp_err_t config_wifi_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com as configurações de Wi-Fi
    cJSON *config = cJSON_CreateObject();
    cJSON_AddBoolToObject(config, "enabled", wifi_config.enabled);
    cJSON_AddStringToObject(config, "ssid", wifi_config.ssid);
    cJSON_AddStringToObject(config, "password", wifi_config.password);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}

/* Manipulador para o endpoint POST /api/v1/config/wifi */
static esp_err_t config_wifi_post_handler(httpd_req_t *req)
{
    char buf[512];  // Buffer para armazenar a requisição
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Atualizando as configurações Wi-Fi
    cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
    if (enabled) wifi_config.enabled = enabled->valueint;

    cJSON *ssid = cJSON_GetObjectItem(json, "ssid");
    if (ssid) strlcpy(wifi_config.ssid, ssid->valuestring, sizeof(wifi_config.ssid));

    cJSON *password = cJSON_GetObjectItem(json, "password");
    if (password) strlcpy(wifi_config.password, password->valuestring, sizeof(wifi_config.password));

    cJSON_Delete(json);

    // Responder com uma mensagem de sucesso
    httpd_resp_sendstr(req, "Configuração Wi-Fi atualizada com sucesso");

    return ESP_OK;
}

/* Manipulador para o endpoint GET /api/v1/config/mqtt */
static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com as configurações de MQTT
    cJSON *config = cJSON_CreateObject();
    cJSON_AddBoolToObject(config, "enabled", mqtt_config.enabled);
    cJSON_AddStringToObject(config, "host", mqtt_config.host);
    cJSON_AddNumberToObject(config, "port", mqtt_config.port);
    cJSON_AddStringToObject(config, "username", mqtt_config.username);
    cJSON_AddStringToObject(config, "password", mqtt_config.password);
    cJSON_AddStringToObject(config, "topic", mqtt_config.topic);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}

/* Manipulador para o endpoint POST /api/v1/config/mqtt */
static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
{
    char buf[512];  // Buffer para armazenar a requisição
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Atualizando as configurações MQTT
    cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
    if (enabled) mqtt_config.enabled = enabled->valueint;

    cJSON *host = cJSON_GetObjectItem(json, "host");
    if (host) strlcpy(mqtt_config.host, host->valuestring, sizeof(mqtt_config.host));

    cJSON *port = cJSON_GetObjectItem(json, "port");
    if (port) mqtt_config.port = port->valueint;

    cJSON *username = cJSON_GetObjectItem(json, "username");
    if (username) strlcpy(mqtt_config.username, username->valuestring, sizeof(mqtt_config.username));

    cJSON *password = cJSON_GetObjectItem(json, "password");
    if (password) strlcpy(mqtt_config.password, password->valuestring, sizeof(mqtt_config.password));

    cJSON *topic = cJSON_GetObjectItem(json, "topic");
    if (topic) strlcpy(mqtt_config.topic, topic->valuestring, sizeof(mqtt_config.topic));

    cJSON_Delete(json);

    // Responder com uma mensagem de sucesso
    httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");

    return ESP_OK;
}

// Manipulador para o endpoint GET /api/v1/config/auth-methods
static esp_err_t config_auth_methods_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com as configurações de métodos de autenticação
    cJSON *config = cJSON_CreateObject();
    cJSON_AddBoolToObject(config, "RFID", auth_methods.RFID);
    cJSON_AddBoolToObject(config, "App", auth_methods.App);
    cJSON_AddBoolToObject(config, "Password", auth_methods.Password);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}

// Manipulador para o endpoint POST /api/v1/config/auth-methods
static esp_err_t config_auth_methods_post_handler(httpd_req_t *req)
{
    char buf[512];  // Buffer para armazenar a requisição
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Parse JSON recebido
    cJSON *json = cJSON_Parse(buf);
    if (json == NULL) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
        return ESP_FAIL;
    }

    // Atualizando as configurações de autenticação
    cJSON *RFID = cJSON_GetObjectItem(json, "RFID");
    if (RFID) auth_methods.RFID = RFID->valueint;

    cJSON *App = cJSON_GetObjectItem(json, "App");
    if (App) auth_methods.App = App->valueint;

    cJSON *Password = cJSON_GetObjectItem(json, "Password");
    if (Password) auth_methods.Password = Password->valueint;

    cJSON_Delete(json);

    // Responder com uma mensagem de sucesso
    httpd_resp_sendstr(req, "Configurações de Autenticação atualizadas com sucesso");

    return ESP_OK;
}


// Manipulador para o endpoint GET /api/v1/config/users
static esp_err_t config_users_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "application/json");

    // Criar objeto JSON com a lista de usuários
    cJSON *config = cJSON_CreateObject();
    cJSON *users_list = cJSON_CreateArray();

    for (int i = 0; i < num_users; i++) {
        cJSON *user = cJSON_CreateObject();
        cJSON_AddStringToObject(user, "username", users[i].username);
        cJSON_AddItemToArray(users_list, user);
    }

    cJSON_AddItemToObject(config, "users", users_list);

    // Convertendo para string e enviando a resposta
    const char *config_str = cJSON_Print(config);
    httpd_resp_sendstr(req, config_str);

    // Liberando a memória
    free((void *)config_str);
    cJSON_Delete(config);

    return ESP_OK;
}


// Manipulador para o endpoint POST /api/v1/config/users
static esp_err_t config_users_post_handler(httpd_req_t *req)
{
    char buf[128];  // Buffer para armazenar o nome do novo usuário
    int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
    if (len <= 0) {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
        return ESP_FAIL;
    }
    buf[len] = '\0'; // Garantir que a string esteja terminada

    // Adicionar o novo usuário
    if (num_users < 10) {
        strlcpy(users[num_users].username, buf, sizeof(users[num_users].username));
        num_users++;
        httpd_resp_sendstr(req, "Usuário adicionado com sucesso");
    } else {
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Máximo de usuários atingido");
    }

    return ESP_OK;
}


// Manipulador para o endpoint DELETE /api/v1/config/users/{username}
static esp_err_t config_users_delete_handler(httpd_req_t *req)
{
    char username[128];  // Nome do usuário a ser removido
    if (httpd_req_get_url_query_str(req, username, sizeof(username)) == ESP_OK) {
        // Verificar e remover o usuário
        for (int i = 0; i < num_users; i++) {
            if (strcmp(users[i].username, username) == 0) {
                // Remover o usuário
                for (int j = i; j < num_users - 1; j++) {
                    users[j] = users[j + 1];
                }
                num_users--;
                httpd_resp_sendstr(req, "Usuário removido com sucesso");
                return ESP_OK;
            }
        }
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Usuário não encontrado");
    }
    return ESP_FAIL;
}



esp_err_t rest_init(const char *base_path)
{
    REST_CHECK(base_path, "wrong base path", err);
    rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
    REST_CHECK(rest_context, "No memory for rest context", err_start);
    strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));

    httpd_handle_t server = NULL;
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
    config.max_uri_handlers = 30;  // Ajuste conforme necessário
    config.uri_match_fn = httpd_uri_match_wildcard;

    ESP_LOGI(REST_TAG, "Starting HTTP Server");
    REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);

    // Registrar manipuladores de URI para as configurações
    httpd_uri_t config_load_balancing_get_uri = {
        .uri = "/api/v1/config/load-balancing",
        .method = HTTP_GET,
        .handler = config_load_balancing_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_load_balancing_get_uri);

    // URI handler for fetching OCPP status
    httpd_uri_t ocpp_status_get_uri = {
        .uri = "/api/v1/ocpp",
        .method = HTTP_GET,
        .handler = ocpp_status_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &ocpp_status_get_uri);

    // URI handler for fetching OCPP config
    httpd_uri_t config_ocpp_get_uri = {
        .uri = "/api/v1/config/ocpp",
        .method = HTTP_GET,
        .handler = config_ocpp_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_ocpp_get_uri);

    // URI handler for posting OCPP config
    httpd_uri_t config_ocpp_post_uri = {
        .uri = "/api/v1/config/ocpp",
        .method = HTTP_POST,
        .handler = config_ocpp_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_ocpp_post_uri);

    // Manipulador para o endpoint POST /api/v1/config/settings
    httpd_uri_t config_settings_post_uri = {
        .uri = "/api/v1/config/settings",
        .method = HTTP_POST,
        .handler = config_settings_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_settings_post_uri);

    // Manipulador para o endpoint GET /api/v1/config/settings
    httpd_uri_t config_settings_get_uri = {
        .uri = "/api/v1/config/settings",
        .method = HTTP_GET,
        .handler = config_settings_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_settings_get_uri);

    // Manipulador para o endpoint GET /api/v1/dashboard
    httpd_uri_t dashboard_get_uri = {
        .uri = "/api/v1/dashboard",
        .method = HTTP_GET,
        .handler = dashboard_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &dashboard_get_uri);

    // Register URI Handlers for electrical configuration
    httpd_uri_t electrical_config_get_uri = {
        .uri = "/api/v1/config/electrical",
        .method = HTTP_GET,
        .handler = electrical_config_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &electrical_config_get_uri);

    httpd_uri_t electrical_config_post_uri = {
        .uri = "/api/v1/config/electrical",
        .method = HTTP_POST,
        .handler = electrical_config_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &electrical_config_post_uri);

    // URI handler for getting Wi-Fi config
    httpd_uri_t config_wifi_get_uri = {
        .uri = "/api/v1/config/wifi",
        .method = HTTP_GET,
        .handler = config_wifi_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_wifi_get_uri);

    // URI handler for posting Wi-Fi config
    httpd_uri_t config_wifi_post_uri = {
        .uri = "/api/v1/config/wifi",
        .method = HTTP_POST,
        .handler = config_wifi_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_wifi_post_uri);

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

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

    // Registrar manipuladores para as configurações de autenticação
    httpd_uri_t config_auth_methods_get_uri = {
        .uri = "/api/v1/config/auth-methods",
        .method = HTTP_GET,
        .handler = config_auth_methods_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_auth_methods_get_uri);

    httpd_uri_t config_auth_methods_post_uri = {
        .uri = "/api/v1/config/auth-methods",
        .method = HTTP_POST,
        .handler = config_auth_methods_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_auth_methods_post_uri);

    // Registrar manipuladores para as configurações de usuários
    httpd_uri_t config_users_get_uri = {
        .uri = "/api/v1/config/users",
        .method = HTTP_GET,
        .handler = config_users_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_users_get_uri);

    httpd_uri_t config_users_post_uri = {
        .uri = "/api/v1/config/users",
        .method = HTTP_POST,
        .handler = config_users_post_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_users_post_uri);

    httpd_uri_t config_users_delete_uri = {
        .uri = "/api/v1/config/users",
        .method = HTTP_DELETE,
        .handler = config_users_delete_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &config_users_delete_uri);

    // URI handler for getting web server files
    httpd_uri_t common_get_uri = {
        .uri = "/*",
        .method = HTTP_GET,
        .handler = rest_common_get_handler,
        .user_ctx = rest_context
    };
    httpd_register_uri_handler(server, &common_get_uri);
    
    return ESP_OK;

err_start:
    free(rest_context);
err:
    return ESP_FAIL;
}
