// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

// cSpell: ignore opsom
//! This module contains adapter models.

use super::*;

#[cfg(test)]
mod tests_helper {
    use super::*;

    #[derive(Default)]
    pub struct TestView {
        // Track the parameters reported by the model (row counts, indices, etc.).
        // The last field in the tuple is the row size the model reports at the time
        // of callback
        pub changed_rows: RefCell<Vec<usize>>,
        pub added_rows: RefCell<Vec<(usize, usize)>>,
        pub removed_rows: RefCell<Vec<(usize, usize)>>,
        pub reset: RefCell<usize>,
    }

    impl TestView {
        pub fn clear(&self) {
            self.changed_rows.borrow_mut().clear();
            self.added_rows.borrow_mut().clear();
            self.removed_rows.borrow_mut().clear();
        }
    }

    impl ModelChangeListener for TestView {
        fn row_changed(self: Pin<&Self>, row: usize) {
            self.changed_rows.borrow_mut().push(row);
        }

        fn row_added(self: Pin<&Self>, index: usize, count: usize) {
            self.added_rows.borrow_mut().push((index, count));
        }

        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
            self.removed_rows.borrow_mut().push((index, count));
        }
        fn reset(self: Pin<&Self>) {
            *self.reset.borrow_mut() += 1;
        }
    }

    pub struct ModelChecker<Data: PartialEq + core::fmt::Debug + 'static> {
        pub model: Rc<dyn Model<Data = Data>>,
        pub rows_copy: RefCell<Vec<Data>>,
    }

    impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChangeListener for ModelChecker<Data> {
        fn row_changed(self: Pin<&Self>, row: usize) {
            self.rows_copy.borrow_mut()[row] = self.model.row_data(row).unwrap();
        }

        fn row_added(self: Pin<&Self>, index: usize, count: usize) {
            let mut copy = self.rows_copy.borrow_mut();
            for row in index..index + count {
                copy.insert(row, self.model.row_data(row).unwrap());
            }
        }

        fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
            self.rows_copy.borrow_mut().drain(index..index + count);
        }
        fn reset(self: Pin<&Self>) {
            *self.rows_copy.borrow_mut() = ModelRc::from(self.model.clone()).iter().collect()
        }
    }

    impl<Data: PartialEq + core::fmt::Debug + 'static> ModelChecker<Data> {
        pub fn new(model: Rc<impl Model<Data = Data> + 'static>) -> ModelChangeListenerBox<Self> {
            let s = Self { rows_copy: RefCell::new(model.iter().collect()), model: model.clone() };
            let s = ModelChangeListenerBox::new(s);
            model.model_tracker().attach_peer(s.as_ref().model_peer());
            s
        }

        #[track_caller]
        pub fn check(&self) {
            assert_eq!(
                *self.rows_copy.borrow(),
                ModelRc::from(self.model.clone()).iter().collect::<Vec<_>>()
            );
        }
    }

    impl<Data: PartialEq + core::fmt::Debug + 'static> Drop for ModelChecker<Data> {
        fn drop(&mut self) {
            self.check();
        }
    }

    #[derive(Default)]
    pub struct BrokenModel<T> {
        pub data: RefCell<Vec<Option<T>>>,
        pub notify: ModelNotify,
    }

    #[cfg(test)]
    impl<T: Clone> Model for BrokenModel<T> {
        type Data = T;

        fn row_count(&self) -> usize {
            self.data.borrow().len()
        }

        fn row_data(&self, row: usize) -> Option<Self::Data> {
            self.data.borrow().get(row).and_then(|x| x.clone())
        }

        fn set_row_data(&self, row: usize, data: Self::Data) {
            self.data.borrow_mut()[row] = Some(data);
            self.notify.row_changed(row);
        }

        fn model_tracker(&self) -> &dyn ModelTracker {
            &self.notify
        }
    }

    impl<T> BrokenModel<T> {
        pub fn new(data: Vec<Option<T>>) -> Rc<Self> {
            Rc::new(Self { data: RefCell::new(data), notify: Default::default() })
        }
    }
}

/// Provides rows that are generated by a map function based on the rows of another Model
///
/// When the other Model is updated, the `MapModel` is updated accordingly.
///
/// Generic parameters:
/// * `M` the type of the wrapped `Model`.
/// * `F` the map function.
///
/// ## Example
///
/// Here we have a [`VecModel`] holding rows of a custom type `Name`.
/// It is then mapped into a `MapModel` of [`SharedString`]s
///
/// ```
/// # use slint::{Model, VecModel, SharedString, MapModel};
/// #[derive(Clone)]
/// struct Name {
///     first: String,
///     last: String,
/// }
///
/// let model = VecModel::from(vec![
///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
/// ]);
///
/// let mapped_model = MapModel::new(model, |n|
///     slint::format!("{}, {}", n.last, n.first)
/// );
///
/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Mustermann, Max"));
/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
///
/// ```
///
/// Alternatively you can use the shortcut [`ModelExt::map`].
/// ```
/// # use slint::{Model, ModelExt, VecModel, SharedString, MapModel};
/// # #[derive(Clone)]
/// # struct Name {
/// #     first: String,
/// #     last: String,
/// # }
/// let mapped_model = VecModel::from(vec![
///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
/// ])
/// .map(|n| slint::format!("{}, {}", n.last, n.first));
/// # assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
/// # assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Mustermann, Max"));
/// # assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
/// ```
///
/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the MapModel:
/// ```
/// # use std::rc::Rc;
/// # use slint::{Model, VecModel, SharedString, MapModel};
/// # #[derive(Clone)]
/// # struct Name {
/// #     first: String,
/// #     last: String,
/// # }
/// let model = Rc::new(VecModel::from(vec![
///     Name { first: "Hans".to_string(), last: "Emil".to_string() },
///     Name { first: "Max".to_string(), last: "Mustermann".to_string() },
///     Name { first: "Roman".to_string(), last: "Tisch".to_string() },
/// ]));
///
/// let mapped_model = MapModel::new(model.clone(), |n|
///     slint::format!("{}, {}", n.last, n.first)
/// );
///
/// model.set_row_data(1, Name { first: "Minnie".to_string(), last: "Musterfrau".to_string() });
///
/// assert_eq!(mapped_model.row_data(0).unwrap(), SharedString::from("Emil, Hans"));
/// assert_eq!(mapped_model.row_data(1).unwrap(), SharedString::from("Musterfrau, Minnie"));
/// assert_eq!(mapped_model.row_data(2).unwrap(), SharedString::from("Tisch, Roman"));
///
/// ```
pub struct MapModel<M, F> {
    wrapped_model: M,
    map_function: F,
}

