#include "wifi_store_nvs.h"

#include <cstring>

#include "esp_log.h"
#include "nvs.h"
namespace {
constexpr const char *TAG = "WIFI";
constexpr const char *kNamespace = "wifi_store";
constexpr const char *kKey = "profiles";
}  // namespace

namespace wearable {

WiFiStoreLoadState NvsWiFiStorage::load(WiFiStoreImage &out) {
    nvs_handle_t handle = 0;
    const auto opened = nvs_open(kNamespace, NVS_READONLY, &handle);
    // A missing namespace means nothing was ever written: Missing, not corrupt.
    if (opened == ESP_ERR_NVS_NOT_FOUND) return WiFiStoreLoadState::Missing;
    if (opened != ESP_OK) {
        ESP_LOGW(TAG, "[WIFI] store open failed: %s", esp_err_to_name(opened));
        return WiFiStoreLoadState::IoError;
    }
    size_t size = out.bytes.size();
    const auto result = nvs_get_blob(handle, kKey, out.bytes.data(), &size);
    nvs_close(handle);
    // The key being absent is Missing; any other failure means data we could not
    // read, which must not look like a first boot.
    if (result == ESP_ERR_NVS_NOT_FOUND) return WiFiStoreLoadState::Missing;
    if (result != ESP_OK) {
        ESP_LOGW(TAG, "[WIFI] store read failed: %s", esp_err_to_name(result));
        return WiFiStoreLoadState::IoError;
    }
    out.size = size;
    // Bytes were returned; the profile-store decoder decides whether they are
    // valid. Present-but-invalid becomes Corrupt in the store.
    return WiFiStoreLoadState::Present;
}

bool NvsWiFiStorage::save(const WiFiStoreImage &image) {
    nvs_handle_t handle = 0;
    auto result = nvs_open(kNamespace, NVS_READWRITE, &handle);
    if (result != ESP_OK) {
        ESP_LOGW(TAG, "[WIFI] store write open failed: %s", esp_err_to_name(result));
        return false;
    }
    result = nvs_set_blob(handle, kKey, image.bytes.data(), image.size);
    if (result == ESP_OK) result = nvs_commit(handle);
    nvs_close(handle);
    if (result != ESP_OK) {
        ESP_LOGW(TAG, "[WIFI] store commit failed: %s", esp_err_to_name(result));
        return false;
    }
    return true;
}

bool NvsWiFiStorage::erase() {
    nvs_handle_t handle = 0;
    auto result = nvs_open(kNamespace, NVS_READWRITE, &handle);
    if (result != ESP_OK) return false;
    result = nvs_erase_key(handle, kKey);
    if (result == ESP_OK) result = nvs_commit(handle);
    nvs_close(handle);
    return result == ESP_OK || result == ESP_ERR_NVS_NOT_FOUND;
}

}  // namespace wearable