#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "cJSON.h"
#include "esp_spiffs.h"
#include "RemindMe.h"
#include <time.h>

static const char *TAG = "JSON_READER";

static void copy_json_string(cJSON *item,
                             const char *key,
                             char *dst,
                             size_t dst_size)
{
    cJSON *v = cJSON_GetObjectItem(item, key);
    if (cJSON_IsString(v) && v->valuestring)
    {
        strncpy(dst, v->valuestring, dst_size - 1);
        dst[dst_size - 1] = '\0';
    }
}

static RemindMeEvent *get_events_from_file(const char *filepath, int *count)
{
    *count = 0;

    FILE *f = fopen(filepath, "r");
    if (!f)
    {
        ESP_LOGE(TAG, "Impossible d'ouvrir le fichier");
        return NULL;
    }

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fseek(f, 0, SEEK_SET);

    char *json_string = malloc(size + 1);
    if (!json_string)
    {
        fclose(f);
        return NULL;
    }

    fread(json_string, 1, size, f);
    fclose(f);
    json_string[size] = 0;

    cJSON *json = cJSON_Parse(json_string);
    free(json_string);

    if (!cJSON_IsArray(json))
    {
        cJSON_Delete(json);
        return NULL;
    }

    int n = cJSON_GetArraySize(json);
    if (n == 0)
    {
        cJSON_Delete(json);
        return NULL;
    }

    RemindMeEvent *events = calloc(n, sizeof(RemindMeEvent));
    if (!events)
    {
        cJSON_Delete(json);
        return NULL;
    }

    for (int i = 0; i < n; i++)
    {
        cJSON *item = cJSON_GetArrayItem(json, i);
        copy_json_string(item, "evenement", events[i].evenement, sizeof(events[i].evenement));
        copy_json_string(item, "affichage", events[i].affichage, sizeof(events[i].affichage));
        copy_json_string(item, "date", events[i].date, sizeof(events[i].date));
        copy_json_string(item, "type", events[i].type, sizeof(events[i].type));
    }

    cJSON_Delete(json);
    *count = n;
    return events;
}

static void read_json_file(const char *filepath, cJSON **root)
{

    FILE *f = fopen(filepath, "r");
    if (!f)
    {
        ESP_LOGE(TAG, "Impossible d'ouvrir le fichier");
        return;
    }

    fseek(f, 0, SEEK_END);
    long size = ftell(f);
    fseek(f, 0, SEEK_SET);

    char *json_string = malloc(size + 1);
    if (!json_string)
    {
        fclose(f);
        return;
    }

    fread(json_string, 1, size, f);
    fclose(f);
    json_string[size] = 0;

    *root = cJSON_Parse(json_string);
    free(json_string);
}

/**
 * Parse une date au format "YYYY-MM-DD" et retourne le timestamp
 */
time_t parse_date(const char *date_str)
{
    struct tm tm = {0};

    // Parser la date (format: YYYY-MM-DD)
    sscanf(date_str, "%d-%d-%d",
           &tm.tm_year, &tm.tm_mon, &tm.tm_mday);

    tm.tm_year -= 1900; // Années depuis 1900
    tm.tm_mon -= 1;     // Mois de 0 à 11
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;

    return mktime(&tm);
}

/**
 * Calcule le nombre de jours entre maintenant et la date donnée
 * Retourne un nombre négatif si la date est passée
 */
int days_until(const char *date_str)
{
    // Obtenir l'heure actuelle
    time_t now;
    time(&now);

    // Parser la date cible
    time_t target = parse_date(date_str);

    // Calculer la différence en secondes
    double diff_seconds = difftime(target, now);

    // Convertir en jours (arrondi)
    int days = (int)(diff_seconds / (60 * 60 * 24));

    return days;
}

RemindMeEvent *get_events(int *count)
{
    RemindMeEvent *evts =  get_events_from_file(
        "/spiffs/events.json",
        count);
    for (size_t i = 0; i < *count; i++)
    {
        sprintf(evts[i].affichage, evts[i].affichage, days_until(evts[i].date));
    }
    return evts;
    
}
esp_err_t events_save_atomic(char *eventsJson)
{
    FILE *f = fopen("/spiffs/events.tmp", "w");
    if (!f)
        goto error;

    fwrite(eventsJson, 1, strlen(eventsJson), f);
    fclose(f);

    rename("/spiffs/events.json", "/spiffs/events.bak");
    rename("/spiffs/events.tmp", "/spiffs/events.json");
    //unlink("/spiffs/events.bak");

    free(eventsJson);
    return ESP_OK;

error:
    free(eventsJson);
    return ESP_FAIL;
}

void add_event(RemindMeEvent e){
    int count=0;
    cJSON *root = cJSON_CreateObject();
    read_json_file("/spiffs/events.json", &root);
    printf("%s","####################### AVANT\n");
    //printf("%s\n",cJSON_Print(root));
    if (!cJSON_IsArray(root))
    {
        ESP_LOGE(TAG, "'root' n'est pas un tableau");
        return;
    }else{
        cJSON *new_event = cJSON_CreateObject();
        if (!new_event)
            return;

        cJSON_AddStringToObject(new_event, "evenement", e.evenement);
        cJSON_AddStringToObject(new_event, "affichage", e.affichage);
        cJSON_AddStringToObject(new_event, "date", e.date);
        cJSON_AddStringToObject(new_event, "type", e.type);
        cJSON_AddItemToArray(root, new_event);
    }
    printf("%s", "####################### APRES\n");
    //printf("%s\n", cJSON_Print(root));
    char *eventsJson=cJSON_Print(root);
    events_save_atomic(eventsJson);
}