impl<M, F, T, U> Model for MapModel<M, F>
where
    M: 'static,
    F: 'static,
    F: Fn(T) -> U,
    M: Model<Data = T>,
{
    type Data = U;

    fn row_count(&self) -> usize {
        self.wrapped_model.row_count()
    }

    fn row_data(&self, row: usize) -> Option<Self::Data> {
        self.wrapped_model.row_data(row).map(|x| (self.map_function)(x))
    }

    fn model_tracker(&self) -> &dyn ModelTracker {
        self.wrapped_model.model_tracker()
    }

    fn as_any(&self) -> &dyn core::any::Any {
        self
    }
}

impl<M, F, T, U> MapModel<M, F>
where
    M: 'static,
    F: 'static,
    F: Fn(T) -> U,
    M: Model<Data = T>,
{
    /// Creates a new MapModel based on the given `wrapped_model` and `map_function`.
    /// Alternatively you can use [`ModelExt::map`] on your Model.
    pub fn new(wrapped_model: M, map_function: F) -> Self {
        Self { wrapped_model, map_function }
    }

    /// Returns a reference to the inner model
    pub fn source_model(&self) -> &M {
        &self.wrapped_model
    }
}

#[test]
fn test_map_model() {
    use alloc::string::ToString;
    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3]));
    let map = MapModel::new(wrapped_rc.clone(), |x| x.to_string());

    wrapped_rc.set_row_data(2, 42);
    wrapped_rc.push(4);

    assert_eq!(map.row_data(2).unwrap(), "42");
    assert_eq!(map.row_data(3).unwrap(), "4");
    assert_eq!(map.row_data(1).unwrap(), "2");
}

struct FilterModelInner<M, F>
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static,
{
    wrapped_model: M,
    filter_function: F,
    // This vector saves the indices of the elements that are not filtered out
    mapping: RefCell<Vec<usize>>,
    notify: ModelNotify,
}

impl<M, F> FilterModelInner<M, F>
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static,
{
    fn build_mapping_vec(&self) {
        let mut mapping = self.mapping.borrow_mut();
        *mapping = (0..self.wrapped_model.row_count())
            .filter_map(|i| {
                self.wrapped_model.row_data(i).and_then(|e| (self.filter_function)(&e).then_some(i))
            })
            .collect();
    }
}

impl<M, F> ModelChangeListener for FilterModelInner<M, F>
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static,
{
    fn row_changed(self: Pin<&Self>, row: usize) {
        let mut mapping = self.mapping.borrow_mut();

        let (index, is_contained) = match mapping.binary_search(&row) {
            Ok(index) => (index, true),
            Err(index) => (index, false),
        };

        let should_be_contained =
            self.wrapped_model.row_data(row).is_some_and(|data| (self.filter_function)(&data));

        if is_contained && should_be_contained {
            drop(mapping);
            self.notify.row_changed(index);
        } else if !is_contained && should_be_contained {
            mapping.insert(index, row);
            drop(mapping);
            self.notify.row_added(index, 1);
        } else if is_contained && !should_be_contained {
            mapping.remove(index);
            drop(mapping);
            self.notify.row_removed(index, 1);
        }
    }

    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
        if count == 0 {
            return;
        }

        let insertion: Vec<usize> = self
            .wrapped_model
            .iter()
            .enumerate()
            .skip(index)
            .take(count)
            .filter_map(|(i, e)| (self.filter_function)(&e).then_some(i))
            .collect();

        let mut mapping = self.mapping.borrow_mut();
        let insertion_point = mapping.binary_search(&index).unwrap_or_else(|ip| ip);
        mapping[insertion_point..].iter_mut().for_each(|i| *i += count);

        if !insertion.is_empty() {
            let insertion_len = insertion.len();
            mapping.splice(insertion_point..insertion_point, insertion);

            drop(mapping);
            self.notify.row_added(insertion_point, insertion_len);
        }
    }

    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
        if count == 0 {
            return;
        }
        let mut mapping = self.mapping.borrow_mut();

        let start = mapping.binary_search(&index).unwrap_or_else(|s| s);
        let end = mapping.binary_search(&(index + count)).unwrap_or_else(|e| e);
        let range = start..end;

        mapping[end..].iter_mut().for_each(|i| *i -= count);

        if !range.is_empty() {
            mapping.drain(range.clone());
            drop(mapping);
            self.notify.row_removed(start, range.len());
        }
    }

    fn reset(self: Pin<&Self>) {
        self.build_mapping_vec();
        self.notify.reset();
    }
}

