/// © MiroZ 2024

#include <nvs_flash.h>
#include <nvs.h>
#include <esp_partition.h>
#include <esp_log.h>

#include "Settings.h"
#include "errors.h"
#include <string.h>
#include <esp_netif.h>

static const char *TAG = "Settings";

Settings & Settings::getInstance()
{
	static Settings instance;
	return instance;
}

Settings::Settings()
{
	ESP_LOGW(TAG, "Starting settings...");
	m_data = (struct NV_DATA *)malloc(sizeof(struct NV_DATA));
	loadData();
	if(m_data->version != SETTINGS_VERSION)
		setDefaults();
}

uint32_t Settings::loadData()
{
    esp_err_t err = nvs_flash_init();

    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) 
	{
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

	nvs_handle handle;

	ESP_ERROR_CHECK(nvs_open(m_namespace, NVS_READWRITE, &handle));

	size_t key_size = 0;
	err = nvs_get_blob(handle, m_dataname, NULL, &key_size);

	if(err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) 
	{
		ESP_LOGE(TAG, "Unable to read NVS key: (%d) %s", err, esp_err_to_name(err));
		abort();
	}

	if(key_size != sizeof(struct NV_DATA))
	{
		ESP_LOGI(TAG, "Stored len (%d) doesn't match expected (%d), using default settings", 
			key_size, sizeof(struct NV_DATA));
		setDefaults();
		ESP_ERROR_CHECK(nvs_set_blob(handle, m_dataname, m_data, sizeof(m_data)));
	}
	else
	{
		ESP_LOGI(TAG, "reading blob");
		ESP_ERROR_CHECK(nvs_get_blob(handle, m_dataname, m_data, &key_size));
	}

	nvs_close(handle);

	return WH_OK;
}

uint32_t Settings::saveData()
{
	nvs_handle handle;
	ESP_ERROR_CHECK(nvs_open(m_namespace, NVS_READWRITE, &handle));
	ESP_ERROR_CHECK(nvs_set_blob(handle, m_dataname, m_data, sizeof(struct NV_DATA)));
	nvs_close(handle);
	return WH_OK;
}

void Settings::setDefaults()
{
	ESP_LOGI(TAG, "Setting defaults");
	memset(m_data, 0, sizeof(struct NV_DATA));
	m_data->version = SETTINGS_VERSION;

	m_data->led.brightness = 25; // 25 %
	m_data->wifi.subnet_mask = PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0));
	m_data->wifi.dns_primary = PP_HTONL(LWIP_MAKEU32(8, 8, 8, 8));
	m_data->wifi.dns_secondary = PP_HTONL(LWIP_MAKEU32(8, 8, 4, 4));

	m_data->device.id = 101;
	m_data->device.group_id = 5101;
}