//
// Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
//

#include "logging.hpp"

#include <cstdio>

#include "Python/Helpers.hpp"

namespace sf {
std::string Logger::formatString(const char *format, ...) {
  char msg[1000] = {0};
  va_list args;
  va_start(args, format);
  vsnprintf(msg, sizeof(msg), format, args);
  va_end(args);

  return std::string(msg);
}

void Logger::setupPyLogger() {
  py::UniqueRef pyLoggingModule;
  py::importPythonModule("snowflake.connector.snow_logging", pyLoggingModule);
  PyObject *logger =
      PyObject_CallMethod(pyLoggingModule.get(), "getSnowLogger", "s", m_name);

  m_pyLogger.reset(logger);
}

Logger::Logger(const char *name) : m_name(name) {}

void Logger::log(int level, const char *path_name, const char *func_name,
                 int line_num, const char *msg) {
  if (m_pyLogger.get() == nullptr) {
    setupPyLogger();
  }

  PyObject *logger = m_pyLogger.get();
  py::UniqueRef keywords(PyDict_New());
  py::UniqueRef call_log(PyObject_GetAttrString(logger, "log"));

  // prepare keyword args for snow_logger
  py::UniqueRef level_ref(Py_BuildValue("i", level));
  py::UniqueRef path_name_ref(Py_BuildValue("s", path_name));
  py::UniqueRef func_name_ref(Py_BuildValue("s", func_name));
  py::UniqueRef line_num_ref(Py_BuildValue("i", line_num));
  py::UniqueRef msg_ref(Py_BuildValue("s", msg));

  PyDict_SetItemString(keywords.get(), "level", level_ref.get());
  PyDict_SetItemString(keywords.get(), "path_name", path_name_ref.get());
  PyDict_SetItemString(keywords.get(), "func_name", func_name_ref.get());
  PyDict_SetItemString(keywords.get(), "line_num", line_num_ref.get());
  PyDict_SetItemString(keywords.get(), "msg", msg_ref.get());

  // call snow_logging.SnowLogger.log()
  PyObject_Call(call_log.get(), Py_BuildValue("()"), keywords.get());
}

void Logger::debug(const char *path_name, const char *func_name, int line_num,
                   const char *format, ...) {
  char msg[1000] = {0};
  va_list args;
  va_start(args, format);
  vsnprintf(msg, sizeof(msg), format, args);
  va_end(args);

  Logger::log(DEBUG, path_name, func_name, line_num, msg);
}

void Logger::info(const char *path_name, const char *func_name, int line_num,
                  const char *format, ...) {
  char msg[1000] = {0};
  va_list args;
  va_start(args, format);
  vsnprintf(msg, sizeof(msg), format, args);
  va_end(args);

  Logger::log(INFO, path_name, func_name, line_num, msg);
}

void Logger::warn(const char *path_name, const char *func_name, int line_num,
                  const char *format, ...) {
  char msg[1000] = {0};
  va_list args;
  va_start(args, format);
  vsnprintf(msg, sizeof(msg), format, args);
  va_end(args);

  Logger::log(WARN, path_name, func_name, line_num, msg);
}

void Logger::error(const char *path_name, const char *func_name, int line_num,
                   const char *format, ...) {
  char msg[1000] = {0};
  va_list args;
  va_start(args, format);
  vsnprintf(msg, sizeof(msg), format, args);
  va_end(args);

  Logger::log(ERROR, path_name, func_name, line_num, msg);
}

}  // namespace sf