/// Provides a filtered subset of rows by another [`Model`].
///
/// When the other Model is updated, the `FilterModel` is updated accordingly.
///
/// Generic parameters:
/// * `M` the type of the wrapped `Model`.
/// * `F` the filter function.
///
/// ## Example
///
/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
/// It is then filtered into a `FilterModel`.
///
/// ```
/// # use slint::{Model, VecModel, SharedString, FilterModel};
/// let model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]);
///
/// let filtered_model = FilterModel::new(model, |s| s.contains('o'));
///
/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
/// ```
///
/// Alternatively you can use the shortcut [`ModelExt::filter`].
/// ```
/// # use slint::{Model, ModelExt, VecModel, SharedString, FilterModel};
/// let filtered_model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]).filter(|s| s.contains('o'));
/// # assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
/// # assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
/// ```
///
/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the FilterModel:
/// ```
/// # use std::rc::Rc;
/// # use slint::{Model, VecModel, SharedString, FilterModel};
/// let model = Rc::new(VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]));
///
/// let filtered_model = FilterModel::new(model.clone(), |s| s.contains('o'));
///
/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("dolor"));
///
/// model.set_row_data(1, SharedString::from("opsom"));
///
/// assert_eq!(filtered_model.row_data(0).unwrap(), SharedString::from("Lorem"));
/// assert_eq!(filtered_model.row_data(1).unwrap(), SharedString::from("opsom"));
/// assert_eq!(filtered_model.row_data(2).unwrap(), SharedString::from("dolor"));
/// ```
pub struct FilterModel<M, F>(ModelChangeListenerBox<FilterModelInner<M, F>>)
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static;

impl<M, F> FilterModel<M, F>
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static,
{
    /// Creates a new FilterModel based on the given `wrapped_model` and filtered by `filter_function`.
    /// Alternatively you can use [`ModelExt::filter`] on your Model.
    pub fn new(wrapped_model: M, filter_function: F) -> Self {
        let filter_model_inner = FilterModelInner {
            wrapped_model,
            filter_function,
            mapping: RefCell::new(Vec::new()),
            notify: Default::default(),
        };

        filter_model_inner.build_mapping_vec();

        let container = ModelChangeListenerBox::new(filter_model_inner);

        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());

        Self(container)
    }

    /// Manually reapply the filter. You need to run this e.g. if the filtering function depends on
    /// mutable state and it has changed.
    pub fn reset(&self) {
        self.0.as_ref().get().reset();
    }

    /// Gets the row index of the underlying unfiltered model for a given filtered row index.
    pub fn unfiltered_row(&self, filtered_row: usize) -> usize {
        self.0.mapping.borrow()[filtered_row]
    }

    /// Returns a reference to the inner model
    pub fn source_model(&self) -> &M {
        &self.0.as_ref().get().get_ref().wrapped_model
    }
}

impl<M, F> Model for FilterModel<M, F>
where
    M: Model + 'static,
    F: Fn(&M::Data) -> bool + 'static,
{
    type Data = M::Data;

    fn row_count(&self) -> usize {
        self.0.mapping.borrow().len()
    }

    fn row_data(&self, row: usize) -> Option<Self::Data> {
        self.0
            .mapping
            .borrow()
            .get(row)
            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))
    }

    fn set_row_data(&self, row: usize, data: Self::Data) {
        let wrapped_row = self.0.mapping.borrow()[row];
        self.0.wrapped_model.set_row_data(wrapped_row, data);
    }

    fn model_tracker(&self) -> &dyn ModelTracker {
        &self.0.notify
    }

    fn as_any(&self) -> &dyn core::any::Any {
        self
    }
}

#[test]
fn test_filter_model() {
    use tests_helper::*;
    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4, 5, 6]));
    let filter = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));

    let _checker = ModelChecker::new(filter.clone());

    assert_eq!(filter.row_data(0).unwrap(), 2);
    assert_eq!(filter.row_data(1).unwrap(), 4);
    assert_eq!(filter.row_data(2).unwrap(), 6);
    assert_eq!(filter.row_count(), 3);

    wrapped_rc.remove(1);
    assert_eq!(filter.row_data(0).unwrap(), 4);
    assert_eq!(filter.row_data(1).unwrap(), 6);
    assert_eq!(filter.row_count(), 2);

    wrapped_rc.push(8);
    wrapped_rc.push(7);
    assert_eq!(filter.row_data(0).unwrap(), 4);
    assert_eq!(filter.row_data(1).unwrap(), 6);
    assert_eq!(filter.row_data(2).unwrap(), 8);
    assert_eq!(filter.row_count(), 3);

    wrapped_rc.set_row_data(1, 2);
    assert_eq!(filter.row_data(0).unwrap(), 2);
    assert_eq!(filter.row_data(1).unwrap(), 4);
    assert_eq!(filter.row_data(2).unwrap(), 6);
    assert_eq!(filter.row_data(3).unwrap(), 8);
    assert_eq!(filter.row_count(), 4);

    wrapped_rc.insert(2, 12);
    assert_eq!(filter.row_data(0).unwrap(), 2);
    assert_eq!(filter.row_data(1).unwrap(), 12);
    assert_eq!(filter.row_data(2).unwrap(), 4);
    assert_eq!(filter.row_data(3).unwrap(), 6);
    assert_eq!(filter.row_data(4).unwrap(), 8);
    assert_eq!(filter.row_count(), 5);
}

#[test]
fn test_filter_model_source_model() {
    use tests_helper::*;
    let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
    let model = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));

    let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
    model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

    let _checker = ModelChecker::new(model.clone());

    model.source_model().push(5);
    model.source_model().push(6);

    let expected = &[2, 4, 6];
    assert_eq!(model.row_count(), expected.len());
    for (i, v) in expected.iter().enumerate() {
        assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
    }
}

#[test]
fn test_filter_model_broken_model() {
    use tests_helper::*;
    let wrapped_rc = BrokenModel::new(std::vec![Some(1), Some(2), None, Some(3), None, Some(4)]);
    let model = Rc::new(FilterModel::new(wrapped_rc.clone(), |x| x % 2 == 0));

    assert_eq!(model.row_count(), 2);
    assert_eq!(model.row_data(0), Some(2));
    assert_eq!(model.row_data(1), Some(4));

    wrapped_rc.notify.row_removed(1, 2);
    wrapped_rc.notify.row_added(1, 2);
    wrapped_rc.data.borrow_mut()[1] = None;
    wrapped_rc.data.borrow_mut()[2] = Some(8);
    wrapped_rc.notify.row_changed(1);
    wrapped_rc.notify.row_changed(2);

    assert_eq!(model.row_count(), 2);
    assert_eq!(model.row_data(0), Some(8));
    assert_eq!(model.row_data(1), Some(4));
}

