#include "SettingsManager.hpp"
#include <ArduinoJson.h>
#include <Preferences.h>
#include <vector>

namespace cyd {

SettingsManager::SettingsManager() = default;

SettingsManager::~SettingsManager() {
    end();
}

bool SettingsManager::begin() {
    if (begun_) {
        return true;
    }
    begun_ = prefs_.begin(kNamespace, false);
    if (begun_) {
        load();
    }
    return begun_;
}

void SettingsManager::end() {
    if (begun_) {
        prefs_.end();
        begun_ = false;
    }
}

void SettingsManager::resetToDefaults() {
    Settings defaults;
    settings_ = defaults;
}

bool SettingsManager::load() {
    if (!begun_) {
        return false;
    }

    size_t len = prefs_.getBytesLength(kSettingsKey);
    if (len == 0) {
        Serial.println("Settings: no stored settings found, using defaults");
        resetToDefaults();
        return true;
    }

    std::vector<char> buffer;
    buffer.resize(len);
    size_t read = prefs_.getBytes(kSettingsKey, buffer.data(), len);
    if (read != len) {
        Serial.println("Settings: read size mismatch, resetting");
        resetToDefaults();
        return false;
    }

    JsonDocument doc;
    DeserializationError err = deserializeJson(doc, buffer.data(), len);
    if (err != DeserializationError::Ok) {
        Serial.printf("Settings: JSON parse error: %s\n", err.c_str());
        resetToDefaults();
        return false;
    }

    uint16_t storedVersion = doc["version"] | 0;
    if (storedVersion != kCurrentVersion) {
        Serial.printf("Settings: migrating from version %d to %d\n", storedVersion, kCurrentVersion);
        migrateFrom(storedVersion);
        return true;
    }

    settings_.wifiSsid = doc["wifiSsid"] | "";
    settings_.wifiPass = doc["wifiPass"] | "";
    settings_.thermoproMac = doc["thermoproMac"] | "";
    settings_.apiEndpoint = doc["apiEndpoint"] | "";
    settings_.apiToken = doc["apiToken"] | "";
    settings_.pollIntervalSec = doc["pollIntervalSec"] | 15;
    String unit = doc["unit"] | "F";
    settings_.unit = unit.length() > 0 ? unit.charAt(0) : 'F';
    settings_.deviceId = doc["deviceId"] | "cyd-smoker";

    JsonArray names = doc["probeNames"].as<JsonArray>();
    for (size_t i = 0; i < settings_.probeNames.size(); ++i) {
        if (i < names.size()) {
            settings_.probeNames[i] = names[i].as<String>();
        } else {
            settings_.probeNames[i] = "Probe " + String(i + 1);
        }
    }

    Serial.println("Settings: loaded from NVS");
    return true;
}

bool SettingsManager::save() {
    if (!begun_) {
        return false;
    }

    JsonDocument doc;
    doc["version"] = kCurrentVersion;
    doc["wifiSsid"] = settings_.wifiSsid;
    doc["wifiPass"] = settings_.wifiPass;
    doc["thermoproMac"] = settings_.thermoproMac;
    doc["apiEndpoint"] = settings_.apiEndpoint;
    doc["apiToken"] = settings_.apiToken;
    doc["pollIntervalSec"] = settings_.pollIntervalSec;
    doc["unit"] = String(settings_.unit);
    doc["deviceId"] = settings_.deviceId;

    JsonArray names = doc["probeNames"].to<JsonArray>();
    for (const auto& name : settings_.probeNames) {
        names.add(name);
    }

    size_t size = measureJson(doc);
    std::vector<char> buffer;
    buffer.resize(size);
    serializeJson(doc, buffer.data(), size);

    prefs_.putBytes(kSettingsKey, buffer.data(), size);
    Serial.println("Settings: saved to NVS");
    return true;
}

String SettingsManager::getProbeName(size_t index) const {
    if (index < settings_.probeNames.size()) {
        return settings_.probeNames[index];
    }
    return "Probe " + String(index + 1);
}

void SettingsManager::setProbeName(size_t index, const String& value) {
    if (index < settings_.probeNames.size()) {
        settings_.probeNames[index] = value.length() ? value : ("Probe " + String(index + 1));
    }
}

bool SettingsManager::hasThermoproMac() const {
    return isValidMac(settings_.thermoproMac);
}

bool SettingsManager::hasWifiCredentials() const {
    return settings_.wifiSsid.length() > 0;
}

bool SettingsManager::isValidMac(const String& mac) {
    if (mac.length() != 17) {
        return false;
    }
    for (int i = 0; i < mac.length(); ++i) {
        char c = mac.charAt(i);
        if ((i + 1) % 3 == 0) {
            if (c != ':') {
                return false;
            }
        } else {
            if (!isxdigit(c)) {
                return false;
            }
        }
    }
    return true;
}

void SettingsManager::migrateFrom(uint16_t oldVersion) {
    // For now, any version mismatch simply resets to defaults. As the schema
    // evolves we can add per-version migrations here.
    (void)oldVersion;
    resetToDefaults();
    save();
}

} // namespace cyd
