use std::marker::PhantomData;
use std::ptr::{addr_of, null, null_mut};
use spa_sys::spa_list;
use pipewire_wrapper_proc_macro::RawWrapper;
use crate::wrapper::RawWrapper;
#[derive(RawWrapper, Debug)]
#[repr(transparent)]
pub struct ListRef {
    #[raw]
    raw: spa_sys::spa_list,
}
pub trait ListElement {
    fn as_list_ptr(&self) -> *mut spa_list;
    fn from_list_ptr(ptr: *mut spa_list) -> *mut Self;
    unsafe fn init_detached(&mut self) {
        let list = self.as_list_ptr();
        (*list).prev = list;
        (*list).next = list;
    }
    unsafe fn remove(&mut self) {
        let list = self.as_list_ptr();
        (*(*list).prev).next = (*list).next;
        (*(*list).next).prev = (*list).prev;
    }
}
impl ListElement for ListRef {
    fn as_list_ptr(&self) -> *mut spa_list {
        self.as_raw_ptr()
    }
    fn from_list_ptr(ptr: *mut spa_list) -> *mut Self {
        ptr as *mut Self
    }
}
pub trait List
where
    Self: Sized,
{
    type Elem: ListElement;
    fn as_list_ptr(&self) -> *mut spa_list;
    fn from_list_ptr(ptr: *mut spa_list) -> *mut Self;
    fn init(&mut self) {
        unsafe {
            let list = self.as_list_ptr();
            (*list).next = list;
            (*list).prev = list;
        }
    }
    fn initialized(&self) -> bool {
        unsafe {
            let list = self.as_list_ptr();
            !(*list).prev.is_null()
        }
    }
    fn empty(&self) -> bool {
        let list = self.as_list_ptr();
        unsafe { (*list).next == (*list).prev && std::ptr::eq((*list).next, list) }
    }
    unsafe fn insert(&mut self, elem: &mut Self::Elem) {
        let list = self.as_list_ptr();
        let elem = elem.as_list_ptr();
        (*elem).prev = list;
        (*elem).next = (*list).next;
        (*list).next = elem;
        (*(*elem).next).prev = elem;
    }
    unsafe fn insert_list(&mut self, other: &mut Self) {
        if !other.empty() {
            let list = self.as_list_ptr();
            let other = other.as_list_ptr();
            (*(*other).next).prev = list;
            (*(*other).prev).next = (*list).next;
            (*(*list).next).prev = (*other).prev;
            (*list).next = (*other).next;
        }
    }
    unsafe fn next(&self, current: &Self::Elem) -> Option<&mut Self::Elem> {
        let link = (*current.as_list_ptr()).next;
        if link == self.as_list_ptr() {
            None
        } else {
            Some(&mut *Self::Elem::from_list_ptr(link))
        }
    }
    unsafe fn prev(&self, current: &Self::Elem) -> Option<&mut Self::Elem> {
        let link = (*current.as_list_ptr()).prev;
        if link == self.as_list_ptr() {
            None
        } else {
            Some(&mut *Self::Elem::from_list_ptr(link))
        }
    }
    unsafe fn first(&self) -> Option<&mut Self::Elem> {
        let list = self.as_list_ptr();
        let first = (*list).next;
        if first == list {
            None
        } else {
            Some(&mut *Self::Elem::from_list_ptr(first))
        }
    }
    unsafe fn last(&self) -> Option<&mut Self::Elem> {
        let list = self.as_list_ptr();
        let last = (*list).prev;
        if last == list {
            None
        } else {
            Some(&mut *Self::Elem::from_list_ptr(last))
        }
    }
    unsafe fn append(&mut self, elem: &mut Self::Elem) {
        let list = (*self.as_list_ptr()).prev;
        let elem = elem.as_list_ptr();
        (*elem).prev = list;
        (*elem).next = (*list).next;
        (*list).next = elem;
        (*(*elem).next).prev = elem;
    }
    unsafe fn prepend(&mut self, elem: &mut Self::Elem) {
        self.insert(elem)
    }
    unsafe fn clean(&mut self) {
        while let Some(first) = self.first() {
            first.remove()
        }
    }
    unsafe fn iter(&self) -> ListIterator<Self> {
        ListIterator {
            list: self,
            element: None,
        }
    }
    unsafe fn iter_mut(&self) -> ListMutIterator<Self> {
        ListMutIterator {
            list: self,
            element: None,
        }
    }
}
pub struct ListIterator<'l, L: List> {
    list: &'l L,
    element: Option<&'l L::Elem>,
}
impl<'l, L: List> Iterator for ListIterator<'l, L> {
    type Item = &'l L::Elem;
    fn next(&mut self) -> Option<Self::Item> {
        let next_ptr = if let Some(element) = self.element {
            unsafe { (*element.as_list_ptr()).next }
        } else {
            unsafe { (*self.list.as_list_ptr()).next }
        };
        if next_ptr == self.list.as_list_ptr() {
            None
        } else {
            self.element = unsafe { Some(&*(L::Elem::from_list_ptr(next_ptr))) };
            self.element
        }
    }
}
pub struct ListMutIterator<'l, L: List> {
    list: &'l L,
    element: Option<*mut spa_list>,
}
impl<'l, L: List> Iterator for ListMutIterator<'l, L> {
    type Item = &'l mut L::Elem;
    fn next(&mut self) -> Option<Self::Item> {
        let next_ptr = if let Some(element) = self.element {
            unsafe { (*element).next }
        } else {
            unsafe { (*self.list.as_list_ptr()).next }
        };
        if next_ptr == self.list.as_list_ptr() {
            None
        } else {
            self.element = Some(next_ptr);
            unsafe { Some(&mut *(L::Elem::from_list_ptr(next_ptr))) }
        }
    }
}
#[repr(C)]
#[cfg(test)]
#[derive(RawWrapper)]
struct TestList {
    #[raw]
    list: spa_list,
}
#[repr(C)]
#[cfg(test)]
#[derive(Debug)]
struct TestElement {
    link: spa_list,
    payload: u32,
}
#[cfg(test)]
impl ListElement for TestElement {
    fn as_list_ptr(&self) -> *mut spa_list {
        addr_of!(self.link) as *mut _
    }
    fn from_list_ptr(ptr: *mut spa_list) -> *mut Self {
        ptr as *mut Self
    }
}
#[cfg(test)]
impl List for TestList {
    type Elem = TestElement;
    fn as_list_ptr(&self) -> *mut spa_list {
        addr_of!(self.list) as *mut _
    }
    fn from_list_ptr(ptr: *mut spa_list) -> *mut Self {
        ptr as *mut Self
    }
}
#[cfg(test)]
impl TestElement {
    fn new(payload: u32) -> Self {
        Self {
            link: spa_list {
                next: null_mut(),
                prev: null_mut(),
            },
            payload,
        }
    }
}
#[cfg(test)]
impl Default for TestList {
    fn default() -> Self {
        Self {
            list: spa_list {
                next: null_mut(),
                prev: null_mut(),
            },
        }
    }
}
#[test]
fn test_init() {
    let mut list = TestList::default();
    unsafe {
        assert!(!list.initialized());
        list.init();
        assert!(list.initialized());
    }
}
#[test]
fn test_empty() {
    let mut list = TestList::default();
    unsafe {
        list.init();
        assert!(list.empty());
    }
}
#[test]
fn test_insert() {
    let mut list = TestList::default();
    unsafe {
        list.init();
        let mut elem1 = TestElement::new(1);
        let mut elem2 = TestElement::new(2);
        assert!(list.empty());
        list.insert(&mut elem1);
        assert!(!list.empty());
        assert_eq!(list.first().unwrap().payload, elem1.payload);
        assert!(list.next(&elem1).is_none());
        assert!(list.prev(&elem1).is_none());
        list.insert(&mut elem2);
        assert_eq!(list.first().unwrap().payload, elem2.payload);
        assert_eq!(list.next(&elem2).unwrap().payload, elem1.payload);
        assert!(list.next(&elem1).is_none());
    }
}
#[test]
fn test_insert_list() {
    let mut list1 = TestList::default();
    let mut list2 = TestList::default();
    unsafe {
        list1.init();
        list2.init();
        let mut elem1 = TestElement::new(1);
        let mut elem2 = TestElement::new(2);
        let mut elem3 = TestElement::new(3);
        let mut elem4 = TestElement::new(4);
        list1.insert(&mut elem1);
        list1.insert(&mut elem2);
        list2.insert(&mut elem3);
        list2.insert(&mut elem4);
        list1.insert_list(&mut list2);
        let current = list1.first();
        assert_eq!(current.as_ref().unwrap().payload, 4);
        let current = list1.next(current.unwrap());
        assert_eq!(current.as_ref().unwrap().payload, 3);
        let current = list1.next(current.unwrap());
        assert_eq!(current.as_ref().unwrap().payload, 2);
        let current = list1.next(current.unwrap());
        assert_eq!(current.as_ref().unwrap().payload, 1);
        let current = list1.next(current.unwrap());
        assert!(current.is_none());
    }
}
#[test]
fn test_iterator() {
    let mut list1 = TestList::default();
    unsafe {
        let mut elem1 = TestElement::new(1);
        let mut elem2 = TestElement::new(2);
        let mut elem3 = TestElement::new(3);
        let mut elem4 = TestElement::new(4);
        list1.init();
        list1.insert(&mut elem1);
        list1.insert(&mut elem2);
        list1.insert(&mut elem3);
        list1.insert(&mut elem4);
        let mut iter = list1.iter();
        assert_eq!(iter.next().unwrap().payload, 4);
        assert_eq!(iter.next().unwrap().payload, 3);
        assert_eq!(iter.next().unwrap().payload, 2);
        assert_eq!(iter.next().unwrap().payload, 1);
        assert!(iter.next().is_none());
    }
}
#[test]
fn test_mut_iterator() {
    let mut list1 = TestList::default();
    unsafe {
        let mut elem1 = TestElement::new(1);
        let mut elem2 = TestElement::new(2);
        let mut elem3 = TestElement::new(3);
        let mut elem4 = TestElement::new(4);
        list1.init();
        list1.insert(&mut elem1);
        list1.insert(&mut elem2);
        list1.insert(&mut elem3);
        list1.insert(&mut elem4);
        let mut iter = list1.iter_mut();
        assert_eq!(iter.next().unwrap().payload, 4);
        assert_eq!(iter.next().unwrap().payload, 3);
        assert_eq!(iter.next().unwrap().payload, 2);
        assert_eq!(iter.next().unwrap().payload, 1);
        assert!(iter.next().is_none());
    }
}