pub trait SortHelper<D> {
    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering;
}

pub struct AscendingSortHelper;

impl<D> SortHelper<D> for AscendingSortHelper
where
    D: core::cmp::Ord,
{
    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {
        lhs.cmp(rhs)
    }
}

impl<F, D> SortHelper<D> for F
where
    F: FnMut(&D, &D) -> core::cmp::Ordering + 'static,
{
    fn cmp(&mut self, lhs: &D, rhs: &D) -> core::cmp::Ordering {
        (self)(lhs, rhs)
    }
}

struct SortModelInner<M, S>
where
    M: Model + 'static,
    S: SortHelper<M::Data> + 'static,
{
    wrapped_model: M,
    sort_helper: RefCell<S>,
    // This vector saves the indices of the elements in sorted order.
    mapping: RefCell<Vec<usize>>,
    notify: ModelNotify,
    sorted_rows_dirty: Cell<bool>,
}

impl<M, S> SortModelInner<M, S>
where
    M: Model + 'static,
    S: SortHelper<M::Data>,
{
    fn build_mapping_vec(&self) {
        if !self.sorted_rows_dirty.get() {
            return;
        }

        let mut mapping = self.mapping.borrow_mut();

        mapping.clear();
        mapping.extend(0..self.wrapped_model.row_count());
        mapping.sort_by(|lhs, rhs| {
            let Some(lhs) = self.wrapped_model.row_data(*lhs) else {
                return core::cmp::Ordering::Greater;
            };
            let Some(rhs) = self.wrapped_model.row_data(*rhs) else {
                return core::cmp::Ordering::Less;
            };
            self.sort_helper.borrow_mut().cmp(&lhs, &rhs)
        });

        self.sorted_rows_dirty.set(false);
    }
}

impl<M, S> ModelChangeListener for SortModelInner<M, S>
where
    M: Model + 'static,
    S: SortHelper<M::Data> + 'static,
{
    fn row_changed(self: Pin<&Self>, row: usize) {
        if self.sorted_rows_dirty.get() {
            self.reset();
            return;
        }

        let mut mapping = self.mapping.borrow_mut();
        let removed_index = mapping.iter().position(|r| *r == row).unwrap();
        mapping.remove(removed_index);

        let insertion_index = if let Some(changed_data) = self.wrapped_model.row_data(row) {
            mapping.partition_point(|existing_row| {
                self.wrapped_model.row_data(*existing_row).is_some_and(|existing| {
                    self.sort_helper.borrow_mut().cmp(&existing, &changed_data)
                        == core::cmp::Ordering::Less
                })
            })
        } else {
            mapping.len()
        };

        mapping.insert(insertion_index, row);

        drop(mapping);

        if insertion_index == removed_index {
            self.notify.row_changed(removed_index);
        } else {
            self.notify.row_removed(removed_index, 1);
            self.notify.row_added(insertion_index, 1);
        }
    }

    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
        if count == 0 {
            return;
        }

        if self.sorted_rows_dirty.get() {
            self.reset();
            return;
        }

        // Adjust the existing sorted row indices to match the updated source model
        for row in self.mapping.borrow_mut().iter_mut() {
            if *row >= index {
                *row += count;
            }
        }

        for row in index..(index + count) {
            let insertion_index = if let Some(added_data) = self.wrapped_model.row_data(row) {
                self.mapping.borrow().partition_point(|existing_row| {
                    self.wrapped_model.row_data(*existing_row).is_some_and(|existing| {
                        self.sort_helper.borrow_mut().cmp(&existing, &added_data)
                            == core::cmp::Ordering::Less
                    })
                })
            } else {
                self.mapping.borrow().len()
            };
            self.mapping.borrow_mut().insert(insertion_index, row);
            self.notify.row_added(insertion_index, 1)
        }
    }

    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
        if count == 0 {
            return;
        }

        if self.sorted_rows_dirty.get() {
            self.reset();
            return;
        }

        let mut removed_rows = Vec::new();

        let mut i = 0;

        loop {
            if i >= self.mapping.borrow().len() {
                break;
            }

            let sort_index = self.mapping.borrow()[i];

            if sort_index >= index {
                if sort_index < index + count {
                    removed_rows.push(i);
                    self.mapping.borrow_mut().remove(i);
                    continue;
                } else {
                    self.mapping.borrow_mut()[i] -= count;
                }
            }

            i += 1;
        }

        for removed_row in removed_rows {
            self.notify.row_removed(removed_row, 1);
        }
    }

    fn reset(self: Pin<&Self>) {
        self.sorted_rows_dirty.set(true);
        self.notify.reset();
    }
}

