use std::sync::Mutex;

use pprof::ProfilerGuard;

pub(super) struct FlameGraph {
    guard: Mutex<Option<ProfilerGuard<'static>>>,
}

impl FlameGraph {
    pub fn new() -> Self {
        Self {
            guard: Mutex::new(None),
        }
    }

    pub fn start(&self) {
        let mut guard = self.guard.lock().unwrap();
        let old = guard.take();
        assert!(old.is_none(), "FlameGraph is already started");
        *guard = Some(
            pprof::ProfilerGuardBuilder::default()
                .frequency(500)
                .blocklist(&["libpthread.so.0", "libm.so.6", "libgcc_s.so.1"])
                .build()
                .unwrap(),
        );
    }

    pub fn stop_to_string(&self) -> anyhow::Result<String> {
        let mut guard = self.guard.lock().unwrap();
        let old = guard.take();
        if old.is_none() {
            return Err(anyhow::anyhow!("FlameGraph is not started"));
        }
        let profiler = old.unwrap();
        drop(guard);

        let report = profiler.report().build()?;
        let mut svg_data = Vec::new();
        report.flamegraph(&mut svg_data)?;
        Ok(String::from_utf8(svg_data)?)
    }
}
