use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
use std::iter::{Extend, IntoIterator, Iterator};
use struct_patch::Filler;
#[cfg(feature = "status")]
use struct_patch::Status;

// NOTE: Default, Extend, IntoIterator, is_empty are required for extendable type
#[derive(Clone, Debug, Default)]
struct WrapVec {
    inner: Vec<usize>,
}

impl Extend<usize> for WrapVec {
    fn extend<WrapVec: IntoIterator<Item = usize>>(&mut self, iter: WrapVec) {
        self.inner.extend(iter.into_iter());
    }
}

impl IntoIterator for WrapVec {
    type Item = usize;
    type IntoIter = Box<dyn Iterator<Item = Self::Item>>;
    fn into_iter(self) -> Self::IntoIter {
        Box::new(self.inner.into_iter())
    }
}

impl WrapVec {
    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }
}

#[derive(Clone, Default, Filler)]
#[filler(attribute(derive(Clone, Debug, Default)))]
struct Item {
    field_complete: bool,
    // Will check the field is equal to the value to define the field is empty or not
    #[filler(empty_value = 0)]
    field_int: usize,
    field_string: String,
    maybe_field_int: Option<usize>,
    maybe_field_string: Option<String>,
    list: Vec<usize>,
    _deque: VecDeque<usize>,
    _linked_list: LinkedList<usize>,
    _map: HashMap<usize, usize>,
    _bmap: BTreeMap<usize, usize>,
    _set: HashSet<usize>,
    _bset: BTreeSet<usize>,
    _heap: BinaryHeap<usize>,
    #[filler(extendable)]
    _wrap: WrapVec,
}

// Generated by Filler derive macro
//
// #[derive(Debug, Default)] // pass by filler(attribute(...))
// struct ItemFiller {
//     maybe_field_int: Option<usize>,
//     maybe_field_string: Option<String>,
//     list: Vec<usize>,
//     _deque: VecDeque<usize>,
//     _linked_list: LinkedList<usize>,
//     _map: HashMap<usize, usize>,
//     _bmap: BTreeMap<usize, usize>,
//     _set: HashSet<usize>,
//     _bset: BTreeSet<usize>,
//     _heap: BinaryHeap<usize>,
// }

fn main() {
    let mut item = Item::default();

    let mut filler: ItemFiller = Item::new_empty_filler();

    #[cfg(feature = "status")]
    assert!(filler.is_empty()); // provided by Status

    filler.maybe_field_int = Some(7);

    #[cfg(feature = "status")]
    assert!(!filler.is_empty());

    assert_eq!(
        format!("{filler:?}"),
        "ItemFiller { field_int: 0, maybe_field_int: Some(7), maybe_field_string: None, list: [], _deque: [], _linked_list: [], _set: {}, _bset: {}, _heap: [], _wrap: WrapVec { inner: [] } }"
    );

    item.apply(filler);

    assert!(!item.field_complete);
    assert_eq!(item.field_int, 0);
    assert_eq!(item.field_string, "");
    assert_eq!(item.maybe_field_int, Some(7));
    assert_eq!(item.maybe_field_string, None);
    assert_eq!(item.list.len(), 0);

    let mut filler: ItemFiller = Item::new_empty_filler();
    filler.maybe_field_int = Some(100);
    filler.maybe_field_string = Some("Something".into());

    item.apply(filler);

    assert!(!item.field_complete);
    assert_eq!(item.field_int, 0);
    assert_eq!(item.field_string, "");
    assert_eq!(item.maybe_field_int, Some(7));
    assert_eq!(item.maybe_field_string, Some("Something".into()));
    assert_eq!(item.list.len(), 0);

    let mut filler: ItemFiller = Item::new_empty_filler();
    filler.list = vec![1, 2];
    item.apply(filler);
    assert_eq!(item.list, vec![1, 2]);

    let mut filler: ItemFiller = Item::new_empty_filler();
    filler.list = vec![3, 4];
    item.apply(filler);
    assert_eq!(item.list, vec![1, 2]);

    let mut filler: ItemFiller = Item::new_empty_filler();
    filler.field_int = 7;
    item.apply(filler);
    assert_eq!(item.field_int, 7);

    let mut filler: ItemFiller = Item::new_empty_filler();
    filler.field_int = 5;
    item.apply(filler);
    assert_eq!(item.field_int, 7);
}
