#include "utils.h"

#include <QJsonDocument>
#include <QJsonObject>
#include <QString>

#include <chrono>
#include <cstdarg>
#include <cstdio>
#include <vector>

typedef struct {
    std::chrono::time_point<std::chrono::system_clock> start;
} timer;

static int _log_level = LOG_INFO;
static timer *_timer = nullptr;

static QString formattedMessage(const char *format, va_list args)
{
    va_list countArgs;
    va_copy(countArgs, args);
    const int length = std::vsnprintf(nullptr, 0, format, countArgs);
    va_end(countArgs);

    if (length < 0) {
        return QString::fromUtf8(format);
    }

    std::vector<char> buffer(static_cast<size_t>(length) + 1);
    std::vsnprintf(buffer.data(), buffer.size(), format, args);
    return QString::fromUtf8(buffer.data(), length);
}

extern "C" {
int logLevel()
{
    return _log_level;
}

void setLogLevel(int l)
{
    _log_level = l;
}

const char *logIndicator(int l)
{
    switch(l) {
    case LOG_ERROR:   return "error";
    case LOG_INFO:    return "info";
    case LOG_DEBUG:   return "debug";
    case LOG_WARNING: return "warning";
    }
    return "unknown";
}

double logElapsedSeconds()
{
    if (_timer == nullptr) {
        _timer = new timer;
        _timer->start = std::chrono::system_clock::now();
    }

    const auto current = std::chrono::system_clock::now();
    const auto milliseconds
        = std::chrono::duration_cast<std::chrono::milliseconds>(
              current - _timer->start)
              .count();
    return milliseconds / 1000.0;
}

void logMessage(int level, const char *format, ...)
{
    if (logLevel() < level) {
        return;
    }

    va_list args;
    va_start(args, format);
    const QString message = formattedMessage(format, args);
    va_end(args);

    QJsonObject object;
    object.insert(QStringLiteral("topic"), QStringLiteral("webview-backend"));
    object.insert(QStringLiteral("level"), QString::fromLatin1(logIndicator(level)));
    object.insert(QStringLiteral("elapsed"), logElapsedSeconds());
    object.insert(QStringLiteral("message"), message);

    const QByteArray json = QJsonDocument(object).toJson(QJsonDocument::Compact);
    std::fprintf(stderr, "json:%s\n", json.constData());
    std::fflush(stderr);
}
}
