/**
 * @file logger.hpp
 * @brief ASF Logger - Wrapper for ESP-IDF logging functionality
 * @author Mahmoud Elmohtady
 * @company Nabd solutions - ASF
 * @copyright Copyright (c) 2025
 * 
 * @details
 * Abstract logger class for the application and device driver layers
 * - Does not depend directly on the low-level logging mechanism provided by platform
 * - Supports logging levels (info, warn, debug, error, verbose)
 * - Formats messages with ISO timestamp, TAG, level, and unique ID
 * - Low overhead design for minimal performance impact
 * - Easily included in all modules without compile/linking errors
 * - Efficient in compilation time and flash space
 * 
 * Design: Namespace with free functions for simplicity and zero overhead
 */

#ifndef LOGGER_HPP
#define LOGGER_HPP

#include <cstdint>
#include <cstdarg>
#include "esp_log.h"
#include "esp_timer.h"

/**
 * @brief Logger namespace containing all logging functionality
 */
namespace asf {
namespace logger {

/**
 * @brief Log level enumeration
 */
enum class LogLevel : uint8_t
{
    VERBOSE = 0,  ///< Verbose level (most detailed)
    DEBUG = 1,    ///< Debug level
    INFO = 2,     ///< Information level
    WARNING = 3,  ///< Warning level
    ERROR = 4,    ///< Error level
    NONE = 5      ///< No logging
};

/**
 * @brief Log criticality enumeration
 */
enum class Criticality : uint8_t
{
    LOW,        ///< Low criticality
    MEDIUM,     ///< Medium criticality
    HIGH,       ///< High criticality
    VERY_HIGH   ///< Very high criticality
};

/**
 * @brief Logger configuration structure
 */
struct LoggerConfig
{
    LogLevel minLevel;          ///< Minimum log level to display
    bool enableTimestamp;       ///< Enable ISO timestamp in output
    bool enableColor;           ///< Enable color output
    bool enableId;              ///< Enable unique ID in output
    uint32_t maxMessageLength;  ///< Maximum message length
    const char* filePath;       ///< Path to log file (nullptr to disable file logging)
};

/**
 * @brief Initialize the logger with configuration
 * @param config Logger configuration
 */
void initialize(const LoggerConfig& config);

/**
 * @brief Set minimum log level
 * @param level Minimum log level to display
 */
void setLogLevel(LogLevel level);

/**
 * @brief Get current minimum log level
 * @return Current minimum log level
 */
LogLevel getLogLevel();

/**
 * @brief Enable or disable timestamp in log output
 * @param enable True to enable, false to disable
 */
void enableTimestamp(bool enable);

/**
 * @brief Enable or disable color in log output
 * @param enable True to enable, false to disable
 */
void enableColor(bool enable);

/**
 * @brief Enable or disable ID in log output
 * @param enable True to enable, false to disable
 */
void enableId(bool enable);

/**
 * @brief Enable file logging
 * @param filePath Path to the log file (e.g., "/ESP/log.txt")
 */
void enableFileLogging(const char* filePath);

/**
 * @brief Get ISO 8601 formatted timestamp
 * @param buffer Buffer to store timestamp
 * @param bufferSize Size of buffer
 * @return Pointer to buffer
 */
const char* getIsoTimestamp(char* buffer, size_t bufferSize);

/**
 * @brief Main logging function
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param level Log level
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void log(const char* tag, uint32_t id, LogLevel level, Criticality criticality, const char* format, ...);

/**
 * @brief Log verbose message
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void logVerbose(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);

/**
 * @brief Log debug message
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void logDebug(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);

/**
 * @brief Log info message
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void logInfo(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);

/**
 * @brief Log warning message
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void logWarning(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);

/**
 * @brief Log error message
 * @param tag Log tag (module name)
 * @param id Unique message ID
 * @param criticality Message criticality
 * @param format Printf-style format string
 * @param ... Variable arguments
 */
void logError(const char* tag, uint32_t id, Criticality criticality, const char* format, ...);

/**
 * @brief Get default logger configuration
 * @return Default logger configuration
 */
LoggerConfig getDefaultConfig();

/**
 * @brief Convert log level to string
 * @param level Log level
 * @return String representation of log level
 */
const char* logLevelToString(LogLevel level);

/**
 * @brief Convert log level to color code
 * @param level Log level
 * @return ANSI color code string
 */
const char* logLevelToColor(LogLevel level);

/**
 * @brief Convert criticality to string
 * @param criticality Message criticality
 * @return String representation of criticality
 */
const char* criticalityToString(Criticality criticality);

} // namespace logger
} // namespace asf

// Convenience macros for easier usage
#define ASF_LOG_VERBOSE(tag, id, crit, format, ...) asf::logger::logVerbose(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_DEBUG(tag, id, crit, format, ...)   asf::logger::logDebug(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_INFO(tag, id, crit, format, ...)    asf::logger::logInfo(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_WARNING(tag, id, crit, format, ...) asf::logger::logWarning(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOG_ERROR(tag, id, crit, format, ...)   asf::logger::logError(tag, id, crit, format, ##__VA_ARGS__)

// Short form macros
#define ASF_LOGV(tag, id, crit, format, ...) ASF_LOG_VERBOSE(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGD(tag, id, crit, format, ...) ASF_LOG_DEBUG(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGI(tag, id, crit, format, ...) ASF_LOG_INFO(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGW(tag, id, crit, format, ...) ASF_LOG_WARNING(tag, id, crit, format, ##__VA_ARGS__)
#define ASF_LOGE(tag, id, crit, format, ...) ASF_LOG_ERROR(tag, id, crit, format, ##__VA_ARGS__)

#endif // LOGGER_HPP