#include <chrono>
#include <cstdarg>
#include <cstdio>
#include <extra2d/services/logger_service.h>
#include <mutex>

namespace extra2d {

// ConsoleLogger 实现
class ConsoleLogger::Impl {
public:
  std::mutex mutex_;
};

ConsoleLogger::ConsoleLogger()
    : level_(LogLevel::Info), impl_(std::make_unique<Impl>()) {
  info_.name = "ConsoleLogger";
  info_.priority = ServicePriority::Core;
}

ConsoleLogger::~ConsoleLogger() = default;

bool ConsoleLogger::initialize() {
  setState(ServiceState::Running);
  return true;
}

void ConsoleLogger::shutdown() { setState(ServiceState::Stopped); }

void ConsoleLogger::setLevel(LogLevel level) { level_ = level; }

LogLevel ConsoleLogger::getLevel() const { return level_; }

bool ConsoleLogger::isEnabled(LogLevel level) const {
  return static_cast<int>(level) >= static_cast<int>(level_);
}

void ConsoleLogger::log(LogLevel level, const char *fmt, ...) {
  if (!isEnabled(level))
    return;

  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);

  output(level, buffer);
}

void ConsoleLogger::log(LogLevel level, const std::string &msg) {
  if (!isEnabled(level))
    return;
  output(level, msg.c_str());
}

void ConsoleLogger::trace(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Trace))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Trace, buffer);
}

void ConsoleLogger::debug(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Debug))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Debug, buffer);
}

void ConsoleLogger::info(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Info))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Info, buffer);
}

void ConsoleLogger::warn(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Warn))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Warn, buffer);
}

void ConsoleLogger::error(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Error))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Error, buffer);
}

void ConsoleLogger::fatal(const char *fmt, ...) {
  if (!isEnabled(LogLevel::Fatal))
    return;
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsnprintf(buffer, sizeof(buffer), fmt, args);
  va_end(args);
  output(LogLevel::Fatal, buffer);
}

void ConsoleLogger::output(LogLevel level, const char *msg) {
  std::lock_guard<std::mutex> lock(impl_->mutex_);

  auto now = std::chrono::system_clock::now();
  auto time = std::chrono::system_clock::to_time_t(now);
  auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
                now.time_since_epoch()) %
            1000;

  std::tm tm;
#ifdef _WIN32
  localtime_s(&tm, &time);
#else
  localtime_r(&time, &tm);
#endif

  const char *levelStr = getLevelString(level);

  // 颜色代码
  const char *color = "";
  const char *reset = "\033[0m";

  switch (level) {
  case LogLevel::Trace:
    color = "\033[90m";
    break;
  case LogLevel::Debug:
    color = "\033[36m";
    break;
  case LogLevel::Info:
    color = "\033[32m";
    break;
  case LogLevel::Warn:
    color = "\033[33m";
    break;
  case LogLevel::Error:
    color = "\033[31m";
    break;
  case LogLevel::Fatal:
    color = "\033[35m";
    break;
  default:
    break;
  }

  printf("%s[%02d:%02d:%02d.%03d] [%s] %s%s\n", color, tm.tm_hour, tm.tm_min,
         tm.tm_sec, (int)ms.count(), levelStr, msg, reset);
}

const char *ConsoleLogger::getLevelString(LogLevel level) {
  switch (level) {
  case LogLevel::Trace:
    return "TRACE";
  case LogLevel::Debug:
    return "DEBUG";
  case LogLevel::Info:
    return "INFO";
  case LogLevel::Warn:
    return "WARN";
  case LogLevel::Error:
    return "ERROR";
  case LogLevel::Fatal:
    return "FATAL";
  default:
    return "UNKNOWN";
  }
}

} // namespace extra2d
