use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

pub(crate) const MAX_INTERCEPT_DEPTH: usize = 10;

pub(crate) struct InterceptGuard {
    depth: Arc<AtomicUsize>,
}

impl InterceptGuard {
    pub(crate) fn enter(depth: &Arc<AtomicUsize>, path: Arc<str>) -> Option<Self> {
        let prev = depth.fetch_add(1, Ordering::Acquire);
        if prev >= MAX_INTERCEPT_DEPTH {
            depth.fetch_sub(1, Ordering::Release);
            tracing::warn!(
                target: "rpstate::intercept",
                path = %path,
                depth = prev + 1,
                "maximum intercept depth reached, skipping execution"
            );
            None
        } else {
            Some(Self {
                depth: depth.clone(),
            })
        }
    }
}

impl Drop for InterceptGuard {
    fn drop(&mut self) {
        self.depth.fetch_sub(1, Ordering::Release);
    }
}

pub struct InterceptDisposer {
    pub id: u64,
    pub path: Arc<str>,
    pub(crate) cleanup: Arc<dyn Fn(u64) + Send + Sync + 'static>,
}

impl InterceptDisposer {
    pub fn remove(self) {
        (self.cleanup)(self.id);
    }
}

impl std::fmt::Debug for InterceptDisposer {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("InterceptDisposer")
            .field("id", &self.id)
            .field("path", &self.path)
            .finish()
    }
}
