use core::marker::PhantomData;
use core::num::NonZeroU32;

use crate::compat::*;
use crate::{ArrayChunks, ImageView, ImageViewMut};

#[derive(Copy)]
pub(crate) struct UnsafeImageMut<'a, V>
where
    V: ImageViewMut,
{
    image: core::ptr::NonNull<V>,
    p: PhantomData<&'a V>,
}

impl<'a, V> Clone for UnsafeImageMut<'a, V>
where
    V: ImageViewMut,
{
    fn clone(&self) -> Self {
        Self {
            image: self.image,
            p: PhantomData,
        }
    }
}

unsafe impl<'a, V: ImageViewMut> Send for UnsafeImageMut<'a, V> {}
unsafe impl<'a, V: ImageViewMut> Sync for UnsafeImageMut<'a, V> {}

impl<'a, V: ImageViewMut> UnsafeImageMut<'a, V> {
    pub fn new(image: &'a mut V) -> Self {
        let ptr = core::ptr::NonNull::new(image as *mut V).unwrap();
        Self {
            image: ptr,
            p: PhantomData,
        }
    }

    fn get(&self) -> &V {
        unsafe { self.image.as_ref() }
    }

    fn get_mut(&mut self) -> &mut V {
        unsafe { self.image.as_mut() }
    }
}

unsafe impl<'a, V: ImageViewMut> ImageView for UnsafeImageMut<'a, V> {
    type Pixel = V::Pixel;

    fn width(&self) -> u32 {
        self.get().width()
    }

    fn height(&self) -> u32 {
        self.get().height()
    }

    fn iter_rows(&self, start_row: u32) -> impl Iterator<Item = &[Self::Pixel]> {
        self.get().iter_rows(start_row)
    }

    fn iter_2_rows(
        &self,
        start_y: u32,
        max_rows: u32,
    ) -> ArrayChunks<impl Iterator<Item = &[Self::Pixel]>, 2> {
        self.get().iter_2_rows(start_y, max_rows)
    }

    fn iter_4_rows(
        &self,
        start_y: u32,
        max_rows: u32,
    ) -> ArrayChunks<impl Iterator<Item = &[Self::Pixel]>, 4> {
        self.get().iter_4_rows(start_y, max_rows)
    }

    fn iter_rows_with_step(
        &self,
        start_y: f64,
        step: f64,
        max_rows: u32,
    ) -> impl Iterator<Item = &[Self::Pixel]> {
        self.get().iter_rows_with_step(start_y, step, max_rows)
    }

    fn split_by_height(
        &self,
        start_row: u32,
        height: NonZeroU32,
        num_parts: NonZeroU32,
    ) -> Option<Vec<impl ImageView<Pixel = Self::Pixel>>> {
        self.get().split_by_height(start_row, height, num_parts)
    }

    fn split_by_width(
        &self,
        start_col: u32,
        width: NonZeroU32,
        num_parts: NonZeroU32,
    ) -> Option<Vec<impl ImageView<Pixel = Self::Pixel>>> {
        self.get().split_by_width(start_col, width, num_parts)
    }
}

unsafe impl<'a, V: ImageViewMut> ImageViewMut for UnsafeImageMut<'a, V> {
    fn iter_rows_mut(&mut self, start_row: u32) -> impl Iterator<Item = &mut [Self::Pixel]> {
        self.get_mut().iter_rows_mut(start_row)
    }

    fn iter_2_rows_mut(&mut self) -> ArrayChunks<impl Iterator<Item = &mut [Self::Pixel]>, 2> {
        self.get_mut().iter_2_rows_mut()
    }

    fn iter_4_rows_mut(&mut self) -> ArrayChunks<impl Iterator<Item = &mut [Self::Pixel]>, 4> {
        self.get_mut().iter_4_rows_mut()
    }

    fn split_by_height_mut(
        &mut self,
        start_row: u32,
        height: NonZeroU32,
        num_parts: NonZeroU32,
    ) -> Option<Vec<impl ImageViewMut<Pixel = Self::Pixel>>> {
        self.get_mut()
            .split_by_height_mut(start_row, height, num_parts)
    }

    fn split_by_width_mut(
        &mut self,
        start_col: u32,
        width: NonZeroU32,
        num_parts: NonZeroU32,
    ) -> Option<Vec<impl ImageViewMut<Pixel = Self::Pixel>>> {
        self.get_mut()
            .split_by_width_mut(start_col, width, num_parts)
    }
}
