#include "system_api.h"

#include "cJSON.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_system.h"
#include "esp_timer.h"

#include "auth.h"
#include "evse_api.h"
#include "evse_config.h"
#include "evse_limits.h"
#include "mqtt.h"
#include "network.h"

#include <string.h>

static const char *TAG = "system_api";

#ifndef FW_VERSION
#define FW_VERSION "1.0"
#endif

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

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Falha ao criar resposta JSON");
        return ESP_FAIL;
    }

    const bool wifi_enabled = wifi_get_enabled();
    const int64_t uptime_us = esp_timer_get_time();

    cJSON_AddStringToObject(root, "apiVersion", "1.0");
    cJSON_AddStringToObject(root, "device", "PLX EV Charger");
    cJSON_AddStringToObject(root, "fwVersion", FW_VERSION);
    cJSON_AddStringToObject(root, "serial", "");
    cJSON_AddStringToObject(root, "mode", wifi_enabled ? "sta" : "ap");
    cJSON_AddBoolToObject(root, "online", true);
    cJSON_AddStringToObject(root, "localConfigMode", wifi_enabled ? "sta" : "ap_default");
    cJSON_AddStringToObject(root, "authScheme", "basic");
    cJSON_AddNumberToObject(root, "uptimeS", (double)(uptime_us / 1000000));
    cJSON_AddNumberToObject(root, "freeHeap", (double)esp_get_free_heap_size());
    cJSON_AddNumberToObject(root, "hardwareMaxA", evse_get_max_charging_current());
    cJSON_AddNumberToObject(root, "currentLimit", evse_get_charging_current());
    cJSON_AddBoolToObject(root, "wifiEnabled", wifi_enabled);
    cJSON_AddStringToObject(root, "authMode", auth_mode_to_str(auth_get_mode()));

    esp_netif_t *netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
    if (netif)
    {
        esp_netif_ip_info_t ip_info;
        if (esp_netif_get_ip_info(netif, &ip_info) == ESP_OK)
        {
            char ip_str[16] = {0};
            snprintf(ip_str, sizeof(ip_str), IPSTR, IP2STR(&ip_info.ip));
            cJSON_AddStringToObject(root, "ip", ip_str);
        }
    }

    cJSON *capabilities = cJSON_CreateObject();
    if (capabilities)
    {
        cJSON_AddBoolToObject(capabilities, "wifiScan", false);
        cJSON_AddBoolToObject(capabilities, "logs", false);
        cJSON_AddBoolToObject(capabilities, "systemReboot", false);
        cJSON_AddBoolToObject(capabilities, "systemFactoryReset", false);
        cJSON_AddBoolToObject(capabilities, "systemApExit", false);
        cJSON_AddBoolToObject(capabilities, "users", true);
        cJSON_AddBoolToObject(capabilities, "tags", true);
        cJSON_AddBoolToObject(capabilities, "security", true);
        cJSON_AddBoolToObject(capabilities, "scheduler", true);
        cJSON_AddBoolToObject(capabilities, "loadBalancing", true);
        cJSON_AddBoolToObject(capabilities, "ocpp", true);
        cJSON_AddBoolToObject(capabilities, "link", true);
        cJSON_AddBoolToObject(capabilities, "metersConfig", true);
        cJSON_AddItemToObject(root, "capabilities", capabilities);
    }

    char *json_str = cJSON_PrintUnformatted(root);
    if (!json_str)
    {
        cJSON_Delete(root);
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Falha ao serializar JSON");
        return ESP_FAIL;
    }

    ESP_LOGD(TAG, "GET /api/v1/system/info -> %s", json_str);
    httpd_resp_sendstr(req, json_str);

    free(json_str);
    cJSON_Delete(root);
    return ESP_OK;
}

void register_system_handlers(httpd_handle_t server, void *ctx)
{
    httpd_register_uri_handler(server, &(httpd_uri_t){
                                          .uri = "/api/v1/system/info",
                                          .method = HTTP_GET,
                                          .handler = system_info_get_handler,
                                          .user_ctx = ctx,
                                      });
}
