// Copyright (C) 2026  The Software Heritage developers
// See the AUTHORS file at the top-level directory of this distribution
// License: GNU General Public License version 3, or any later version
// See top-level LICENSE file for more information

use std::collections::HashSet;

use rayon::iter::ParallelIterator;
use swh_graph_stdlib::labeling::{DenseLabels, Labels};

macro_rules! set {
    ($($v:expr),* $(,)?) => {{
        vec![$($v,)*].into_iter().collect::<HashSet<_>>()
    }};
}

fn new_store(num_nodes: usize) -> DenseLabels<u64> {
    DenseLabels::new(num_nodes, ())
}

#[test]
fn test_insert_and_get() {
    let mut store = new_store(5);
    assert!(store.is_empty());

    assert!(store.insert(0, 10).is_none());
    assert!(!store.is_empty());

    assert!(store.insert(3, 30).is_none());

    assert_eq!(store.get(0), Some(&10));
    assert_eq!(store.get(3), Some(&30));
    assert_eq!(store.get(1), None);
    assert_eq!(store.get(2), None);
    assert_eq!(store.get(4), None);

    assert!(store.contains_key(0));
    assert!(!store.contains_key(1));
    assert!(!store.contains_key(2));
    assert!(store.contains_key(3));
    assert!(!store.contains_key(4));
}

#[test]
fn test_insert_overwrites() {
    let mut store = new_store(3);

    assert!(store.insert(1, 10).is_none());

    assert_eq!(store.insert(1, 20), Some(10));
    assert_eq!(store.get(1), Some(&20));

    assert_eq!(store.insert(1, 30), Some(20));
    assert_eq!(store.get(1), Some(&30));

    assert!(!store.is_empty());
}

#[test]
fn test_remove() {
    let mut store = new_store(4);

    store.insert(1, 10);
    store.insert(2, 20);

    assert!(store.remove(0).is_none());

    assert_eq!(store.remove(1), Some(10));
    assert_eq!(store.get(1), None);
    assert!(!store.contains_key(1));
    assert!(store.remove(1).is_none());

    assert_eq!(store.get(2), Some(&20));
    assert!(!store.is_empty());

    assert_eq!(store.remove(2), Some(20));
    assert!(store.is_empty());
}

#[test]
fn test_iterators() {
    let mut store = new_store(4);
    store.insert(1, 10);
    store.insert(3, 30);

    let iter_result: Vec<Option<&u64>> = store.iter().collect();
    assert_eq!(iter_result, vec![None, Some(&10), None, Some(&30)]);

    let labeled: HashSet<(usize, &u64)> = store.iter_labeled().collect();
    assert_eq!(labeled, set![(1, &10), (3, &30)]);

    let par_labeled: HashSet<(usize, &u64)> = store.par_iter_labeled().collect();
    assert_eq!(par_labeled, labeled);
}