/// Provides a sorted view of rows by another [`Model`].
///
/// When the other Model is updated, the `Sorted` is updated accordingly.
///
/// Generic parameters:
/// * `M` the type of the wrapped `Model`.
/// * `F` a type that provides an order to model rows. It is constrained by the internal trait `SortHelper`, which is used to sort the model in ascending order if the model data supports it, or by a given sort function.
///
/// ## Example
///
/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
/// It is then sorted into a `SortModel`.
///
/// ```
/// # use slint::{Model, VecModel, SharedString, SortModel};
/// let model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]);
///
/// let sorted_model = SortModel::new(model, |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
///
/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
/// ```
///
/// Alternatively you can use the shortcut [`ModelExt::sort_by`].
/// ```
/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
/// let sorted_model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]).sort_by(|lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
/// # assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// # assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// # assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
/// ```
///
/// It is also possible to get a ascending sorted  `SortModel` order for `core::cmp::Ord` type items.
///
/// ```
/// # use slint::{Model, VecModel, SortModel};
/// let model = VecModel::from(vec![
///     5,
///     1,
///     3,
/// ]);
///
/// let sorted_model = SortModel::new_ascending(model);
///
/// assert_eq!(sorted_model.row_data(0).unwrap(), 1);
/// assert_eq!(sorted_model.row_data(1).unwrap(), 3);
/// assert_eq!(sorted_model.row_data(2).unwrap(), 5);
/// ```
///
/// Alternatively you can use the shortcut [`ModelExt::sort`].
/// ```
/// # use slint::{Model, ModelExt, VecModel, SharedString, SortModel};
/// let sorted_model = VecModel::from(vec![
///     5,
///     1,
///     3,
/// ]).sort();
/// # assert_eq!(sorted_model.row_data(0).unwrap(), 1);
/// # assert_eq!(sorted_model.row_data(1).unwrap(), 3);
/// # assert_eq!(sorted_model.row_data(2).unwrap(), 5);
/// ```
///
/// If you want to modify the underlying [`VecModel`] you can give it a [`Rc`] of the SortModel:
/// ```
/// # use std::rc::Rc;
/// # use slint::{Model, VecModel, SharedString, SortModel};
/// let model = Rc::new(VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]));
///
/// let sorted_model = SortModel::new(model.clone(), |lhs, rhs| lhs.to_lowercase().cmp(&rhs.to_lowercase()));
///
/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("Lorem"));
///
/// model.set_row_data(1, SharedString::from("opsom"));
///
/// assert_eq!(sorted_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(sorted_model.row_data(1).unwrap(), SharedString::from("Lorem"));
/// assert_eq!(sorted_model.row_data(2).unwrap(), SharedString::from("opsom"));
/// ```
pub struct SortModel<M, F>(ModelChangeListenerBox<SortModelInner<M, F>>)
where
    M: Model + 'static,
    F: SortHelper<M::Data> + 'static;

impl<M, F> SortModel<M, F>
where
    M: Model + 'static,
    F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
{
    /// Creates a new SortModel based on the given `wrapped_model` and sorted by `sort_function`.
    /// Alternatively you can use [`ModelExt::sort_by`] on your Model.
    pub fn new(wrapped_model: M, sort_function: F) -> Self
    where
        F: FnMut(&M::Data, &M::Data) -> core::cmp::Ordering + 'static,
    {
        let sorted_model_inner = SortModelInner {
            wrapped_model,
            sort_helper: RefCell::new(sort_function),
            mapping: RefCell::new(Vec::new()),
            notify: Default::default(),
            sorted_rows_dirty: Cell::new(true),
        };

        let container = ModelChangeListenerBox::new(sorted_model_inner);

        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());

        Self(container)
    }
}

impl<M> SortModel<M, AscendingSortHelper>
where
    M: Model + 'static,
    M::Data: core::cmp::Ord,
{
    /// Creates a new SortModel based on the given `wrapped_model` and sorted in ascending order.
    /// Alternatively you can use [`ModelExt::sort`] on your Model.
    pub fn new_ascending(wrapped_model: M) -> Self
    where
        M::Data: core::cmp::Ord,
    {
        let sorted_model_inner = SortModelInner {
            wrapped_model,
            sort_helper: RefCell::new(AscendingSortHelper),
            mapping: RefCell::new(Vec::new()),
            notify: Default::default(),
            sorted_rows_dirty: Cell::new(true),
        };

        let container = ModelChangeListenerBox::new(sorted_model_inner);

        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());

        Self(container)
    }
}

impl<M, S> SortModel<M, S>
where
    M: Model + 'static,
    S: SortHelper<M::Data>,
{
    /// Returns a reference to the inner model
    pub fn source_model(&self) -> &M {
        &self.0.as_ref().get().get_ref().wrapped_model
    }

    /// Manually reapply the sorting. You need to run this e.g. if the sort function depends
    /// on mutable state and it has changed.
    pub fn reset(&self) {
        self.0.as_ref().get().reset();
    }

    /// Gets the row index of the underlying unsorted model for a given sorted row index.
    pub fn unsorted_row(&self, sorted_row: usize) -> usize {
        self.0.build_mapping_vec();
        self.0.mapping.borrow()[sorted_row]
    }
}

impl<M, S> Model for SortModel<M, S>
where
    M: Model + 'static,
    S: SortHelper<M::Data>,
{
    type Data = M::Data;

    fn row_count(&self) -> usize {
        self.0.wrapped_model.row_count()
    }

    fn row_data(&self, row: usize) -> Option<Self::Data> {
        self.0.build_mapping_vec();

        self.0
            .mapping
            .borrow()
            .get(row)
            .and_then(|&wrapped_row| self.0.wrapped_model.row_data(wrapped_row))
    }

    fn set_row_data(&self, row: usize, data: Self::Data) {
        let wrapped_row = self.0.mapping.borrow()[row];
        self.0.wrapped_model.set_row_data(wrapped_row, data);
    }

    fn model_tracker(&self) -> &dyn ModelTracker {
        &self.0.notify
    }

    fn as_any(&self) -> &dyn core::any::Any {
        self
    }
}

#[cfg(test)]
mod sort_tests {
    use super::*;
    use std::vec;
    use tests_helper::*;

