//! Logging hook abstractions for libraries, CLI, and plugins.

use std::sync::Arc;

/// Severity for records emitted through PixelFlow logging hooks.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum LogLevel {
    /// Detailed diagnostic event for troubleshooting.
    Trace,
    /// Developer-focused diagnostic event.
    Debug,
    /// Informational event for normal operation.
    Info,
    /// Recoverable problem or degraded behavior.
    Warn,
    /// Operation failed and returned an error.
    Error,
}

/// Immutable log event delivered to a [`LogSink`].
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct LogRecord {
    level: LogLevel,
    target: String,
    message: String,
}

impl LogRecord {
    /// Creates a log record for a target and message.
    #[must_use]
    pub fn new(level: LogLevel, target: impl Into<String>, message: impl Into<String>) -> Self {
        Self {
            level,
            target: target.into(),
            message: message.into(),
        }
    }

    /// Returns record severity.
    #[must_use]
    pub const fn level(&self) -> LogLevel {
        self.level
    }

    /// Returns module or subsystem target.
    #[must_use]
    pub fn target(&self) -> &str {
        &self.target
    }

    /// Returns human-readable log message.
    #[must_use]
    pub fn message(&self) -> &str {
        &self.message
    }
}

/// Destination for PixelFlow log records.
pub trait LogSink: Send + Sync {
    /// Handles one immutable log record.
    fn log(&self, record: &LogRecord);
}

/// Log sink that discards all records.
#[derive(Debug, Default)]
pub struct NoopLogSink;

impl LogSink for NoopLogSink {
    fn log(&self, _record: &LogRecord) {}
}

/// Cloneable logger handle used by core and downstream crates.
#[derive(Clone)]
pub struct Logger {
    sink: Arc<dyn LogSink>,
}

impl Logger {
    /// Creates a logger from a shared sink.
    #[must_use]
    pub fn new(sink: Arc<dyn LogSink>) -> Self {
        Self { sink }
    }

    /// Emits one log record to the configured sink.
    pub fn emit(&self, record: &LogRecord) {
        self.sink.log(record);
    }

    /// Creates and emits one log record.
    pub fn log(&self, level: LogLevel, target: impl Into<String>, message: impl Into<String>) {
        self.emit(&LogRecord::new(level, target, message));
    }
}

impl Default for Logger {
    fn default() -> Self {
        Self::new(Arc::new(NoopLogSink))
    }
}
