/// Macro to generate singleton pattern for structs
///
/// Usage:
/// ```rust,ignore
/// use crate::utils::singleton::singleton;
///
/// struct MyStruct {
///     value: i32,
/// }
/// impl MyStruct {
///     fn new() -> Self {
///         MyStruct { value: 0 }
///     }
/// }
/// singleton!(MyStruct, INSTANCE);
/// ```
#[macro_export]
macro_rules! singleton {
    ($struct_name:ty, $instance_name:ident) => {
        static $instance_name: std::sync::OnceLock<$struct_name> = std::sync::OnceLock::new();

        impl $struct_name {
            pub fn global() -> &'static $struct_name {
                $instance_name.get_or_init(|| Self::new())
            }
        }
    };

    ($struct_name:ty, $instance_name:ident, $init_expr:expr) => {
        static $instance_name: std::sync::OnceLock<$struct_name> = std::sync::OnceLock::new();

        impl $struct_name {
            pub fn global() -> &'static $struct_name {
                $instance_name.get_or_init(|| $init_expr)
            }
        }
    };
}

/// Macro for singleton pattern with logging
#[macro_export]
macro_rules! singleton_with_logging {
    ($struct_name:ty, $instance_name:ident, $struct_name_str:literal) => {
        static $instance_name: std::sync::OnceLock<$struct_name> = std::sync::OnceLock::new();

        impl $struct_name {
            pub fn global() -> &'static $struct_name {
                $instance_name.get_or_init(|| {
                    let instance = Self::new();
                    $crate::logging!(
                        info,
                        $crate::utils::logging::Type::Setup,
                        true,
                        concat!($struct_name_str, " initialized")
                    );
                    instance
                })
            }
        }
    };
}

/// Macro for singleton pattern with lazy initialization using a closure
/// This replaces patterns like lazy_static! or complex OnceLock initialization
#[macro_export]
macro_rules! singleton_lazy {
    ($struct_name:ty, $instance_name:ident, $init_closure:expr) => {
        static $instance_name: std::sync::OnceLock<$struct_name> = std::sync::OnceLock::new();

        impl $struct_name {
            pub fn global() -> &'static $struct_name {
                $instance_name.get_or_init($init_closure)
            }
        }
    };
}

/// Macro for singleton pattern with lazy initialization and logging
#[macro_export]
macro_rules! singleton_lazy_with_logging {
    ($struct_name:ty, $instance_name:ident, $struct_name_str:literal, $init_closure:expr) => {
        static $instance_name: std::sync::OnceLock<$struct_name> = std::sync::OnceLock::new();

        impl $struct_name {
            pub fn global() -> &'static $struct_name {
                $instance_name.get_or_init(|| {
                    let instance = $init_closure();
                    $crate::logging!(
                        info,
                        $crate::utils::logging::Type::Setup,
                        true,
                        concat!($struct_name_str, " initialized")
                    );
                    instance
                })
            }
        }
    };
}

#[cfg(test)]
mod tests {
    struct TestStruct {
        value: i32,
    }

    impl TestStruct {
        fn new() -> Self {
            Self { value: 42 }
        }
    }

    singleton!(TestStruct, TEST_INSTANCE);

    #[test]
    fn test_singleton_macro() {
        let instance1 = TestStruct::global();
        let instance2 = TestStruct::global();

        assert_eq!(instance1.value, 42);
        assert_eq!(instance2.value, 42);
        assert!(std::ptr::eq(instance1, instance2));
    }
}
