//! Structured logging with compile-time macros.
//!
//! This module provides a small `Logger` that writes to a `Sink` and four macros:
//! - `os_error!(logger, "...")`
//! - `os_warn!(logger, "...")`
//! - `os_log!(logger, "...")` (informational)
//! - `os_trace!(logger, "...")` (verbose tracing)
//!
//! The macros accept format strings compatible with `core::fmt`.
//! Example:
//! ```no_run
//! use os_observatory::sink::RingBufferSink;
//! use os_observatory::logging::{Logger, Level};
//! use os_observatory::{os_log, os_error};
//!
//! static SINK: RingBufferSink<1024> = RingBufferSink::new();
//! let logger = Logger::new(&SINK).with_level(Level::Info);
//! os_log!(&logger, "Booting kernel v{}", 1);
//! os_error!(&logger, "Unexpected status={}", 42u32);
//! ```

use core::fmt::{self, Write};

use crate::sink::Sink;

/// Logging granularity levels.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum Level {
    Error,
    Warn,
    Info,
    Trace,
}

/// Lightweight logger writing textual records to a `Sink`.
pub struct Logger<'a, S: Sink> {
    sink: &'a S,
    level: Level,
}

impl<'a, S: Sink> Logger<'a, S> {
    /// Creates a new logger with default level `Info`.
    pub fn new(sink: &'a S) -> Self {
        Self {
            sink,
            level: Level::Info,
        }
    }

    /// Sets the minimum level of messages that will be emitted.
    pub fn with_level(mut self, level: Level) -> Self {
        self.level = level;
        self
    }

    /// Returns the current level.
    #[inline]
    pub fn level(&self) -> Level {
        self.level
    }

    /// Emits a preformatted message at the given level.
    pub fn log_args(&self, level: Level, args: fmt::Arguments<'_>) {
        if level > self.level {
            return;
        }
        let mut w = SinkWriter { sink: self.sink };
        let _ = w.write_str(prefix(level));
        let _ = w.write_fmt(args);
        let _ = w.write_str("\n");
    }
}

/// Adapter implementing `core::fmt::Write` for a `Sink`.
struct SinkWriter<'a, S: Sink> {
    sink: &'a S,
}

impl<'a, S: Sink> Write for SinkWriter<'a, S> {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let _ = self.sink.write_str(s);
        Ok(())
    }
}

#[inline]
fn prefix(level: Level) -> &'static str {
    match level {
        Level::Error => "[ERROR] ",
        Level::Warn => "[WARN ] ",
        Level::Info => "[INFO ] ",
        Level::Trace => "[TRACE] ",
    }
}

/// Logs an error message.
#[macro_export]
macro_rules! os_error {
    ($logger:expr, $($arg:tt)*) => {{
        $logger.log_args($crate::logging::Level::Error, core::format_args!($($arg)*));
    }};
}

/// Logs a warning message.
#[macro_export]
macro_rules! os_warn {
    ($logger:expr, $($arg:tt)*) => {{
        $logger.log_args($crate::logging::Level::Warn, core::format_args!($($arg)*));
    }};
}

/// Logs an informational message.
#[macro_export]
macro_rules! os_log {
    ($logger:expr, $($arg:tt)*) => {{
        $logger.log_args($crate::logging::Level::Info, core::format_args!($($arg)*));
    }};
}

/// Logs a verbose tracing message.
#[macro_export]
macro_rules! os_trace {
    ($logger:expr, $($arg:tt)*) => {{
        $logger.log_args($crate::logging::Level::Trace, core::format_args!($($arg)*));
    }};
}

