// components/rest_api/src/scheduler_settings_api.c
#include "scheduler_settings_api.h"
#include "scheduler.h"
#include "scheduler_types.h"

#include "esp_log.h"
#include "esp_http_server.h"
#include "cJSON.h"

#include <stdio.h>
#include <string.h>

static const char *TAG = "scheduler_api";

/* =========================
 * Helpers HH:MM <-> minutos
 *  - aceita 24:00 => 1440
 * ========================= */

static bool parse_hhmm(const char *s, uint16_t *out_min)
{
    if (!s || !out_min)
        return false;

    int h = 0, m = 0;
    if (sscanf(s, "%d:%d", &h, &m) != 2)
        return false;

    if (h == 24 && m == 0)
    {
        *out_min = 1440;
        return true;
    }

    if (h < 0 || h > 23 || m < 0 || m > 59)
        return false;

    *out_min = (uint16_t)(h * 60 + m);
    return true;
}

static void format_hhmm(uint16_t minutes, char *buf, size_t buf_sz)
{
    if (!buf || buf_sz < 6)
        return;

    if (minutes == 1440)
    {
        snprintf(buf, buf_sz, "24:00");
        return;
    }

    minutes %= 1440;
    snprintf(buf, buf_sz, "%02d:%02d", minutes / 60, minutes % 60);
}

static cJSON *window_to_json(const sched_window_t *w)
{
    cJSON *o = cJSON_CreateObject();
    if (!o)
        return NULL;

    char b[8];
    format_hhmm(w->start_min, b, sizeof(b));
    cJSON_AddStringToObject(o, "startTime", b);

    format_hhmm(w->end_min, b, sizeof(b));
    cJSON_AddStringToObject(o, "endTime", b);

    cJSON_AddNumberToObject(o, "currentA", (int)w->current_a);

    return o;
}

static bool parse_windows_array(cJSON *arr, sched_config_t *cfg)
{
    if (!arr || !cfg || !cJSON_IsArray(arr))
        return false;

    int n = cJSON_GetArraySize(arr);
    if (n <= 0)
        return false;
    if (n > SCHED_MAX_WINDOWS)
        n = SCHED_MAX_WINDOWS;

    cfg->window_count = 0;

    for (int i = 0; i < n; i++)
    {
        cJSON *it = cJSON_GetArrayItem(arr, i);
        if (!cJSON_IsObject(it))
            return false;

        cJSON *js = cJSON_GetObjectItem(it, "startTime");
        cJSON *je = cJSON_GetObjectItem(it, "endTime");
        cJSON *ja = cJSON_GetObjectItem(it, "currentA");

        if (!cJSON_IsString(js) || !cJSON_IsString(je) || !cJSON_IsNumber(ja))
            return false;

        uint16_t sm = 0, em = 0;
        if (!parse_hhmm(js->valuestring, &sm))
            return false;
        if (!parse_hhmm(je->valuestring, &em))
            return false;

        int a = ja->valueint;
        if (a < 6 || a > 80)
            return false;

        cfg->windows[cfg->window_count].start_min = sm;
        cfg->windows[cfg->window_count].end_min = em;
        cfg->windows[cfg->window_count].current_a = (uint16_t)a;
        cfg->window_count++;
    }

    return true;
}

/* =========================
 * GET /api/v1/config/scheduler
 * ========================= */
static esp_err_t scheduler_config_get_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "GET /api/v1/config/scheduler");
    httpd_resp_set_type(req, "application/json");

    sched_config_t cfg = scheduler_get_config();

    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "cJSON alloc failed");
        return ESP_FAIL;
    }

    cJSON_AddBoolToObject(root, "enabled", cfg.enabled);
    cJSON_AddStringToObject(root, "mode", sched_mode_to_str(cfg.mode));

    cJSON *arr = cJSON_CreateArray();
    for (int i = 0; i < cfg.window_count && i < SCHED_MAX_WINDOWS; i++)
    {
        cJSON *w = window_to_json(&cfg.windows[i]);
        if (w)
            cJSON_AddItemToArray(arr, w);
    }
    cJSON_AddItemToObject(root, "windows", arr);

    cJSON_AddBoolToObject(root, "allowedNow", scheduler_is_allowed_now());
    cJSON_AddNumberToObject(root, "currentLimitNowA", (int)scheduler_get_current_limit_now_a());

    char *json_str = cJSON_PrintUnformatted(root);
    if (!json_str)
    {
        cJSON_Delete(root);
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "cJSON print failed");
        return ESP_FAIL;
    }

    httpd_resp_sendstr(req, json_str);
    free(json_str);
    cJSON_Delete(root);
    return ESP_OK;
}

/* =========================
 * POST /api/v1/config/scheduler
 * ========================= */
static esp_err_t scheduler_config_post_handler(httpd_req_t *req)
{
    ESP_LOGD(TAG, "POST /api/v1/config/scheduler");

    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, "Empty body");
        return ESP_FAIL;
    }
    buf[len] = '\0';

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

    // começa do estado atual
    sched_config_t cfg = scheduler_get_config();

    // enabled
    cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
    if (cJSON_IsBool(j_enabled))
        cfg.enabled = cJSON_IsTrue(j_enabled);

    if (!cfg.enabled)
    {
        cfg.mode = SCHED_MODE_DISABLED;
        cfg.window_count = 0;
        scheduler_set_config(&cfg);
        cJSON_Delete(json);
        httpd_resp_sendstr(req, "OK");
        return ESP_OK;
    }

    // enabled=true => exige windows[]
    cJSON *j_windows = cJSON_GetObjectItem(json, "windows");
    if (!j_windows || !cJSON_IsArray(j_windows))
    {
        cJSON_Delete(json);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Missing windows[]");
        return ESP_FAIL;
    }

    cfg.mode = SCHED_MODE_DAILY_MULTI;

    if (!parse_windows_array(j_windows, &cfg))
    {
        cJSON_Delete(json);
        httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
                            "Invalid windows (use: [{startTime,endTime,currentA}], currentA 6-80)");
        return ESP_FAIL;
    }

    scheduler_set_config(&cfg);
    cJSON_Delete(json);

    httpd_resp_sendstr(req, "OK");
    return ESP_OK;
}

void register_scheduler_settings_handlers(httpd_handle_t server, void *ctx)
{
    httpd_uri_t get_uri = {
        .uri = "/api/v1/config/scheduler",
        .method = HTTP_GET,
        .handler = scheduler_config_get_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &get_uri);

    httpd_uri_t post_uri = {
        .uri = "/api/v1/config/scheduler",
        .method = HTTP_POST,
        .handler = scheduler_config_post_handler,
        .user_ctx = ctx};
    httpd_register_uri_handler(server, &post_uri);

    ESP_LOGD(TAG, "Scheduler REST handlers registered");
}