    #[test]
    fn test_sorted_model_insert() {
        let wrapped_rc = Rc::new(VecModel::from(std::vec![3, 4, 1, 2]));
        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));

        let _checker = ModelChecker::new(sorted_model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        assert_eq!(sorted_model.row_count(), 4);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
        assert_eq!(sorted_model.row_data(3).unwrap(), 4);

        wrapped_rc.insert(0, 10);

        assert_eq!(observer.added_rows.borrow().len(), 1);
        assert!(observer.added_rows.borrow().eq(&[(4, 1)]));
        assert!(observer.changed_rows.borrow().is_empty());
        assert!(observer.removed_rows.borrow().is_empty());
        assert_eq!(*observer.reset.borrow(), 0);
        observer.clear();

        assert_eq!(sorted_model.row_count(), 5);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
        assert_eq!(sorted_model.row_data(3).unwrap(), 4);
        assert_eq!(sorted_model.row_data(4).unwrap(), 10);
    }

    #[test]
    fn test_sorted_model_remove() {
        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));

        let _checker = ModelChecker::new(sorted_model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        assert_eq!(sorted_model.row_count(), 4);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
        assert_eq!(sorted_model.row_data(3).unwrap(), 4);

        // Remove the entry with the value 4
        wrapped_rc.remove(1);

        assert!(observer.added_rows.borrow().is_empty());
        assert!(observer.changed_rows.borrow().is_empty());
        assert_eq!(observer.removed_rows.borrow().len(), 1);
        assert!(observer.removed_rows.borrow().eq(&[(3, 1)]));
        assert_eq!(*observer.reset.borrow(), 0);
        observer.clear();

        assert_eq!(sorted_model.row_count(), 3);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
    }

    #[test]
    fn test_sorted_model_changed() {
        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
        let sorted_model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));

        let _checker = ModelChecker::new(sorted_model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        sorted_model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        assert_eq!(sorted_model.row_count(), 4);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
        assert_eq!(sorted_model.row_data(3).unwrap(), 4);

        // Change the entry with the value 4 to 10 -> maintain order
        wrapped_rc.set_row_data(1, 10);

        assert!(observer.added_rows.borrow().is_empty());
        assert_eq!(observer.changed_rows.borrow().len(), 1);
        assert_eq!(*observer.changed_rows.borrow().first().unwrap(), 3);
        assert!(observer.removed_rows.borrow().is_empty());
        assert_eq!(*observer.reset.borrow(), 0);
        observer.clear();

        assert_eq!(sorted_model.row_count(), 4);
        assert_eq!(sorted_model.row_data(0).unwrap(), 1);
        assert_eq!(sorted_model.row_data(1).unwrap(), 2);
        assert_eq!(sorted_model.row_data(2).unwrap(), 3);
        assert_eq!(sorted_model.row_data(3).unwrap(), 10);

        // Change the entry with the value 10 to 0 -> new order with remove and insert
        wrapped_rc.set_row_data(1, 0);

        assert_eq!(observer.added_rows.borrow().len(), 1);
        assert!(observer.added_rows.borrow().first().unwrap().eq(&(0, 1)));
        assert!(observer.changed_rows.borrow().is_empty());
        assert_eq!(observer.removed_rows.borrow().len(), 1);
        assert!(observer.removed_rows.borrow().first().unwrap().eq(&(3, 1)));
        assert_eq!(*observer.reset.borrow(), 0);
        observer.clear();

        assert_eq!(sorted_model.row_count(), 4);
        assert_eq!(sorted_model.row_data(0).unwrap(), 0);
        assert_eq!(sorted_model.row_data(1).unwrap(), 1);
        assert_eq!(sorted_model.row_data(2).unwrap(), 2);
        assert_eq!(sorted_model.row_data(3).unwrap(), 3);
    }

    #[test]
    fn test_sorted_model_source_model() {
        let wrapped_rc = Rc::new(VecModel::from(vec![3, 4, 1, 2]));
        let model = Rc::new(SortModel::new(wrapped_rc.clone(), |lhs, rhs| lhs.cmp(rhs)));
        let _checker = ModelChecker::new(model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        model.source_model().push(6);
        model.source_model().push(5);

        let expected = &[1, 2, 3, 4, 5, 6];
        assert_eq!(model.row_count(), expected.len());
        for (i, v) in expected.iter().enumerate() {
            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
        }

        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));
        model.reset();
        assert_eq!(*observer.reset.borrow(), 1);
    }

    #[test]
    fn test_sorted_broken_model() {
        let wrapped_rc = BrokenModel::new(std::vec![
            Some("1"),
            Some("2"),
            None,
            Some("4"),
            None,
            Some("3"),
            Some("0"),
            Some("5")
        ]);
        let model = Rc::new(SortModel::new_ascending(wrapped_rc.clone()));

        assert_eq!(model.row_count(), 8);
        assert_eq!(model.row_data(0), Some("0"));
        assert_eq!(model.row_data(1), Some("1"));
        assert_eq!(model.row_data(2), Some("2"));
        assert_eq!(model.row_data(3), Some("3"));
        assert_eq!(model.row_data(4), Some("4"));
        assert_eq!(model.row_data(5), Some("5"));
        assert_eq!(model.row_data(6), None);
        assert_eq!(model.row_data(7), None);

        wrapped_rc.notify.row_removed(2, 2);
        wrapped_rc.notify.row_added(2, 2);
        wrapped_rc.data.borrow_mut()[1] = None;
        wrapped_rc.notify.row_changed(1);
        wrapped_rc.data.borrow_mut()[2] = Some("a");
        wrapped_rc.notify.row_changed(2);

        assert_eq!(model.row_count(), 8);
        assert_eq!(model.row_data(0), Some("0"));
        assert_eq!(model.row_data(1), Some("1"));
        assert_eq!(model.row_data(2), Some("3"));
        assert_eq!(model.row_data(3), Some("4"));
        assert_eq!(model.row_data(4), Some("5"));
        assert_eq!(model.row_data(5), Some("a"));
        assert_eq!(model.row_data(6), None);
        assert_eq!(model.row_data(7), None);

        assert!(Rc::ptr_eq(model.source_model(), &wrapped_rc));
    }
}

