#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "eeprom_virtual.h"

static const char *TAG = "EEPROM_VIRTUAL";
static nvs_handle_t s_nvs;


/**
 * @brief Inicializa o “EEPROM virtual” (usa partição NVS)
 */
esp_err_t eeprom_virtual_init(void)
{
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "❌ Falha ao inicializar NVS (%s)", esp_err_to_name(ret));
        return ret;
    }

    ret = nvs_open("storage", NVS_READWRITE, &s_nvs);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "❌ Erro ao abrir namespace NVS: %s", esp_err_to_name(ret));
        return ret;
    }

    ESP_LOGI(TAG, "✅ EEPROM virtual pronta (namespace 'storage')");
    return ESP_OK;
}

/**
 * @brief Guarda dados binários na NVS
 */
esp_err_t eeprom_virtual_write_bin(const char *key, const void *data, size_t len)
{
    if (!key || !data || len == 0) return ESP_ERR_INVALID_ARG;
    esp_err_t ret = nvs_set_blob(s_nvs, key, data, len);
    if (ret == ESP_OK) {
        ret = nvs_commit(s_nvs);
        ESP_LOGI(TAG, "💾 Gravado '%s' (%d bytes)", key, (int)len);
    } else {
        ESP_LOGE(TAG, "❌ Falha ao gravar '%s' (%s)", key, esp_err_to_name(ret));
    }
    return ret;
}

/**
 * @brief Lê dados binários da NVS
 */
esp_err_t eeprom_virtual_read_bin(const char *key, void *buf, size_t *len)
{
    if (!key || !buf || !len) return ESP_ERR_INVALID_ARG;
    esp_err_t ret = nvs_get_blob(s_nvs, key, buf, len);
    if (ret == ESP_OK)
        ESP_LOGI(TAG, "📖 Lido '%s' (%d bytes)", key, (int)*len);
    else if (ret == ESP_ERR_NVS_NOT_FOUND)
        ESP_LOGW(TAG, "⚠️ Chave '%s' não encontrada", key);
    else
        ESP_LOGE(TAG, "❌ Erro ao ler '%s' (%s)", key, esp_err_to_name(ret));
    return ret;
}

/**
 * @brief Apaga uma chave da EEPROM virtual
 */
esp_err_t eeprom_virtual_erase_key(const char *key)
{
    esp_err_t ret = nvs_erase_key(s_nvs, key);
    if (ret == ESP_OK) nvs_commit(s_nvs);
    ESP_LOGI(TAG, "🧹 Apagado '%s' (%s)", key, esp_err_to_name(ret));
    return ret;
}

/**
 * @brief Apaga todo o conteúdo da EEPROM virtual
 */
esp_err_t eeprom_virtual_erase_all(void)
{
    esp_err_t ret = nvs_erase_all(s_nvs);
    if (ret == ESP_OK) nvs_commit(s_nvs);
    ESP_LOGW(TAG, "🧨 EEPROM virtual limpa (%s)", esp_err_to_name(ret));
    return ret;
}
