#include "logwrapper.h"
#include "help.h"
#include <iostream>
#include <string>


Napi::Value napi_NativeAddonLog(const Napi::CallbackInfo& info)
{
    const Napi::Env env = info.Env();

    if (NS_HELP::VerifyArgs(__func__, info, { NS_HELP::NUMBER, NS_HELP::STRING, NS_HELP::OBJECT_OR_STRING }))
    {
        plog::Severity objSeverity = (plog::Severity)(info[0].As<Napi::Number>().Int32Value());
        std::string strCaller = std::string("js:") + std::string(info[1].As<Napi::String>());
        std::string strMsg = info[2].As<Napi::Object>().ToString();

        // Use variant of LOG macro implementation to ensure caller instead of __func__ is registered in log:
        (*plog::get<LOGINSTANCE>()) += plog::Record(objSeverity, strCaller.c_str(), 0, nullptr, PLOG_GET_THIS()) << strMsg;
    }

    return env.Undefined();
}

Napi::Value napi_GetNativeAddonLogConfig(const Napi::CallbackInfo& info)
{
    const Napi::Env env = info.Env();

    if (NS_HELP::VerifyArgs(__func__, info, { }))
    {
        plog::Severity objMaxSeverity = plog::get<LOGINSTANCE>()->getMaxSeverity();
        std::string strMaxSeverity = std::string(plog::severityToString(objMaxSeverity));

        Napi::Object config = Napi::Object::New(env);

        config.Set(Napi::String::New(env, "maxSeverity"), Napi::Number::New(env, objMaxSeverity));
        config.Set(Napi::String::New(env, "maxSeverityString"), Napi::String::New(env, strMaxSeverity));
        config.Set(Napi::String::New(env, "configuredLogPath"), Napi::String::New(env, _LogWrapper.GetConfigLogPath()));

        return config;
    }

    return env.Undefined();
}


IMPLEMENT_GETINSTANCE(LogWrapper)
LogWrapper::LogWrapper()
{}

LogWrapper::~LogWrapper()
{}

void LogWrapper::Config()
{
    std::cout << "start config log wrapper" << std::endl;
    char* pDefault = std::getenv("YEALINKSDK_RESOURCE_PATH");
    std::string strPath = pDefault ? pDefault : "";
    if (strPath.empty())
    {
#if _WIN32
        char* pAppData = std::getenv("APPDATA");
        strPath = pAppData ? pAppData : "";
#elif __APPLE__
        char* pHome  = getenv("HOME");
        char buf[PATH_MAX];
        if(pHome == NULL)
        {
            // if path home not found, user current
            pHome = getcwd(buf, PATH_MAX);
        }
        strPath = std::string(pHome ? pHome : "");
        strPath = strPath.append("/Library/Application Support/YealinkSdk");
#endif
    }

#if _WIN32
    if (!strPath.empty())
    {
        strPath = strPath.append("\\YealinkSdk");
    }
#endif

    auto funcEndWith = [](const std::string& str, const std::string& suffix) {
        return str.size() >= suffix.size() && 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
    };

    if (!funcEndWith(strPath, "/") && !funcEndWith(strPath, "\\"))
    {
#ifdef _WIN32
        strPath = strPath.append("\\");
#else
        strPath = strPath.append("/");
#endif
    }

    strPath = strPath.append("YealinkNodeWrapper.log");

    // Use same environment variable and defaults as Yealink SDK to setup log level.
    const char * const pSeverityEnv = std::getenv("YEALINKSDK_TRACE_LEVEL");
    std::string strSeverityEnv(pSeverityEnv ? pSeverityEnv : "info");

    std::cout << "log file:" << strPath << "," << "serveriry:" << strSeverityEnv << std::endl;

    plog::Severity objSeverity = plog::warning;
    if (strSeverityEnv == "fatal")
    {
        objSeverity = plog::fatal;
    }
    else if (strSeverityEnv == "error")
    {
        objSeverity = plog::error;
    }
    else if (strSeverityEnv == "warning")
    {
        objSeverity = plog::warning;
    }
    else if (strSeverityEnv == "info")
    {
        objSeverity = plog::info;
    }
    else if (strSeverityEnv == "debug")
    {
        objSeverity = plog::debug;
    }
    else if (strSeverityEnv == "trace" || strSeverityEnv == "verbose")
    {
        objSeverity = plog::verbose;
    }
    else
    {
        objSeverity = plog::none;
    }

    // Setup plog:
    plog::init<LOGINSTANCE>(objSeverity, strPath.c_str(), 10 * 1024 * 1024, 5);

    // Save log location for reference (if anything is logged).
    //configuredLogPath = (objSeverity!=plog::none) ? strPath : "";

    // Log configuration:
    LOG_(LOGINSTANCE, plog::info) << "config log severity: " << plog::severityToString(objSeverity) << " and log instance: " << LOGINSTANCE;
}

void LogWrapper::Trace(const plog::Severity& objSeverity, const std::string& str)
{
    LOG_(LOGINSTANCE, objSeverity) << str << "\n";
}