/// Provides a reversed view of another [`Model`].
///
/// When the other Model is updated, the `ReverseModel` is updated accordingly.
///
/// Generic parameters:
/// * `M` the type of the wrapped `Model`.
///
/// ## Example
///
/// Here we have a [`VecModel`] holding [`crate::SharedString`]s.
/// It is then reversed into a `ReverseModel`.
///
/// ```
/// # use slint::{Model, VecModel, SharedString, ReverseModel};
/// let model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]);
///
/// let reverse_model = ReverseModel::new(model);
///
/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
/// ```
///
/// Alternatively you can use the shortcut [`ModelExt::reverse`].
/// ```
/// # use slint::{Model, ModelExt, VecModel, SharedString};
/// let reverse_model = VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]).reverse();
/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
/// ```
///
/// If you want to modify the underlying [`VecModel`] you can give the ReverseModel a [`Rc`] of it:
/// ```
/// # use std::rc::Rc;
/// # use slint::{Model, VecModel, SharedString, ReverseModel};
/// let model = Rc::new(VecModel::from(vec![
///     SharedString::from("Lorem"),
///     SharedString::from("ipsum"),
///     SharedString::from("dolor"),
/// ]));
///
/// let reverse_model = ReverseModel::new(model.clone());
///
/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("dolor"));
/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("Lorem"));
///
/// model.push(SharedString::from("opsom"));
///
/// assert_eq!(reverse_model.row_data(0).unwrap(), SharedString::from("opsom"));
/// assert_eq!(reverse_model.row_data(1).unwrap(), SharedString::from("dolor"));
/// assert_eq!(reverse_model.row_data(2).unwrap(), SharedString::from("ipsum"));
/// assert_eq!(reverse_model.row_data(3).unwrap(), SharedString::from("Lorem"));
/// ```
pub struct ReverseModel<M>(ModelChangeListenerBox<ReverseModelInner<M>>)
where
    M: Model + 'static;

struct ReverseModelInner<M>
where
    M: Model + 'static,
{
    wrapped_model: M,
    notify: ModelNotify,
}

impl<M> ModelChangeListener for ReverseModelInner<M>
where
    M: Model + 'static,
{
    fn row_changed(self: Pin<&Self>, row: usize) {
        self.notify.row_changed(self.wrapped_model.row_count() - 1 - row);
    }

    fn row_added(self: Pin<&Self>, index: usize, count: usize) {
        let row_count = self.wrapped_model.row_count();
        let old_row_count = row_count - count;
        let index = old_row_count - index;
        self.notify.row_added(index, count);
    }

    fn row_removed(self: Pin<&Self>, index: usize, count: usize) {
        let row_count = self.wrapped_model.row_count();
        self.notify.row_removed(row_count - index, count);
    }

    fn reset(self: Pin<&Self>) {
        self.notify.reset()
    }
}

impl<M> ReverseModel<M>
where
    M: Model + 'static,
{
    /// Creates a new ReverseModel based on the given `wrapped_model`.
    /// Alternatively you can use [`ModelExt::reverse`] on your Model.
    pub fn new(wrapped_model: M) -> Self {
        let inner = ReverseModelInner { wrapped_model, notify: Default::default() };
        let container = ModelChangeListenerBox::new(inner);
        container.wrapped_model.model_tracker().attach_peer(container.as_ref().model_peer());
        Self(container)
    }

    /// Returns a reference to the inner model
    pub fn source_model(&self) -> &M {
        &self.0.as_ref().get().get_ref().wrapped_model
    }
}

impl<M> Model for ReverseModel<M>
where
    M: Model + 'static,
{
    type Data = M::Data;

    fn row_count(&self) -> usize {
        self.0.wrapped_model.row_count()
    }

    fn row_data(&self, row: usize) -> Option<Self::Data> {
        let count = self.0.wrapped_model.row_count();
        self.0.wrapped_model.row_data(count.checked_sub(row + 1)?)
    }
    fn set_row_data(&self, row: usize, data: Self::Data) {
        let count = self.0.as_ref().wrapped_model.row_count();
        self.0.wrapped_model.set_row_data(count - row - 1, data);
    }

    fn model_tracker(&self) -> &dyn ModelTracker {
        &self.0.notify
    }

    fn as_any(&self) -> &dyn core::any::Any {
        self
    }
}

#[cfg(test)]
mod reversed_tests {
    use super::*;
    use std::vec;
    use tests_helper::*;

    #[track_caller]
    fn check_content(model: &ReverseModel<Rc<VecModel<i32>>>, expected: &[i32]) {
        assert_eq!(model.row_count(), expected.len());
        for (i, v) in expected.iter().enumerate() {
            assert_eq!(model.row_data(i), Some(*v), "Expected {v} at index {i}");
        }
    }

    #[test]
    fn test_reversed_model() {
        let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
        let _checker = ModelChecker::new(model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        check_content(&model, &[4, 3, 2, 1]);
    }

    #[test]
    fn test_reversed_model_insert() {
        for (idx, mapped_idx) in [(0, 4), (1, 3), (2, 2), (3, 1), (4, 0)] {
            std::println!("Inserting at {idx} expecting mapped to {mapped_idx}");
            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
            let _checker = ModelChecker::new(model.clone());

            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

            wrapped_rc.insert(idx, 10);

            assert_eq!(observer.added_rows.borrow().len(), 1);
            assert!(
                observer.added_rows.borrow().eq(&[(mapped_idx, 1)]),
                "Added rows: {:?}",
                observer.added_rows.borrow()
            );
            assert!(observer.changed_rows.borrow().is_empty());
            assert!(observer.removed_rows.borrow().is_empty());
            assert_eq!(*observer.reset.borrow(), 0);
            assert_eq!(model.row_data(mapped_idx), Some(10));
        }
    }

    #[test]
    fn test_reversed_model_remove() {
        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
            std::println!("Removing at {idx} expecting mapped to {mapped_idx}");
            let wrapped_rc = Rc::new(VecModel::from(vec![1, 2, 3, 4]));
            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
            let _checker = ModelChecker::new(model.clone());

            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

            wrapped_rc.remove(idx);

            assert_eq!(observer.removed_rows.borrow().len(), 1);
            assert!(
                observer.removed_rows.borrow().eq(&[(mapped_idx, 1)]),
                "Remove rows: {:?}",
                observer.removed_rows.borrow()
            );
            assert!(observer.added_rows.borrow().is_empty());
            assert!(observer.changed_rows.borrow().is_empty());
            assert_eq!(*observer.reset.borrow(), 0);
        }
    }

