#include "robot/console.h"
#include <robot/time.h>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <string>

namespace robot
{

  // Global flag to enable/disable colors
  static bool color_enabled = true;

  static inline bool format_ends_with_newline(const char *format)
  {
    if (format == nullptr)
    {
      return false;
    }
    const size_t n = std::strlen(format);
    return (n > 0 && format[n - 1] == '\n');
  }

  bool is_color_supported()
  {
    // Check if NO_COLOR environment variable is set
    const char *no_color = std::getenv("NO_COLOR");
    if (no_color != nullptr && strlen(no_color) > 0)
    {
      return false;
    }

    // Check if TERM environment variable suggests color support
    const char *term = std::getenv("TERM");
    if (term != nullptr)
    {
      // Common terminals that support colors
      if (strstr(term, "xterm") != nullptr ||
          strstr(term, "color") != nullptr ||
          strstr(term, "256") != nullptr ||
          strstr(term, "screen") != nullptr ||
          strstr(term, "tmux") != nullptr)
      {
        return true;
      }
    }

    // Default to true for most modern terminals
    return true;
  }

  void set_color_enabled(bool enabled)
  {
    color_enabled = enabled && is_color_supported();
  }

  bool is_color_enabled()
  {
    return color_enabled && is_color_supported();
  }

  // Helper function to format timestamp as "sec.nsec"
  static std::string format_timestamp()
  {
    try
    {
      // Use WallTime instead of Time to avoid initialization issues
      // WallTime::now() doesn't require Time::init() and is always available
      robot::WallTime now = robot::WallTime::now();
      std::ostringstream oss;
      oss << now.sec << "." << std::setfill('0') << std::setw(9) << now.nsec;
      return oss.str();
    }
    catch (...)
    {
      // If WallTime::now() fails, return empty string
      return "";
    }
  }

  // Helper function that accepts va_list
  static void vprintf_color(const char *color_code, const char *format, va_list args)
  {
    // Print timestamp first
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }

    if (is_color_enabled())
    {
      std::printf("%s", color_code);
    }

    std::vprintf(format, args);

