use std::{collections::BinaryHeap, fmt::Debug, hash::Hash};

use rustc_hash::FxHashMap;

#[derive(Debug)]
pub struct LazyRemoveBinHeap<T: Ord + Hash + Eq + Clone> {
    heap: BinaryHeap<T>,
    tombstones: FxHashMap<T, ()>,
}

impl<T: Ord + Hash + Eq + Clone + Debug> LazyRemoveBinHeap<T> {
    pub fn new(prealloc_size: usize) -> Self {
        LazyRemoveBinHeap {
            heap: BinaryHeap::with_capacity(prealloc_size.next_power_of_two()),
            tombstones: FxHashMap::default(),
        }
    }

    pub fn push(&mut self, item: T) {
        self.heap.push(item);
    }

    pub fn remove(&mut self, item: T) {
        self.tombstones.insert(item, ());
    }

    pub fn peek(&mut self) -> Option<&T> {
        self.evict_tombstones();
        self.heap.peek()
    }

    pub fn is_empty(&mut self) -> bool {
        self.peek().is_none()
    }

    fn evict_tombstones(&mut self) {
        loop {
            match self.heap.peek() {
                None => break,
                Some(top) => match self.tombstones.remove(&top) {
                    Some(_) => {
                        self.heap.pop();
                    }
                    _ => break,
                },
            }
        }
    }
}
