use core::{marker::PhantomData, ptr::NonNull};
use crate::{rot_left, rot_right};
#[derive(Debug, PartialEq)]
pub(crate) struct Bricks<const L: usize> {
    idx_buf: [usize; L],
    local_editable_end: usize,  remote_editable_end: usize, history_end: usize,         }
pub struct LineIter<'a, const L: usize, I> {
    bricks: &'a [usize],
    collection: &'a [I],
}
pub struct LineIterMut<'a, 'b, const L: usize, I> {
    bricks: &'a [usize],
    col_ptr: NonNull<[I]>,
    _cpd: PhantomData<&'b mut [I]>,
}
impl<'a, const L: usize, I> Iterator for LineIter<'a, L, I> {
    type Item = &'a I;
    fn next(&mut self) -> Option<Self::Item> {
        let (now, remain) = self.bricks.split_first()?;
        self.bricks = remain;
        self.collection.get(*now)
    }
}
impl<'a, const L: usize, I> DoubleEndedIterator for LineIter<'a, L, I> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let (now, remain) = self.bricks.split_last()?;
        self.bricks = remain;
        self.collection.get(*now)
    }
}
impl<'a, 'b, const L: usize, I> Iterator for LineIterMut<'a, 'b, L, I> {
    type Item = &'b mut I;
    fn next(&mut self) -> Option<Self::Item> {
        let (now, remain) = self.bricks.split_first()?;
        self.bricks = remain;
        unsafe { Some(&mut *self.col_ptr.as_ptr().cast::<I>().add(*now)) }
    }
}
impl<'a, 'b, const L: usize, I> DoubleEndedIterator for LineIterMut<'a, 'b, L, I> {
    fn next_back(&mut self) -> Option<Self::Item> {
        let (now, remain) = self.bricks.split_last()?;
        self.bricks = remain;
        unsafe { Some(&mut *self.col_ptr.as_ptr().cast::<I>().add(*now)) }
    }
}
impl<const L: usize> Bricks<L> {
    pub fn new() -> Self {
        let mut idx_buf = [0; L];
        idx_buf.iter_mut().enumerate().for_each(|(i, v)| *v = i);
        Self {
            idx_buf: idx_buf,
            local_editable_end: 0,
            remote_editable_end: 0,
            history_end: 0,
        }
    }
    pub fn iter_local_editable<'a, I>(&'a self, t: &'a [I]) -> LineIter<'a, L, I> {
        LineIter {
            bricks: &self.idx_buf[0..self.local_editable_end],
            collection: t,
        }
    }
    pub fn iter_remote_editable<'a, I>(&'a self, t: &'a [I]) -> LineIter<'a, L, I> {
        LineIter {
            bricks: &self.idx_buf[self.local_editable_end..self.remote_editable_end],
            collection: t,
        }
    }
    pub fn iter_local_editable_mut<'a, 'b, I>(
        &'a self,
        t: &'b mut [I],
    ) -> LineIterMut<'a, 'b, L, I> {
        LineIterMut {
            bricks: &self.idx_buf[0..self.local_editable_end],
            col_ptr: NonNull::from(t),
            _cpd: PhantomData,
        }
    }
    pub fn iter_remote_editable_mut<'a, 'b, I>(
        &'a self,
        t: &'b mut [I],
    ) -> LineIterMut<'a, 'b, L, I> {
        LineIterMut {
            bricks: &self.idx_buf[self.local_editable_end..self.remote_editable_end],
            col_ptr: NonNull::from(t),
            _cpd: PhantomData,
        }
    }
    pub fn iter_history<'a, I>(&'a self, t: &'a [I]) -> LineIter<'a, L, I> {
        LineIter {
            bricks: &self.idx_buf[self.remote_editable_end..self.history_end],
            collection: t,
        }
    }
    pub fn pop_local_editable_front(&mut self) {
        if self.local_editable_end == 0 {
            return;
        }
        rot_left(&mut self.idx_buf[..self.history_end]);
        self.local_editable_end -= 1;
        self.remote_editable_end -= 1;
        self.history_end -= 1;
    }
    pub fn pop_remote_editable_front(&mut self) {
        if self.remote_editable_end == self.local_editable_end {
            return;
        }
        rot_left(&mut self.idx_buf[self.local_editable_end..self.history_end]);
        self.remote_editable_end -= 1;
        self.history_end -= 1;
    }
    pub fn local_editable_front(&self) -> Option<usize> {
        if self.local_editable_end == 0 {
            None
        } else {
            Some(self.idx_buf[0])
        }
    }
    pub fn remote_editable_front(&self) -> Option<usize> {
        if self.remote_editable_end == self.local_editable_end {
            None
        } else {
            Some(self.idx_buf[self.local_editable_end])
        }
    }
    pub fn insert_local_editable_front(&mut self) -> Result<usize, ()> {
        if self.local_editable_end == L {
            return Err(());
        }
        let end = self.history_end.wrapping_add(1).min(L);
        rot_right(&mut self.idx_buf[..end]);
        self.local_editable_end = self.local_editable_end.wrapping_add(1).min(L);
        self.remote_editable_end = self.remote_editable_end.wrapping_add(1).min(L);
        self.history_end = self.history_end.wrapping_add(1).min(L);
        Ok(self.idx_buf[0])
    }
    pub fn insert_remote_editable_front(&mut self) -> Result<usize, ()> {
        if self.remote_editable_end == L {
            return Err(());
        }
        let end = self.history_end.wrapping_add(1).min(L);
        rot_right(&mut self.idx_buf[self.local_editable_end..end]);
        self.remote_editable_end = self.remote_editable_end.wrapping_add(1).min(L);
        self.history_end = self.history_end.wrapping_add(1).min(L);
        Ok(self.idx_buf[self.local_editable_end])
    }
    pub fn submit_local_editable(&mut self) {
        let range = &mut self.idx_buf[..self.remote_editable_end];
        for _ in 0..(self.remote_editable_end - self.local_editable_end) {
            rot_right(range);
        }
        self.remote_editable_end -= self.local_editable_end;
        self.local_editable_end = 0;
    }
    pub fn submit_remote_editable(&mut self) {
        self.remote_editable_end = self.local_editable_end;
    }
}
#[cfg(test)]
pub mod brick_tests {
    use super::Bricks;
    #[test]
    fn smoke() {
        let mut brick = Bricks::<8>::new();
        println!("{:?}", brick);
        for i in 0..8 {
            let x = brick.insert_local_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        println!("{:?}", brick);
        brick.insert_local_editable_front().unwrap_err();
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [7, 6, 5, 4, 3, 2, 1, 0],
                local_editable_end: 8,
                remote_editable_end: 8,
                history_end: 8,
            }
        );
        println!("=====");
        let mut brick = Bricks::<8>::new();
        for i in 0..4 {
            let x = brick.insert_local_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [3, 2, 1, 0, 4, 5, 6, 7],
                local_editable_end: 4,
                remote_editable_end: 4,
                history_end: 4,
            }
        );
        println!("-----");
        for i in 4..8 {
            let x = brick.insert_remote_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [3, 2, 1, 0, 7, 6, 5, 4],
                local_editable_end: 4,
                remote_editable_end: 8,
                history_end: 8,
            }
        );
        println!("{:?}", brick);
        println!("=====");
        let mut brick = Bricks::<8>::new();
        for i in 0..3 {
            let x = brick.insert_local_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        for i in 3..5 {
            let x = brick.insert_remote_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [2, 1, 0, 4, 3, 5, 6, 7],
                local_editable_end: 3,
                remote_editable_end: 5,
                history_end: 5,
            }
        );
        println!("-----");
        brick.submit_local_editable();
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [4, 3, 2, 1, 0, 5, 6, 7],
                local_editable_end: 0,
                remote_editable_end: 2,
                history_end: 5,
            }
        );
        println!("-----");
        brick.submit_remote_editable();
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [4, 3, 2, 1, 0, 5, 6, 7],
                local_editable_end: 0,
                remote_editable_end: 0,
                history_end: 5,
            }
        );
        println!("=====");
        for i in 5..8 {
            let x = brick.insert_local_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [7, 6, 5, 4, 3, 2, 1, 0],
                local_editable_end: 3,
                remote_editable_end: 3,
                history_end: 8,
            }
        );
        println!("-----");
        for i in 0..2 {
            let x = brick.insert_remote_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [7, 6, 5, 1, 0, 4, 3, 2],
                local_editable_end: 3,
                remote_editable_end: 5,
                history_end: 8,
            }
        );
        let mut buf = [10, 20, 30, 40, 50, 60, 70, 80];
        assert_eq!(
            brick
                .iter_local_editable(&buf)
                .copied()
                .collect::<Vec<_>>()
                .as_slice(),
            &[80, 70, 60],
        );
        assert_eq!(
            brick
                .iter_local_editable_mut(&mut buf)
                .map(|c| *c)
                .collect::<Vec<_>>()
                .as_slice(),
            &[80, 70, 60],
        );
        assert_eq!(
            brick
                .iter_remote_editable(&buf)
                .copied()
                .collect::<Vec<_>>()
                .as_slice(),
            &[20, 10],
        );
        assert_eq!(
            brick
                .iter_remote_editable_mut(&mut buf)
                .map(|c| *c)
                .collect::<Vec<_>>()
                .as_slice(),
            &[20, 10],
        );
        assert_eq!(
            brick
                .iter_history(&buf)
                .copied()
                .collect::<Vec<_>>()
                .as_slice(),
            &[50, 40, 30],
        );
        println!("-----");
        for i in 2..5 {
            let x = brick.insert_local_editable_front().unwrap();
            println!("{:?}", brick);
            assert_eq!(x, i);
        }
        println!("{:?}", brick);
        assert_eq!(
            brick,
            Bricks {
                idx_buf: [4, 3, 2, 7, 6, 5, 1, 0],
                local_editable_end: 6,
                remote_editable_end: 8,
                history_end: 8,
            }
        );
        brick.insert_remote_editable_front().unwrap_err();
        assert_eq!(brick.insert_local_editable_front().unwrap(), 0);
    }
}