    // Auto newline unless caller already provided one in format string.
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }

    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
  }

  void printf_color(const char *color_code, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color_code, format, args);
    va_end(args);
  }

  void printf_red(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::RED, format, args);
    va_end(args);
  }

  void printf_green(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::GREEN, format, args);
    va_end(args);
  }

  void printf_yellow(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::YELLOW, format, args);
    va_end(args);
  }

  void printf_blue(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::BLUE, format, args);
    va_end(args);
  }

  void printf_cyan(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::CYAN, format, args);
    va_end(args);
  }

  void printf_magenta(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::MAGENTA, format, args);
    va_end(args);
  }

  void printf_white(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::WHITE, format, args);
    va_end(args);
  }

  void log_info(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::BRIGHT_BLUE, format, args);
    va_end(args);
  }

  void log_success(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::GREEN, format, args);
    va_end(args);
  }

  void log_warning(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::YELLOW, format, args);
    va_end(args);
  }

  void log_error(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::RED, format, args);
    va_end(args);
  }

  void log_debug(const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    vprintf_color(color::CYAN, format, args);
    va_end(args);
  }

  void log_info_at(const char *file, int line, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }
    if (is_color_enabled())
    {
      std::printf("%s[INFO] [%s:%d] ", color::BRIGHT_BLUE, file, line);
    }
    else
    {
      std::printf("[INFO] [%s:%d] ", file, line);
    }
    std::vprintf(format, args);
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }
    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
    va_end(args);
  }

  void log_success_at(const char *file, int line, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }
    if (is_color_enabled())
    {
      std::printf("%s[SUCCESS] [%s:%d] ", color::GREEN, file, line);
    }
    else
    {
      std::printf("[SUCCESS] [%s:%d] ", file, line);
    }
    std::vprintf(format, args);
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }
    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
    va_end(args);
  }

  void log_warning_at(const char *file, int line, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }
    if (is_color_enabled())
    {
      std::printf("%s[WARNING] [%s:%d] ", color::YELLOW, file, line);
    }
    else
    {
      std::printf("[WARNING] [%s:%d] ", file, line);
    }
    std::vprintf(format, args);
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }
    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
    va_end(args);
  }

  void log_error_at(const char *file, int line, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }
    if (is_color_enabled())
    {
      std::printf("%s[ERROR] [%s:%d] ", color::RED, file, line);
    }
    else
    {
      std::printf("[ERROR] [%s:%d] ", file, line);
    }
    std::vprintf(format, args);
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }
    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
    va_end(args);
  }

  void log_debug_at(const char *file, int line, const char *format, ...)
  {
    va_list args;
    va_start(args, format);
    std::string timestamp = format_timestamp();
    if (!timestamp.empty())
    {
      std::printf("[%s] ", timestamp.c_str());
    }
    if (is_color_enabled())
    {
      std::printf("%s[DEBUG] [%s:%d] ", color::CYAN, file, line);
    }
    else
    {
      std::printf("[DEBUG] [%s:%d] ", file, line);
    }
    std::vprintf(format, args);
    if (!format_ends_with_newline(format))
    {
      std::printf("\n");
    }
    if (is_color_enabled())
    {
      std::printf("%s", color::RESET);
    }
    va_end(args);
  }

  void log_error_throttle(double throttle, const char *format, ...)
  {
    static auto last_log_time = std::chrono::steady_clock::time_point{};
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration<double>(now - last_log_time).count();

    if (elapsed >= throttle)
    {
      last_log_time = now;
      va_list args;
      va_start(args, format);
      vprintf_color(color::RED, format, args);
      va_end(args);
    }
  }

  void log_info_throttle(double throttle, const char *format, ...)
  {
    static auto last_log_time = std::chrono::steady_clock::time_point{};
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration<double>(now - last_log_time).count();

    if (elapsed >= throttle)
    {
      last_log_time = now;
      va_list args;
      va_start(args, format);
      vprintf_color(color::BRIGHT_BLUE, format, args);
      va_end(args);
    }
  }

  void log_success_throttle(double throttle, const char *format, ...)
  {
    static auto last_log_time = std::chrono::steady_clock::time_point{};
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration<double>(now - last_log_time).count();

    if (elapsed >= throttle)
    {
      last_log_time = now;
      va_list args;
      va_start(args, format);
      vprintf_color(color::GREEN, format, args);
      va_end(args);
    }
  }

  void log_warning_throttle(double throttle, const char *format, ...)
  {
    static auto last_log_time = std::chrono::steady_clock::time_point{};
    auto now = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration<double>(now - last_log_time).count();

    if (elapsed >= throttle)
    {
      last_log_time = now;
      va_list args;
      va_start(args, format);
      vprintf_color(color::YELLOW, format, args);
      va_end(args);
    }
  }

  void log_assert(bool condition, const char *format, ...)
  {
    if (!condition)
    {
      // Print timestamp first
      std::string timestamp = format_timestamp();
      if (!timestamp.empty())
      {
        std::printf("[%s] ", timestamp.c_str());
      }

      // Print error message if provided
      if (format != nullptr)
      {
        va_list args;
        va_start(args, format);
        if (is_color_enabled())
        {
          std::printf("%s", color::RED);
        }
        std::vprintf(format, args);
        if (!format_ends_with_newline(format))
        {
          std::printf("\n");
        }
        if (is_color_enabled())
        {
          std::printf("%s", color::RESET);
        }
        va_end(args);
      }
      else
      {
        // Default error message
        if (is_color_enabled())
        {
          std::printf("%s", color::RED);
        }
        std::printf("Assertion failed!\n");
        if (is_color_enabled())
        {
          std::printf("%s", color::RESET);
        }
      }
      
      // Terminate the program
      std::abort();
    }
  }

} // namespace robot
