#ifndef __MX_LOG_H
#define __MX_LOG_H

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

#ifndef MX_LOG_ENABLE
#define MX_LOG_ENABLE 0U
#endif

/* Optional backends (choose at compile time):
 * - MX_LOG_BACKEND_STDIO: prints via printf/fputs (default: 1)
 * - MX_LOG_BACKEND_RTT  : prints via SEGGER RTT (default: 0)
 * - MX_LOG_SET_WRITER() : user provided output callback
 */
#ifndef MX_LOG_BACKEND_STDIO
#define MX_LOG_BACKEND_STDIO 0U
#endif

#ifndef MX_LOG_BACKEND_RTT
#define MX_LOG_BACKEND_RTT   0U
#endif

typedef enum {
    MX_LOG_LEVEL_ERROR = 0,
    MX_LOG_LEVEL_WARN  = 1,
    MX_LOG_LEVEL_INFO  = 2,
    MX_LOG_LEVEL_DEBUG = 3
} mx_log_level_t;

typedef void (*mx_log_writer_t)(const char *msg);

void mx_log_init(void);
void mx_log_set_level(mx_log_level_t level);
mx_log_level_t mx_log_get_level(void);
void mx_log_set_writer(mx_log_writer_t writer);
void mx_log_printf(mx_log_level_t level, const char *tag, const char *fmt, ...);
void mx_log_vprintf(mx_log_level_t level, const char *tag, const char *fmt, va_list ap);
void mx_log_hex_frame(const char *tag, const uint8_t *data, uint16_t len);

#if MX_LOG_ENABLE
#define MX_LOGD(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_DEBUG, (tag), (fmt), ##__VA_ARGS__)
#define MX_LOGI(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_INFO,  (tag), (fmt), ##__VA_ARGS__)
#define MX_LOGW(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_WARN,  (tag), (fmt), ##__VA_ARGS__)
#define MX_LOGE(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_ERROR, (tag), (fmt), ##__VA_ARGS__)
#else
#define MX_LOGD(tag, fmt, ...) ((void)0)
#define MX_LOGI(tag, fmt, ...) ((void)0)
#define MX_LOGW(tag, fmt, ...) ((void)0)
#define MX_LOGE(tag, fmt, ...) ((void)0)
#endif

#ifndef APP_CALI_LOG_ENABLE
#define APP_CALI_LOG_ENABLE MX_LOG_ENABLE
#endif

#ifndef FLASH_PORT_LOG_ENABLE
#define FLASH_PORT_LOG_ENABLE MX_LOG_ENABLE
#endif

#ifndef MOZEN_LOG_ENABLE
#define MOZEN_LOG_ENABLE MX_LOG_ENABLE
#endif

#if APP_CALI_LOG_ENABLE && MX_LOG_ENABLE
#define APP_CALI_LOGD(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_DEBUG, (tag), (fmt), ##__VA_ARGS__)
#define APP_CALI_LOGI(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_INFO,  (tag), (fmt), ##__VA_ARGS__)
#define APP_CALI_LOGW(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_WARN,  (tag), (fmt), ##__VA_ARGS__)
#define APP_CALI_LOGE(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_ERROR, (tag), (fmt), ##__VA_ARGS__)
#else
#define APP_CALI_LOGD(tag, fmt, ...) ((void)0)
#define APP_CALI_LOGI(tag, fmt, ...) ((void)0)
#define APP_CALI_LOGW(tag, fmt, ...) ((void)0)
#define APP_CALI_LOGE(tag, fmt, ...) ((void)0)
#endif

#if FLASH_PORT_LOG_ENABLE && MX_LOG_ENABLE
#define FLASH_PORT_LOGD(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_DEBUG, (tag), (fmt), ##__VA_ARGS__)
#define FLASH_PORT_LOGI(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_INFO,  (tag), (fmt), ##__VA_ARGS__)
#define FLASH_PORT_LOGW(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_WARN,  (tag), (fmt), ##__VA_ARGS__)
#define FLASH_PORT_LOGE(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_ERROR, (tag), (fmt), ##__VA_ARGS__)
#else
#define FLASH_PORT_LOGD(tag, fmt, ...) ((void)0)
#define FLASH_PORT_LOGI(tag, fmt, ...) ((void)0)
#define FLASH_PORT_LOGW(tag, fmt, ...) ((void)0)
#define FLASH_PORT_LOGE(tag, fmt, ...) ((void)0)
#endif

#if MOZEN_LOG_ENABLE && MX_LOG_ENABLE
#define MOZEN_LOGD(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_DEBUG, (tag), (fmt), ##__VA_ARGS__)
#define MOZEN_LOGI(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_INFO,  (tag), (fmt), ##__VA_ARGS__)
#define MOZEN_LOGW(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_WARN,  (tag), (fmt), ##__VA_ARGS__)
#define MOZEN_LOGE(tag, fmt, ...) mx_log_printf(MX_LOG_LEVEL_ERROR, (tag), (fmt), ##__VA_ARGS__)
#else
#define MOZEN_LOGD(tag, fmt, ...) ((void)0)
#define MOZEN_LOGI(tag, fmt, ...) ((void)0)
#define MOZEN_LOGW(tag, fmt, ...) ((void)0)
#define MOZEN_LOGE(tag, fmt, ...) ((void)0)
#endif

#endif /* __MX_LOG_H */
