/*
 * log.h
 *
 * Created on: 21.04.2025
 * Author: Kilian
 *
 * Core logging system with support for multiple backends
 */
#pragma once
#ifndef __LOG_H
#define __LOG_H

#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>

/* Configuration */
#define MAX_MESSAGE_LENGTH 384
#define USE_ANSI_ESCAPE_CODES true  // if true, log messages will be colored according to their log level
#define PRINT_TIMESTAMP false       // if true, timestamp (from HAL_GetTick) is printed before each log message

/* Maximum number of backends that can be registered */
#define MAX_LOG_BACKENDS 4

/* Log level definitions */
typedef enum {
  LOG_LEVEL_FATAL,
  LOG_LEVEL_ERROR,
  LOG_LEVEL_WARNING,
  LOG_LEVEL_INFO,
  LOG_LEVEL_DEBUG,
  LOG_LEVEL_NOISY
} log_level_t;

/* Log message structure */
typedef struct {
  log_level_t level;
  uint32_t timestamp;
  char message[MAX_MESSAGE_LENGTH];
  size_t message_length;
} log_message_t;

/* Log backend interface */
typedef struct {
  const char* name;
  void (*init)(void);
  bool (*is_enabled)(log_level_t level);
  void (*write)(const log_message_t* message);
  void (*flush)(void);
  void (*clear)(void);
} log_backend_t;

/* Log level names with formatting for display */
#if USE_ANSI_ESCAPE_CODES
[[maybe_unused]] static const char *const log_level_names[] = {
    "\033[31m[FATAL]\033[0m ", "\033[31m[ERROR]\033[0m ",
    "\033[93m[WARN] \033[0m ", "\033[97m[INFO] \033[0m ",
    "\033[37m[DEBUG]\033[0m ", "\033[37m[NOISY]\033[0m "};
#else
[[maybe_unused]] static const char *const log_level_names[] = {
    "[FATAL] ", "[ERROR] ", "[WARN]  ", "[INFO]  ", "[DEBUG] ", "[NOISY] "};
#endif

/* Backend management functions */
bool log_register_backend(const log_backend_t* backend);
void log_init_all_backends(void);

/* Frontend logging functions */
[[gnu::format(printf, 2, 3)]]
void log_message(log_level_t level, const char *msg, ...);

#ifdef LOG_PREFIX
#define log_message(level, fmt, ...) \
    log_message(level, LOG_PREFIX fmt, ##__VA_ARGS__)
#endif

[[gnu::format(printf, 2, 3)]]
void log_message_cont(log_level_t level, const char *msg, ...);

void log_clear_console(void);

bool log_is_level_enabled(log_level_t level);

/* Convenience macros for different log levels */
#define log_fatal(fmt, ...) log_message(LOG_LEVEL_FATAL, fmt, ##__VA_ARGS__)
#define log_error(fmt, ...) log_message(LOG_LEVEL_ERROR, fmt, ##__VA_ARGS__)
#define log_warning(fmt, ...) log_message(LOG_LEVEL_WARNING, fmt, ##__VA_ARGS__)
#define log_info(fmt, ...) log_message(LOG_LEVEL_INFO, fmt, ##__VA_ARGS__)
#define log_debug(fmt, ...) log_message(LOG_LEVEL_DEBUG, fmt, ##__VA_ARGS__)
#define log_noisy(fmt, ...) log_message(LOG_LEVEL_NOISY, fmt, ##__VA_ARGS__)

#endif /* __LOG_H */