#pragma once

#include <cstddef>

// Logger global thread-safe para apps del registry. Escribe a archivo (cwd
// junto al ejecutable, igual que app_settings.ini) y mantiene un ring buffer
// in-memory que el visualizador (log_window) consume.
//
// Lifecycle:
//   - run_app llama logger_init(cfg.log_file, cfg.log_level) si log_file != nullptr
//   - app llama log_info / log_warn / ... durante su ciclo de vida
//   - run_app llama logger_close() al exit
//
// Apps que NO usan fn::run_app deben llamar logger_init/close manualmente.
// Si nunca se llama logger_init, los log_* siguen funcionando contra el ring
// buffer in-memory pero no escriben a disco.
//
// Formato de cada linea:
//   [YYYY-MM-DD HH:MM:SS.mmm] [LEVEL] mensaje
namespace fn_log {

enum class Level : int {
    Debug = 0,
    Info  = 1,
    Warn  = 2,
    Error = 3,
};

// Inicializa el logger global. file_path se interpreta relativo al cwd
// (donde la app ya escribe app_settings.ini). Crea/trunca el archivo si no
// existe; si existe, abre en modo append.
//
// Idempotente: si ya hay un archivo abierto, lo cierra y reabre el nuevo.
// Returns true si pudo abrir el archivo (false → solo buffer in-memory).
bool logger_init(const char* file_path, Level min_level = Level::Info);

// Cierra el archivo. log_* siguen funcionando contra el buffer in-memory.
void logger_close();

// Nivel minimo. Mensajes por debajo se descartan silenciosamente (no van ni
// al archivo ni al buffer).
void  logger_set_level(Level level);
Level logger_level();

// Path del archivo activo. Vacio si no inicializado o cerrado.
const char* logger_path();

// Emisores. Formato printf-style. Cada llamada escribe una linea completa.
// Thread-safe (mutex interno).
void log_debug(const char* fmt, ...);
void log_info (const char* fmt, ...);
void log_warn (const char* fmt, ...);
void log_error(const char* fmt, ...);

// === Ring buffer in-memory (para log_window) ===

constexpr std::size_t kBufferCapacity = 2000;
constexpr std::size_t kEntryTextMax   = 480; // deja sitio para timestamp + level

struct Entry {
    Level         level;
    long long     ts_ms; // unix epoch en milisegundos
    char          text[kEntryTextMax];
};

// Numero de entradas vivas en el buffer (≤ kBufferCapacity).
std::size_t buffer_size();

// Acceso por indice [0, buffer_size()). i==0 es la entrada mas antigua viva.
// Nullptr si i fuera de rango. Snapshot — el caller debe asumir que la
// entrada puede ser sobrescrita en la siguiente llamada thread-unsafe; para
// el viewer esto no es problema porque ImGui es single-threaded.
const Entry* buffer_at(std::size_t i);

// Limpia el ring buffer. No toca el archivo en disco.
void buffer_clear();

// Helper para el viewer: nombre corto del nivel ("DEBUG"/"INFO"/...).
const char* level_label(Level level);

} // namespace fn_log