    #[test]
    fn test_reversed_model_changed() {
        for (idx, mapped_idx) in [(0, 3), (1, 2), (2, 1), (3, 0)] {
            std::println!("Changing at {idx} expecting mapped to {mapped_idx}");
            let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
            let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
            let _checker = ModelChecker::new(model.clone());

            let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
            model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

            wrapped_rc.set_row_data(idx, 10);

            assert_eq!(observer.changed_rows.borrow().len(), 1);
            assert!(
                observer.changed_rows.borrow().eq(&[mapped_idx]),
                "Changed rows: {:?}",
                observer.changed_rows.borrow()
            );
            assert!(observer.added_rows.borrow().is_empty());
            assert!(observer.removed_rows.borrow().is_empty());
            assert_eq!(*observer.reset.borrow(), 0);
            assert_eq!(model.row_data(mapped_idx), Some(10));
        }
    }

    #[test]
    fn test_reversed_model_source_model() {
        let wrapped_rc = Rc::new(VecModel::from(std::vec![1, 2, 3, 4]));
        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));
        let _checker = ModelChecker::new(model.clone());

        let observer = Box::pin(ModelChangeListenerContainer::<TestView>::default());
        model.model_tracker().attach_peer(Pin::as_ref(&observer).model_peer());

        model.source_model().push(5);

        check_content(&model, &[5, 4, 3, 2, 1]);
    }

    #[test]
    fn test_reversed_broken_model() {
        let wrapped_rc = BrokenModel::new(std::vec![Some("1"), Some("2"), None, Some("4")]);
        let model = Rc::new(ReverseModel::new(wrapped_rc.clone()));

        wrapped_rc.notify.row_added(1, 3);

        assert_eq!(model.row_count(), 4);
        assert_eq!(model.row_data(0), Some("4"));
        assert_eq!(model.row_data(1), None);
        assert_eq!(model.row_data(2), Some("2"));
        assert_eq!(model.row_data(3), Some("1"));
    }
}

#[test]
fn test_long_chain_integrity() {
    use alloc::string::ToString;
    use tests_helper::*;
    let origin_model = Rc::new(VecModel::from((0..100).collect::<Vec<_>>()));
    let checker1 = ModelChecker::new(origin_model.clone());
    let fizzbuzz = Rc::new(MapModel::new(origin_model.clone(), |number| {
        if (number % 3) == 0 && (number % 5) == 0 {
            "FizzBuzz".to_string()
        } else if (number % 3) == 0 {
            "Fizz".to_string()
        } else if (number % 5) == 0 {
            "Buzz".to_string()
        } else {
            number.to_string()
        }
    }));
    let checker2 = ModelChecker::new(fizzbuzz.clone());
    let filter = Rc::new(FilterModel::new(fizzbuzz, |s| s != "FizzBuzz"));
    let checker3 = ModelChecker::new(filter.clone());
    let reverse = Rc::new(ReverseModel::new(filter));
    let checker4 = ModelChecker::new(reverse.clone());
    let sorted = Rc::new(SortModel::new_ascending(reverse));
    let checker5 = ModelChecker::new(sorted.clone());
    let filter2 = Rc::new(FilterModel::new(sorted, |s| s != "Fizz"));
    let checker6 = ModelChecker::new(filter2.clone());

    let check_all = || {
        checker1.check();
        checker2.check();
        checker3.check();
        checker4.check();
        checker5.check();
        checker6.check();
    };

    origin_model.extend(50..150);
    check_all();
    origin_model.insert(8, 1000);
    check_all();
    origin_model.remove(9);
    check_all();
    origin_model.remove(10);
    origin_model.remove(11);
    origin_model.set_row_data(55, 10001);
    check_all();
    origin_model.set_row_data(58, 10002);
    origin_model.set_row_data(59, 10003);
    origin_model.remove(28);
    origin_model.remove(29);
    origin_model.insert(100, 8888);
    origin_model.remove(30);
    origin_model.set_row_data(60, 10004);
    origin_model.remove(130);
    origin_model.set_row_data(61, 10005);
    origin_model.remove(131);
    check_all();
    origin_model.remove(12);
    origin_model.remove(13);
    origin_model.remove(14);
    origin_model.set_row_data(62, 10006);
    origin_model.set_row_data(63, 10007);
    origin_model.set_row_data(64, 10008);
    origin_model.set_row_data(65, 10009);
    check_all();

    // Since VecModel don't have this as public API, just add some function that use row_removed on a wider range.
    trait RemoveRange {
        fn remove_range(&self, range: core::ops::Range<usize>);
    }
    impl<T> RemoveRange for VecModel<T> {
        fn remove_range(&self, range: core::ops::Range<usize>) {
            self.array.borrow_mut().drain(range.clone());
            self.notify.row_removed(range.start, range.len())
        }
    }

    origin_model.remove_range(25..110);
    check_all();

    origin_model.extend(900..910);
    origin_model.set_row_data(45, 44444);
    origin_model.remove_range(10..30);
    origin_model.insert(45, 3000);
    origin_model.insert(45, 3001);
    origin_model.insert(45, 3002);
    origin_model.insert(45, 3003);
    origin_model.insert(45, 3004);
    origin_model.insert(45, 3006);
    origin_model.insert(45, 3007);
    check_all();
}
