use std::{
    panic::{RefUnwindSafe, UnwindSafe},
    sync::Arc,
};
use serde::Serialize;
use strum_macros::{Display, EnumIter};
use crate::enums::{unit_enum_deserialize, unit_enum_from_str};
#[derive(
    Default, EnumIter, Display, Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Debug, Serialize,
)]
pub enum LogLevel {
    Debug,
    #[default]
    Warn,
    Info,
    Error,
}
unit_enum_from_str!(LogLevel);
unit_enum_deserialize!(LogLevel);
pub trait LoggingStrategy: Send {
    fn log(&self, message: &str, level: LogLevel);
}
#[derive(Clone)]
pub struct Logger(
    Arc<Box<dyn LoggingStrategy + Send + Sync + UnwindSafe + RefUnwindSafe + 'static>>,
);
impl Logger {
    pub fn new<T: LoggingStrategy + Send + Sync + UnwindSafe + RefUnwindSafe + 'static>(
        strategy: T,
    ) -> Self {
        Self(Arc::new(Box::new(strategy)))
    }
    pub fn log<M: AsRef<str>>(&self, message: M, level: LogLevel) {
        self.0.log(message.as_ref(), level)
    }
    pub fn info<M: AsRef<str>>(&self, message: M) {
        self.0.log(message.as_ref(), LogLevel::Info)
    }
    pub fn warn<M: AsRef<str>>(&self, message: M) {
        self.0.log(message.as_ref(), LogLevel::Warn)
    }
    pub fn error<M: AsRef<str>>(&self, message: M) {
        self.0.log(message.as_ref(), LogLevel::Error)
    }
    pub fn debug<M: AsRef<str>>(&self, message: M) {
        self.0.log(message.as_ref(), LogLevel::Debug)
    }
}