#include <Tactility/settings/Time.h>

#include <Tactility/settings/SystemSettings.h>

#include <tactility/paths.h>
#include <tactility/preferences.h>
#include <tactility/system_event.h>

#ifdef ESP_PLATFORM
#include <ctime>
#endif

namespace tt::settings {

constexpr auto* TIME_SETTINGS_NAMESPACE = "time";

constexpr auto* TIMEZONE_PREFERENCES_KEY_NAME = "tz_name";
constexpr auto* TIMEZONE_PREFERENCES_KEY_CODE = "tz_code";
constexpr auto* TIMEZONE_PREFERENCES_KEY_TIME24 = "tz_time24";

namespace {

// Same "time" namespace/file that Ntp.cpp's storeTimeInNvs()/setTimeFromNvs() use for
// "syncTime" - matches the shared NVS namespace this used to be.
bool getPreferencesPath(std::string& outPath) {
    char root[128];
    if (paths_get_user_data_path(root, sizeof(root)) != ERROR_NONE) {
        return false;
    }
    outPath = std::string(root) + "/" + TIME_SETTINGS_NAMESPACE + ".properties";
    return true;
}

} // namespace

void initTimeZone() {
#ifdef ESP_PLATFORM
    auto code= getTimeZoneCode();
    if (!code.empty()) {
        setenv("TZ", code.c_str(), 1);
        tzset();
    }
#endif
}

void setTimeZone(const std::string& name, const std::string& code) {
    std::string path;
    if (getPreferencesPath(path)) {
        Preferences* preferences = preferences_open(path.c_str());
        if (preferences != nullptr) {
            preferences_put_string(preferences, TIMEZONE_PREFERENCES_KEY_NAME, name.c_str());
            preferences_put_string(preferences, TIMEZONE_PREFERENCES_KEY_CODE, code.c_str());
            preferences_close(preferences);
        }
    }

#ifdef ESP_PLATFORM
    setenv("TZ", code.c_str(), 1);
    tzset();
#endif

    system_event_emit(KERNEL_EVENT_TIME_CHANGED, nullptr, 0);
}

std::string getTimeZoneName() {
    std::string path;
    if (getPreferencesPath(path)) {
        Preferences* preferences = preferences_open(path.c_str());
        if (preferences != nullptr) {
            char buffer[64];
            error_t error = preferences_opt_string(preferences, TIMEZONE_PREFERENCES_KEY_NAME, buffer, sizeof(buffer));
            preferences_close(preferences);
            if (error == ERROR_NONE) {
                return buffer;
            }
        }
    }
    return "Europe/Amsterdam";
}

bool hasTimeZone() {
    std::string path;
    if (!getPreferencesPath(path)) {
        return false;
    }
    Preferences* preferences = preferences_open(path.c_str());
    if (preferences == nullptr) {
        return false;
    }
    bool has = preferences_has_string(preferences, TIMEZONE_PREFERENCES_KEY_NAME);
    preferences_close(preferences);
    return has;
}

std::string getTimeZoneCode() {
    std::string path;
    if (getPreferencesPath(path)) {
        Preferences* preferences = preferences_open(path.c_str());
        if (preferences != nullptr) {
            char buffer[64];
            error_t error = preferences_opt_string(preferences, TIMEZONE_PREFERENCES_KEY_CODE, buffer, sizeof(buffer));
            preferences_close(preferences);
            if (error == ERROR_NONE) {
                return buffer;
            }
        }
    }
    return "CET-1CEST,M3.5.0,M10.5.0/3";  // Default: Europe/Amsterdam
}

bool isTimeFormat24Hour() {
    SystemSettings properties;
    if (!loadSystemSettings(properties)) {
        return true;
    } else {
        return properties.timeFormat24h;
    }
}

void setTimeFormat24Hour(bool show24Hour) {
    SystemSettings properties;
    if (!loadSystemSettings(properties)) {
        return;
    }

    properties.timeFormat24h = show24Hour;
    saveSystemSettings(properties);
}

}
