#include "zoost/zt.utils.h"

#include "zoost/zt.common.h"
#include "zoost/zt.define.hpp"

std::string zoostUtils::gConfigDir = "";

zoostPath::zoostPath()
{
    // 默认使用 Utils 中的静态变量
    SetConfigDir(zoostUtils::gConfigDir);
}

bool zoostPath::CreateConfigDir(const std::string& appName)
{
    try {
        std::string configDir;
        if (!GetConfigDir(appName, configDir)) {
            return false;
        }
        return zoostFs::create_directories(configDir);
    } catch (const std::exception& e) {
        errMsg_ = zoostCommon::ToU8Copy(e.what());
        return false;
    }
}

bool zoostPath::GetConfigDir(const std::string& appName, std::string& dir)
{
    std::string home;
    if (configDir_.empty()) {
        if (!GetHome(home)) {
            return false;
        }
    } else {
        home = configDir_;
    }
    zoostFs::path p(home);
    p /= configDirName_;
    p /= appName;
    dir = p.string();
    return true;
}

bool zoostPath::GetBinaryPath(std::string& path)
{
    path.clear();
#if defined(_WIN32) || defined(_WIN64)
    char buf[MAX_PATH]{};
    DWORD length = GetModuleFileName(NULL, buf, MAX_PATH);
    if (length == 0) {
        return false;
    }
    path = buf;
#elif defined(__clang__) && defined(__APPLE__)
    uint32_t size = 0;
    _NSGetExecutablePath(nullptr, &size);
    path.resize(size);
    auto r = _NSGetExecutablePath(path.data(), &size);
    if (r != 0) {
        return false;
    }
#else
    char buf[512]{};
    auto len = readlink("/proc/self/exe", buf, 512);
    if (len < 0) {
        return false;
    }
    buf[len] = '\0';
    path = buf;
#endif
    return true;
}

bool zoostPath::GetBinaryDir(std::string& dir)
{
    if (!GetBinaryPath(dir)) {
        return false;
    }
    dir = GetParentPath(dir);
    return true;
}

bool zoostPath::GetHome(std::string& path)
{
#if defined(_WIN32) || defined(_WIN64)
    char buf[MAX_PATH]{};
    auto* homeDir = std::getenv("USERPROFILE");
    if (!homeDir) {
        return false;
    }
    path = homeDir;
    return true;
#else
    auto r = getenv("HOME");
    if (r == nullptr) {
        return false;
    }
    path = r;
    return true;
#endif
}

bool zoostPath::GetConfigFile(const std::string& appName, const std::string& fileName, std::string& path)
{
    std::string tp;
    if (configDir_.empty()) {
        if (!GetHome(tp)) {
            return false;
        }
    } else {
        tp = configDir_;
    }

    zoostFs::path p(tp);
    p /= configDirName_;
    p /= appName;
    p /= fileName;
    path = p.string();
    return true;
}

void zoostPath::SetConfigDirName(const std::string& name)
{
    configDirName_ = name;
}

void zoostPath::SetConfigDir(const std::string& path)
{
    configDir_ = path;
}

std::string zoostPath::GetParentPath(const std::string& path)
{
    zoostFs::path p(path);
    return p.parent_path().string();
}

std::string zoostPath::GetErrorMsg() const
{
    return errMsg_;
}

zoostDateTime zoostUtils::CurrentTime()
{
    auto now = std::chrono::system_clock::now();
    auto now_time_t = std::chrono::system_clock::to_time_t(now);
    std::tm local_tm = *std::localtime(&now_time_t);
    auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
    zoostDateTime z;
    z.year = static_cast<int>(local_tm.tm_year + 1900);
    z.mon = static_cast<int>(local_tm.tm_mon + 1);
    z.day = static_cast<int>(local_tm.tm_mday);
    z.hour = static_cast<int>(local_tm.tm_hour);
    z.min = static_cast<int>(local_tm.tm_min);
    z.sec = static_cast<int>(local_tm.tm_sec);
    z.msec = static_cast<int>(now_ms.count());
    return z;
}

void zoostUtils::SetConfigDir(const std::string& path)
{
    gConfigDir = path;
}
