//! Types for storing and interacting with values in Widgets.

use std::collections::HashMap;
use std::fmt::{Debug, Display};
use std::future::Future;
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, DerefMut, Not};
use std::panic::UnwindSafe;
use std::str::FromStr;
use std::sync::atomic::{self, AtomicBool};
use std::sync::{Arc, Mutex, MutexGuard, TryLockError};
use std::task::{Poll, Waker};
use std::thread::ThreadId;
use std::time::Duration;

use ahash::AHashSet;
use kempt::{Map, Sort};

use crate::animation::{AnimationHandle, DynamicTransition, IntoAnimate, LinearInterpolate, Spawn};
use crate::context::sealed::WindowHandle;
use crate::context::{self, WidgetContext};
use crate::utils::{run_in_bg, IgnorePoison, UnwindsafeCondvar, WithClone};
use crate::widget::{Children, MakeWidget, MakeWidgetWithId, WidgetId, WidgetInstance};
use crate::widgets::{Radio, Select, Space, Switcher};

/// An instance of a value that provides APIs to observe and react to its
/// contents.
#[derive(Debug)]
pub struct Dynamic<T>(Arc<DynamicData<T>>);

impl<T> Dynamic<T> {
    /// Creates a new instance wrapping `value`.
    pub fn new(value: T) -> Self {
        Self(Arc::new(DynamicData {
            state: Mutex::new(State {
                wrapped: GenerationalValue {
                    value,
                    generation: Generation::default(),
                },
                callbacks: Arc::default(),
                windows: AHashSet::new(),
                readers: 0,
                wakers: Vec::new(),
                widgets: AHashSet::new(),
            }),
            during_callback_state: Mutex::default(),
            sync: UnwindsafeCondvar::default(),
        }))
    }

    /// Returns a new dynamic that has its contents linked with `self` by the
    /// pair of mapping functions provided.
    ///
    /// When the returned dynamic is updated, `r_into_t` will be invoked. This
    /// function accepts `&R` and can return `T`, or `Option<T>`. If a value is
    /// produced, `self` will be updated with the new value.
    ///
    /// When `self` is updated, `t_into_r` will be invoked. This function
    /// accepts `&T` and can return `R` or `Option<R>`. If a value is produced,
    /// the returned dynamic will be updated with the new value.
    ///
    /// # Panics
    ///
    /// This function panics if calling `t_into_r` with the current contents of
    /// the Dynamic produces a `None` value. This requirement is only for the
    /// first invocation, and it is guaranteed to occur before this function
    /// returns.
    pub fn linked<R, TIntoR, TIntoRResult, RIntoT, RIntoTResult>(
        &self,
        mut t_into_r: TIntoR,
        mut r_into_t: RIntoT,
    ) -> Dynamic<R>
    where
        T: PartialEq + Send + 'static,
        R: PartialEq + Send + 'static,
        TIntoRResult: Into<Option<R>> + Send + 'static,
        RIntoTResult: Into<Option<T>> + Send + 'static,
        TIntoR: FnMut(&T) -> TIntoRResult + Send + 'static,
        RIntoT: FnMut(&R) -> RIntoTResult + Send + 'static,
    {
        let initial_r = self
            .map_ref(|v| t_into_r(v))
            .into()
            .expect("t_into_r must succeed with the current value");
        let r = Dynamic::new(initial_r);
        r.with_clone(move |r| {
            self.for_each(move |t| {
                if let Some(update) = t_into_r(t).into() {
                    let _result = r.replace(update);
                }
            });
        });

        self.with_clone(|t| {
            r.with_for_each(move |r| {
                if let Some(update) = r_into_t(r).into() {
                    let _result = t.replace(update);
                }
            })
        })
    }

    /// Creates a [linked](Self::linked) dynamic containing a `String`.
    ///
    /// When `self` is updated, [`ToString::to_string()`] will be called to
    /// produce a new string value to store in the returned dynamic.
    ///
    /// When the returned dynamic is updated, [`str::parse`](std::str) is called
    /// to produce a new `T`. If an error is returned, `self` will not be
    /// updated. Otherwise, `self` will be updated with the produced value.
    #[must_use]
    pub fn linked_string(&self) -> Dynamic<String>
    where
        T: ToString + FromStr + PartialEq + Send + 'static,
    {
        self.linked(ToString::to_string, |s: &String| s.parse().ok())
    }

    /// Maps the contents with read-only access.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    pub fn map_ref<R>(&self, map: impl FnOnce(&T) -> R) -> R {
        self.map_generational(|gen| map(&gen.value))
    }

    /// Maps the contents with read-only access, providing access to the value's
    /// [`Generation`].
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    pub fn map_generational<R>(&self, map: impl FnOnce(&GenerationalValue<T>) -> R) -> R {
        let state = self.state().expect("deadlocked");
        map(&state.wrapped)
    }

    /// Maps the contents with exclusive access. Before returning from this
    /// function, all observers will be notified that the contents have been
    /// updated.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    pub fn map_mut<R>(&self, map: impl FnOnce(&mut T) -> R) -> R {
        self.0.map_mut(|value, _| map(value)).expect("deadlocked")
    }

    /// Updates the value to the result of invoking [`Not`] on the current
    /// value. This function returns the new value.
    #[allow(clippy::must_use_candidate)]
    pub fn toggle(&self) -> T
    where
        T: Not<Output = T> + Clone,
    {
        self.map_mut(|value| {
            *value = !value.clone();
            value.clone()
        })
    }

    /// Returns a new dynamic that contains the updated contents of this dynamic
    /// at most once every `period`.
    #[must_use]
    pub fn debounced_every(&self, period: Duration) -> Self
    where
        T: PartialEq + Clone + Send + Sync + 'static,
    {
        let debounced = Dynamic::new(self.get());
        let mut debounce = Debounce::new(debounced.clone(), period);
        self.for_each_cloned(move |value| debounce.update(value));
        debounced
    }

    /// Returns a new dynamic that contains the updated contents of this dynamic
    /// delayed by `period`. Each time this value is updated, the delay is
    /// reset.
    #[must_use]
    pub fn debounced_with_delay(&self, period: Duration) -> Self
    where
        T: PartialEq + Clone + Send + Sync + 'static,
    {
        let debounced = Dynamic::new(self.get());
        let mut debounce = Debounce::new(debounced.clone(), period).extending();
        self.for_each_cloned(move |value| debounce.update(value));
        debounced
    }

    /// Returns a new dynamic that is updated using `U::from(T.clone())` each
    /// time `self` is updated.
    #[must_use]
    pub fn map_each_into<U>(&self) -> Dynamic<U>
    where
        U: PartialEq + From<T> + Send + 'static,
        T: Clone + Send + 'static,
    {
        self.map_each(|value| U::from(value.clone()))
    }

    /// Returns a new dynamic that is updated using `U::from(&T)` each
    /// time `self` is updated.
    #[must_use]
    pub fn map_each_to<U>(&self) -> Dynamic<U>
    where
        U: PartialEq + for<'a> From<&'a T> + Send + 'static,
        T: Clone + Send + 'static,
    {
        self.map_each(|value| U::from(value))
    }

    /// Attaches `for_each` to this value so that it is invoked each time the
    /// value's contents are updated.
    pub fn for_each<F>(&self, mut for_each: F)
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a T) + Send + 'static,
    {
        let this = self.clone();
        self.0.for_each(move || {
            this.map_ref(&mut for_each);
        });
    }

    /// Attaches `for_each` to this value and its [`Generation`] so that it is
    /// invoked each time the value's contents are updated.
    pub fn for_each_generational<F>(&self, mut for_each: F)
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a GenerationalValue<T>) + Send + 'static,
    {
        let this = self.clone();
        self.0.for_each(move || {
            this.map_generational(&mut for_each);
        });
    }

    /// Attaches `for_each` to this value so that it is invoked each time the
    /// value's contents are updated.
    pub fn for_each_cloned<F>(&self, mut for_each: F)
    where
        T: Clone + Send + 'static,
        F: FnMut(T) + Send + 'static,
    {
        let this = self.clone();
        self.0.for_each(move || {
            for_each(this.get());
        });
    }

    /// Attaches `for_each` to this value so that it is invoked each time the
    /// value's contents are updated. This function returns `self`.
    #[must_use]
    pub fn with_for_each<F>(self, for_each: F) -> Self
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a T) + Send + 'static,
    {
        self.for_each(for_each);
        self
    }

    /// Creates a new dynamic value that contains the result of invoking `map`
    /// each time this value is changed.
    pub fn map_each<R, F>(&self, mut map: F) -> Dynamic<R>
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a T) -> R + Send + 'static,
        R: PartialEq + Send + 'static,
    {
        let this = self.clone();
        self.0.map_each(move || this.map_ref(&mut map))
    }

    /// Creates a new dynamic value that contains the result of invoking `map`
    /// each time this value is changed.
    pub fn map_each_generational<R, F>(&self, mut map: F) -> Dynamic<R>
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a GenerationalValue<T>) -> R + Send + 'static,
        R: PartialEq + Send + 'static,
    {
        let this = self.clone();
        self.0.map_each(move || this.map_generational(&mut map))
    }

    /// Creates a new dynamic value that contains the result of invoking `map`
    /// each time this value is changed.
    pub fn map_each_cloned<R, F>(&self, mut map: F) -> Dynamic<R>
    where
        T: Clone + Send + 'static,
        F: FnMut(T) -> R + Send + 'static,
        R: PartialEq + Send + 'static,
    {
        let this = self.clone();
        self.0.map_each(move || map(this.get()))
    }

    /// A helper function that invokes `with_clone` with a clone of self. This
    /// code may produce slightly more readable code.
    ///
    /// ```rust
    /// let value = gooey::value::Dynamic::new(1);
    ///
    /// // Using with_clone
    /// value.with_clone(|value| {
    ///     std::thread::spawn(move || {
    ///         println!("{}", value.get());
    ///     })
    /// });
    ///
    /// // Using an explicit clone
    /// std::thread::spawn({
    ///     let value = value.clone();
    ///     move || {
    ///         println!("{}", value.get());
    ///     }
    /// });
    ///
    /// println!("{}", value.get());
    /// ````
    pub fn with_clone<R>(&self, with_clone: impl FnOnce(Self) -> R) -> R {
        with_clone(self.clone())
    }

    pub(crate) fn redraw_when_changed(&self, window: WindowHandle) {
        self.0.redraw_when_changed(window);
    }

    pub(crate) fn invalidate_when_changed(&self, window: WindowHandle, widget: WidgetId) {
        self.0.invalidate_when_changed(window, widget);
    }

    /// Returns a clone of the currently contained value.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.0.get().expect("deadlocked").value
    }

    /// Returns a clone of the currently contained value.
    ///
    /// `context` will be invalidated when the value is updated.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get_tracking_refresh(&self, context: &WidgetContext<'_, '_>) -> T
    where
        T: Clone,
    {
        context.redraw_when_changed(self);
        self.get()
    }

    /// Returns a clone of the currently contained value.
    ///
    /// `context` will be invalidated when the value is updated.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get_tracking_invalidate(&self, context: &WidgetContext<'_, '_>) -> T
    where
        T: Clone,
    {
        context.invalidate_when_changed(self);
        self.get()
    }

    /// Returns the currently stored value, replacing the current contents with
    /// `T::default()`.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn take(&self) -> T
    where
        T: Default,
    {
        std::mem::take(&mut self.lock())
    }

    /// Checks if the currently stored value is different than `T::default()`,
    /// and if so, returns `Some(self.take())`.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn take_if_not_default(&self) -> Option<T>
    where
        T: Default + PartialEq,
    {
        let default = T::default();
        let mut guard = self.lock();
        if *guard == default {
            None
        } else {
            Some(std::mem::replace(&mut guard, default))
        }
    }

    /// Replaces the contents with `new_value`, returning the previous contents.
    /// Before returning from this function, all observers will be notified that
    /// the contents have been updated.
    ///
    /// If the calling thread has exclusive access to the contents of this
    /// dynamic, this call will return None and the value will not be updated.
    /// If detecting this is important, use [`Self::try_replace()`].
    pub fn replace(&self, new_value: T) -> Option<T>
    where
        T: PartialEq,
    {
        self.try_replace(new_value).ok()
    }

    /// Replaces the contents with `new_value` if `new_value` is different than
    /// the currently stored value. If the value is updated, the previous
    /// contents are returned.
    ///
    ///
    /// Before returning from this function, all observers will be notified that
    /// the contents have been updated.
    ///
    /// # Errors
    ///
    /// - [`ReplaceError::NoChange`]: Returned when `new_value` is equal to the
    /// currently stored value.
    /// - [`ReplaceError::Deadlock`]: Returned when the current thread already
    ///       has exclusive access to the contents of this dynamic.
    pub fn try_replace(&self, new_value: T) -> Result<T, ReplaceError<T>>
    where
        T: PartialEq,
    {
        match self.0.map_mut(|value, changed| {
            if *value == new_value {
                *changed = false;
                Err(ReplaceError::NoChange(new_value))
            } else {
                Ok(std::mem::replace(value, new_value))
            }
        }) {
            Ok(old) => old,
            Err(_) => Err(ReplaceError::Deadlock),
        }
    }

    /// Stores `new_value` in this dynamic. Before returning from this function,
    /// all observers will be notified that the contents have been updated.
    ///
    /// If the calling thread has exclusive access to the contents of this
    /// dynamic, this call will return None and the value will not be updated.
    /// If detecting this is important, use [`Self::try_replace()`].
    pub fn set(&self, new_value: T)
    where
        T: PartialEq,
    {
        let _old = self.replace(new_value);
    }

    /// Returns a new reference-based reader for this dynamic value.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn create_reader(&self) -> DynamicReader<T> {
        self.state().expect("deadlocked").readers += 1;
        DynamicReader {
            source: self.0.clone(),
            read_generation: self.0.state().expect("deadlocked").wrapped.generation,
        }
    }

    /// Converts this [`Dynamic`] into a reader.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn into_reader(self) -> DynamicReader<T> {
        self.create_reader()
    }

    /// Returns an exclusive reference to the contents of this dynamic.
    ///
    /// This call will block until all other guards for this dynamic have been
    /// dropped.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn lock(&self) -> DynamicGuard<'_, T> {
        DynamicGuard {
            guard: self.0.state().expect("deadlocked"),
            accessed_mut: false,
        }
    }

    fn state(&self) -> Result<DynamicMutexGuard<'_, T>, DeadlockError> {
        self.0.state()
    }

    /// Returns the current generation of the value.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn generation(&self) -> Generation {
        self.state().expect("deadlocked").wrapped.generation
    }

    /// Returns a pending transition for this value to `new_value`.
    pub fn transition_to(&self, new_value: T) -> DynamicTransition<T>
    where
        T: LinearInterpolate + Clone + Send + Sync,
    {
        DynamicTransition {
            dynamic: self.clone(),
            new_value,
        }
    }

    /// Returns a new [`Radio`] that updates this dynamic to `widget_value` when
    /// pressed. `label` is drawn next to the checkbox and is also clickable to
    /// select the radio.
    #[must_use]
    pub fn new_radio(&self, widget_value: T, label: impl MakeWidget) -> Radio<T>
    where
        Self: Clone,
        // Technically this trait bound isn't necessary, but it prevents trying
        // to call new_radio on unsupported types. The MakeWidget/Widget
        // implementations require these bounds (and more).
        T: Clone + Eq,
    {
        Radio::new(widget_value, self.clone(), label)
    }

    /// Returns a new [`Select`] that updates this dynamic to `widget_value`
    /// when pressed. `label` is drawn next to the checkbox and is also
    /// clickable to select the widget.
    #[must_use]
    pub fn new_select(&self, widget_value: T, label: impl MakeWidget) -> Select<T>
    where
        Self: Clone,
        // Technically this trait bound isn't necessary, but it prevents trying
        // to call new_select on unsupported types. The MakeWidget/Widget
        // implementations require these bounds (and more).
        T: Clone + Eq,
    {
        Select::new(widget_value, self.clone(), label)
    }

    /// Validates the contents of this dynamic using the `check` function,
    /// returning a dynamic that contains the validation status.
    #[must_use]
    pub fn validate_with<E, Valid>(&self, mut check: Valid) -> Dynamic<Validation>
    where
        T: Send + 'static,
        Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static,
        E: Display,
    {
        let validation = Dynamic::new(Validation::None);
        self.for_each({
            let validation = validation.clone();
            move |value| {
                validation.set(match check(value) {
                    Ok(()) => Validation::Valid,
                    Err(err) => Validation::Invalid(err.to_string()),
                });
            }
        });
        validation
    }
}

impl Dynamic<WidgetInstance> {
    /// Returns a new [`Switcher`] widget whose contents is the value of this
    /// dynamic.
    #[must_use]
    pub fn switcher(self) -> Switcher {
        Switcher::new(self)
    }
}

impl MakeWidgetWithId for Dynamic<WidgetInstance> {
    fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
        self.switcher().make_with_id(id)
    }
}

impl MakeWidgetWithId for Dynamic<Option<WidgetInstance>> {
    fn make_with_id(self, id: crate::widget::WidgetTag) -> WidgetInstance {
        self.map_each(|widget| {
            widget
                .as_ref()
                .map_or_else(|| Space::clear().make_widget(), Clone::clone)
        })
        .make_with_id(id)
    }
}

impl<T> context::sealed::Trackable for Dynamic<T> {
    fn redraw_when_changed(&self, handle: WindowHandle) {
        self.redraw_when_changed(handle);
    }

    fn invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) {
        self.invalidate_when_changed(handle, id);
    }
}

impl<T> PartialEq for Dynamic<T> {
    fn eq(&self, other: &Self) -> bool {
        Arc::ptr_eq(&self.0, &other.0)
    }
}

impl<T> Default for Dynamic<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<T> Clone for Dynamic<T> {
    fn clone(&self) -> Self {
        Self(self.0.clone())
    }
}

impl<T> Drop for Dynamic<T> {
    fn drop(&mut self) {
        let state = self.state().expect("deadlocked");
        if state.readers == 0 {
            drop(state);
            self.0.sync.notify_all();
        }
    }
}

impl<T> From<Dynamic<T>> for DynamicReader<T> {
    fn from(value: Dynamic<T>) -> Self {
        value.create_reader()
    }
}

impl From<&str> for Dynamic<String> {
    fn from(value: &str) -> Self {
        Dynamic::from(value.to_string())
    }
}

impl From<String> for Dynamic<String> {
    fn from(value: String) -> Self {
        Dynamic::new(value)
    }
}

#[derive(Debug)]
struct DynamicMutexGuard<'a, T> {
    dynamic: &'a DynamicData<T>,
    guard: MutexGuard<'a, State<T>>,
}

impl<'a, T> Drop for DynamicMutexGuard<'a, T> {
    fn drop(&mut self) {
        let mut during_state = self.dynamic.during_callback_state.lock().ignore_poison();
        *during_state = None;
        drop(during_state);
        self.dynamic.sync.notify_all();
    }
}

impl<'a, T> Deref for DynamicMutexGuard<'a, T> {
    type Target = State<T>;

    fn deref(&self) -> &Self::Target {
        &self.guard
    }
}
impl<'a, T> DerefMut for DynamicMutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.guard
    }
}

#[derive(Debug)]
struct LockState {
    locked_thread: ThreadId,
}

#[derive(Debug)]
struct DynamicData<T> {
    state: Mutex<State<T>>,
    during_callback_state: Mutex<Option<LockState>>,
    sync: UnwindsafeCondvar,
}

impl<T> DynamicData<T> {
    fn state(&self) -> Result<DynamicMutexGuard<'_, T>, DeadlockError> {
        let mut during_sync = self.during_callback_state.lock().ignore_poison();

        let current_thread_id = std::thread::current().id();
        let guard = loop {
            match self.state.try_lock() {
                Ok(g) => break g,
                Err(TryLockError::Poisoned(poision)) => break poision.into_inner(),
                Err(TryLockError::WouldBlock) => loop {
                    match &*during_sync {
                        Some(state) if state.locked_thread == current_thread_id => {
                            return Err(DeadlockError)
                        }
                        Some(_) => {
                            during_sync = self.sync.wait(during_sync).ignore_poison();
                        }
                        None => break,
                    }
                },
            }
        };
        *during_sync = Some(LockState {
            locked_thread: current_thread_id,
        });
        Ok(DynamicMutexGuard {
            dynamic: self,
            guard,
        })
    }

    pub fn redraw_when_changed(&self, window: WindowHandle) {
        let mut state = self.state().expect("deadlocked");
        state.windows.insert(window);
    }

    pub fn invalidate_when_changed(&self, window: WindowHandle, widget: WidgetId) {
        let mut state = self.state().expect("deadlocked");
        state.widgets.insert((window, widget));
    }

    pub fn get(&self) -> Result<GenerationalValue<T>, DeadlockError>
    where
        T: Clone,
    {
        self.state().map(|state| state.wrapped.clone())
    }

    pub fn map_mut<R>(&self, map: impl FnOnce(&mut T, &mut bool) -> R) -> Result<R, DeadlockError> {
        let mut state = self.state()?;
        let (old, callbacks) = {
            let state = &mut *state;
            let mut changed = true;
            let result = map(&mut state.wrapped.value, &mut changed);
            let callbacks = changed.then(|| state.note_changed());

            (result, callbacks)
        };
        drop(state);
        drop(callbacks);

        self.sync.notify_all();

        Ok(old)
    }

    pub fn for_each<F>(&self, map: F)
    where
        F: for<'a> FnMut() + Send + 'static,
    {
        let state = self.state().expect("deadlocked");
        let mut callbacks = state.callbacks.callbacks.lock().ignore_poison();
        callbacks.push(Box::new(map));
    }

    pub fn map_each<R, F>(&self, mut map: F) -> Dynamic<R>
    where
        F: for<'a> FnMut() -> R + Send + 'static,
        R: PartialEq + Send + 'static,
    {
        let initial_value = map();
        let mapped_value = Dynamic::new(initial_value);
        let returned = mapped_value.clone();

        self.for_each(move || {
            mapped_value.set(map());
        });

        returned
    }
}

/// An error occurred while updating a value in a [`Dynamic`].
pub enum ReplaceError<T> {
    /// The value was already equal to the one set.
    NoChange(T),
    /// The current thread already has exclusive access to this dynamic.
    Deadlock,
}

/// A deadlock occurred accessing a [`Dynamic`].
///
/// Currently Gooey is only able to detect deadlocks where a single thread tries
/// to lock the same [`Dynamic`] multiple times.
#[derive(Debug)]
struct DeadlockError;

impl std::error::Error for DeadlockError {}

impl Display for DeadlockError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str("a deadlock was detected")
    }
}

struct State<T> {
    wrapped: GenerationalValue<T>,
    callbacks: Arc<ChangeCallbacksData>,
    windows: AHashSet<WindowHandle>,
    widgets: AHashSet<(WindowHandle, WidgetId)>,
    wakers: Vec<Waker>,
    readers: usize,
}

impl<T> State<T> {
    fn note_changed(&mut self) -> ChangeCallbacks {
        self.wrapped.generation = self.wrapped.generation.next();

        for (window, widget) in self.widgets.drain() {
            window.invalidate(widget);
        }
        for window in self.windows.drain() {
            window.redraw();
        }
        for waker in self.wakers.drain(..) {
            waker.wake();
        }

        ChangeCallbacks(self.callbacks.clone())
    }
}

impl<T> Debug for State<T>
where
    T: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("State")
            .field("wrapped", &self.wrapped)
            .field("readers", &self.readers)
            .finish_non_exhaustive()
    }
}

#[derive(Default)]
struct ChangeCallbacksData {
    callbacks: Mutex<Vec<Box<dyn ValueCallback>>>,
    currently_executing: AtomicBool,
}

struct ChangeCallbacks(Arc<ChangeCallbacksData>);

impl Drop for ChangeCallbacks {
    fn drop(&mut self) {
        if self
            .0
            .currently_executing
            .compare_exchange(
                false,
                true,
                atomic::Ordering::Release,
                atomic::Ordering::Acquire,
            )
            .is_ok()
        {
            let mut callbacks = self.0.callbacks.lock().ignore_poison();
            for callback in &mut *callbacks {
                callback.changed();
            }
            self.0
                .currently_executing
                .store(false, atomic::Ordering::Release);
        } else {
            tracing::warn!("Could not invoke dynamic callbacks because they are already running on this thread");
        }
    }
}

trait ValueCallback: Send {
    fn changed(&mut self);
}

impl<F> ValueCallback for F
where
    F: for<'a> FnMut() + Send + 'static,
{
    fn changed(&mut self) {
        self();
    }
}

/// A value stored in a [`Dynamic`] with its [`Generation`].
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GenerationalValue<T> {
    /// The stored value.
    pub value: T,
    generation: Generation,
}

impl<T> GenerationalValue<T> {
    /// Returns the generation of this value.
    ///
    /// Each time a [`Dynamic`] is updated, the generation is also updated. This
    /// value can be used to track whether a particular value has been observed.
    pub const fn generation(&self) -> Generation {
        self.generation
    }

    /// Returns a new instance containing the result of invoking `map` with
    /// `self.value`.
    ///
    /// The returned instance will have the same generation as this instance.
    pub fn map<U>(self, map: impl FnOnce(T) -> U) -> GenerationalValue<U> {
        GenerationalValue {
            value: map(self.value),
            generation: self.generation,
        }
    }

    /// Returns a new instance containing the result of invoking `map` with
    /// `&self.value`.
    ///
    /// The returned instance will have the same generation as this instance.
    pub fn map_ref<U>(&self, map: impl for<'a> FnOnce(&'a T) -> U) -> GenerationalValue<U> {
        GenerationalValue {
            value: map(&self.value),
            generation: self.generation,
        }
    }
}

impl<T> Deref for GenerationalValue<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> DerefMut for GenerationalValue<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

/// An exclusive reference to the contents of a [`Dynamic`].
///
/// If the contents are accessed through [`DerefMut`], all obververs will be
/// notified of a change when this guard is dropped.
#[derive(Debug)]
pub struct DynamicGuard<'a, T> {
    guard: DynamicMutexGuard<'a, T>,
    accessed_mut: bool,
}

impl<'a, T> Deref for DynamicGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.guard.wrapped.value
    }
}

impl<'a, T> DerefMut for DynamicGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.accessed_mut = true;
        &mut self.guard.wrapped.value
    }
}

impl<T> Drop for DynamicGuard<'_, T> {
    fn drop(&mut self) {
        if self.accessed_mut {
            let mut callbacks = Some(self.guard.note_changed());
            run_in_bg(move || drop(callbacks.take()));
        }
    }
}

/// A reader that tracks the last generation accessed through this reader.
#[derive(Debug)]
pub struct DynamicReader<T> {
    source: Arc<DynamicData<T>>,
    read_generation: Generation,
}

impl<T> DynamicReader<T> {
    /// Maps the contents of the dynamic value and returns the result.
    ///
    /// This function marks the currently stored value as being read.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    pub fn map_ref<R>(&mut self, map: impl FnOnce(&T) -> R) -> R {
        let state = self.source.state().expect("deadlocked");
        self.read_generation = state.wrapped.generation;
        map(&state.wrapped.value)
    }

    /// Returns true if the dynamic has been modified since the last time the
    /// value was accessed through this reader.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn has_updated(&self) -> bool {
        self.source.state().expect("deadlocked").wrapped.generation != self.read_generation
    }

    /// Returns a clone of the currently contained value.
    ///
    /// This function marks the currently stored value as being read.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get(&mut self) -> T
    where
        T: Clone,
    {
        let GenerationalValue { value, generation } = self.source.get().expect("deadlocked");
        self.read_generation = generation;
        value
    }

    /// Returns a clone of the currently contained value.
    ///
    /// This function marks the currently stored value as being read.
    ///
    /// `context` will be invalidated when the value is updated.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get_tracking_refresh(&mut self, context: &WidgetContext<'_, '_>) -> T
    where
        T: Clone,
    {
        self.source.redraw_when_changed(context.handle());
        self.get()
    }

    /// Returns a clone of the currently contained value.
    ///
    /// This function marks the currently stored value as being read.
    ///
    /// `context` will be invalidated when the value is updated.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    #[must_use]
    pub fn get_tracking_invalidate(&mut self, context: &WidgetContext<'_, '_>) -> T
    where
        T: Clone,
    {
        self.source
            .invalidate_when_changed(context.handle(), context.widget().id());
        self.get()
    }

    /// Blocks the current thread until the contained value has been updated or
    /// there are no remaining writers for the value.
    ///
    /// Returns true if a newly updated value was discovered.
    ///
    /// # Panics
    ///
    /// This function panics if this value is already locked by the current
    /// thread.
    pub fn block_until_updated(&mut self) -> bool {
        let mut deadlock_state = self.source.during_callback_state.lock().ignore_poison();
        assert!(
            deadlock_state
                .as_ref()
                .map_or(true, |state| state.locked_thread
                    != std::thread::current().id()),
            "deadlocked"
        );
        loop {
            let state = self.source.state.lock().ignore_poison();
            if state.wrapped.generation != self.read_generation {
                return true;
            } else if state.readers == Arc::strong_count(&self.source) {
                return false;
            }
            drop(state);

            // Wait for a notification of a change, which is synch
            deadlock_state = self.source.sync.wait(deadlock_state).ignore_poison();
        }
    }

    /// Suspends the current async task until the contained value has been
    /// updated or there are no remaining writers for the value.
    ///
    /// Returns true if a newly updated value was discovered.
    pub fn wait_until_updated(&mut self) -> BlockUntilUpdatedFuture<'_, T> {
        BlockUntilUpdatedFuture(self)
    }
}

impl<T> context::sealed::Trackable for DynamicReader<T> {
    fn redraw_when_changed(&self, handle: WindowHandle) {
        self.source.redraw_when_changed(handle);
    }

    fn invalidate_when_changed(&self, handle: WindowHandle, id: WidgetId) {
        self.source.invalidate_when_changed(handle, id);
    }
}

impl<T> Clone for DynamicReader<T> {
    fn clone(&self) -> Self {
        self.source.state().expect("deadlocked").readers += 1;
        Self {
            source: self.source.clone(),
            read_generation: self.read_generation,
        }
    }
}

impl<T> Drop for DynamicReader<T> {
    fn drop(&mut self) {
        let mut state = self.source.state().expect("deadlocked");
        state.readers -= 1;
    }
}

/// Suspends the current async task until the contained value has been
/// updated or there are no remaining writers for the value.
///
/// Yeilds true if a newly updated value was discovered.
#[derive(Debug)]
#[must_use = "futures must be .await'ed to be executed"]
pub struct BlockUntilUpdatedFuture<'a, T>(&'a mut DynamicReader<T>);

impl<'a, T> Future for BlockUntilUpdatedFuture<'a, T> {
    type Output = bool;

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
        let mut state = self.0.source.state().expect("deadlocked");
        if state.wrapped.generation != self.0.read_generation {
            return Poll::Ready(true);
        } else if state.readers == Arc::strong_count(&self.0.source) {
            return Poll::Ready(false);
        }

        state.wakers.push(cx.waker().clone());
        Poll::Pending
    }
}

#[test]
fn disconnecting_reader_from_dynamic() {
    let value = Dynamic::new(1);
    let mut ref_reader = value.create_reader();
    drop(value);
    assert!(!ref_reader.block_until_updated());
}

#[test]
fn disconnecting_reader_threaded() {
    let a = Dynamic::new(1);
    let mut a_reader = a.create_reader();
    let b = Dynamic::new(1);
    let mut b_reader = b.create_reader();

    let thread = std::thread::spawn(move || {
        b.set(2);

        assert!(a_reader.block_until_updated());
        assert_eq!(a_reader.get(), 2);
        assert!(!a_reader.block_until_updated());
    });

    // Wait for the thread to set b to 2.
    assert!(b_reader.block_until_updated());
    assert_eq!(b_reader.get(), 2);

    // Set a to 2 and drop the handle.
    a.set(2);
    drop(a);

    thread.join().unwrap();
}

#[test]
fn disconnecting_reader_async() {
    let a = Dynamic::new(1);
    let mut a_reader = a.create_reader();
    let b = Dynamic::new(1);
    let mut b_reader = b.create_reader();

    let async_thread = std::thread::spawn(move || {
        pollster::block_on(async move {
            // Set b to 2, allowing the thread to execute its code.
            b.set(2);

            assert!(a_reader.wait_until_updated().await);
            assert_eq!(a_reader.get(), 2);
            assert!(!a_reader.wait_until_updated().await);
        });
    });

    // Wait for the pollster thread to set b to 2.
    assert!(b_reader.block_until_updated());
    assert_eq!(b_reader.get(), 2);

    // Set a to 2 and drop the handle.
    a.set(2);
    drop(a);

    async_thread.join().unwrap();
}

/// A tag that represents an individual revision of a [`Dynamic`] value.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct Generation(usize);

impl Generation {
    /// Returns the next tag.
    #[must_use]
    pub fn next(self) -> Self {
        Self(self.0.wrapping_add(1))
    }
}

/// A type that can convert into a `Dynamic<T>`.
pub trait IntoDynamic<T> {
    /// Returns `self` as a dynamic.
    fn into_dynamic(self) -> Dynamic<T>;
}

impl<T> IntoDynamic<T> for Dynamic<T> {
    fn into_dynamic(self) -> Dynamic<T> {
        self
    }
}

impl<T, F> IntoDynamic<T> for F
where
    F: FnMut(&T) + Send + 'static,
    T: Default + Send + 'static,
{
    /// Returns [`Dynamic::default()`] with `self` installed as a for-each
    /// callback.
    fn into_dynamic(self) -> Dynamic<T> {
        Dynamic::default().with_for_each(self)
    }
}

/// A type that can be the source of a [`Switcher`] widget.
pub trait Switchable<T>: IntoDynamic<T> + Sized {
    /// Returns a new [`Switcher`] whose contents is the result of invoking
    /// `map` each time `self` is updated.
    fn switcher<F>(self, map: F) -> Switcher
    where
        F: FnMut(&T, &Dynamic<T>) -> WidgetInstance + Send + 'static,
        T: Send + 'static,
    {
        Switcher::mapping(self, map)
    }

    /// Returns a new [`Switcher`] whose contents switches between the values
    /// contained in `map` using the value in `self` as the key.
    fn switch_between<Collection>(self, map: Collection) -> Switcher
    where
        Collection: GetWidget<T> + Send + 'static,
        T: Send + 'static,
    {
        Switcher::mapping(self, move |key, _| {
            map.get(key)
                .map_or_else(|| Space::clear().make_widget(), Clone::clone)
        })
    }
}

/// A collection of widgets that can be queried by `Key`.
pub trait GetWidget<Key> {
    /// Returns the widget associated with `key`, if found.
    fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance>;
}

impl<Key, State> GetWidget<Key> for HashMap<Key, WidgetInstance, State>
where
    Key: Hash + Eq,
    State: BuildHasher,
{
    fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance> {
        HashMap::get(self, key)
    }
}

impl<Key> GetWidget<Key> for Map<Key, WidgetInstance>
where
    Key: Sort,
{
    fn get<'a>(&'a self, key: &Key) -> Option<&'a WidgetInstance> {
        Map::get(self, key)
    }
}

impl GetWidget<usize> for Children {
    fn get<'a>(&'a self, key: &usize) -> Option<&'a WidgetInstance> {
        (**self).get(*key)
    }
}

impl GetWidget<usize> for Vec<WidgetInstance> {
    fn get<'a>(&'a self, key: &usize) -> Option<&'a WidgetInstance> {
        (**self).get(*key)
    }
}

impl<T, W> Switchable<T> for W where W: IntoDynamic<T> {}

/// A value that may be either constant or dynamic.
#[derive(Debug)]
pub enum Value<T> {
    /// A value that will not ever change externally.
    Constant(T),
    /// A value that may be updated externally.
    Dynamic(Dynamic<T>),
}

impl<T> Value<T> {
    /// Returns a [`Value::Dynamic`] containing `value`.
    pub fn dynamic(value: T) -> Self {
        Self::Dynamic(Dynamic::new(value))
    }

    /// Maps the current contents to `map` and returns the result.
    pub fn map<R>(&self, map: impl FnOnce(&T) -> R) -> R {
        match self {
            Value::Constant(value) => map(value),
            Value::Dynamic(dynamic) => dynamic.map_ref(map),
        }
    }

    /// Maps the current contents to `map` and returns the result.
    ///
    /// If `self` is a dynamic, `context` will be invalidated when the value is
    /// updated.
    pub fn map_tracking_redraw<R>(
        &self,
        context: &WidgetContext<'_, '_>,
        map: impl FnOnce(&T) -> R,
    ) -> R {
        match self {
            Value::Constant(value) => map(value),
            Value::Dynamic(dynamic) => {
                context.redraw_when_changed(dynamic);
                dynamic.map_ref(map)
            }
        }
    }

    /// Maps the current contents to `map` and returns the result.
    ///
    /// If `self` is a dynamic, `context` will be invalidated when the value is
    /// updated.
    pub fn map_tracking_invalidate<R>(
        &self,
        context: &WidgetContext<'_, '_>,
        map: impl FnOnce(&T) -> R,
    ) -> R {
        match self {
            Value::Constant(value) => map(value),
            Value::Dynamic(dynamic) => {
                context.invalidate_when_changed(dynamic);
                dynamic.map_ref(map)
            }
        }
    }

    /// Maps the current contents with exclusive access and returns the result.
    pub fn map_mut<R>(&mut self, map: impl FnOnce(&mut T) -> R) -> R {
        match self {
            Value::Constant(value) => map(value),
            Value::Dynamic(dynamic) => dynamic.map_mut(map),
        }
    }

    /// Returns a new value that is updated using `U::from(T.clone())` each time
    /// `self` is updated.
    #[must_use]
    pub fn map_each<R, F>(&self, mut map: F) -> Value<R>
    where
        T: Send + 'static,
        F: for<'a> FnMut(&'a T) -> R + Send + 'static,
        R: PartialEq + Send + 'static,
    {
        match self {
            Value::Constant(value) => Value::Constant(map(value)),
            Value::Dynamic(dynamic) => Value::Dynamic(dynamic.map_each(map)),
        }
    }

    /// Returns a clone of the currently stored value.
    pub fn get(&self) -> T
    where
        T: Clone,
    {
        self.map(Clone::clone)
    }

    /// Returns a clone of the currently stored value.
    ///
    /// If `self` is a dynamic, `context` will be invalidated when the value is
    /// updated.
    pub fn get_tracked(&self, context: &WidgetContext<'_, '_>) -> T
    where
        T: Clone,
    {
        self.map_tracking_redraw(context, Clone::clone)
    }

    /// Returns the current generation of the data stored, if the contained
    /// value is [`Dynamic`].
    pub fn generation(&self) -> Option<Generation> {
        match self {
            Value::Constant(_) => None,
            Value::Dynamic(value) => Some(value.generation()),
        }
    }

    /// Marks the widget for redraw when this value is updated.
    ///
    /// This function has no effect if the value is constant.
    pub fn redraw_when_changed(&self, context: &WidgetContext<'_, '_>) {
        if let Value::Dynamic(dynamic) = self {
            context.redraw_when_changed(dynamic);
        }
    }

    /// Marks the widget for redraw when this value is updated.
    ///
    /// This function has no effect if the value is constant.
    pub fn invalidate_when_changed(&self, context: &WidgetContext<'_, '_>) {
        if let Value::Dynamic(dynamic) = self {
            context.invalidate_when_changed(dynamic);
        }
    }
}

impl<T> IntoDynamic<T> for Value<T> {
    fn into_dynamic(self) -> Dynamic<T> {
        match self {
            Value::Constant(value) => Dynamic::new(value),
            Value::Dynamic(value) => value,
        }
    }
}

impl<T> Clone for Value<T>
where
    T: Clone,
{
    fn clone(&self) -> Self {
        match self {
            Self::Constant(arg0) => Self::Constant(arg0.clone()),
            Self::Dynamic(arg0) => Self::Dynamic(arg0.clone()),
        }
    }
}

impl<T> Default for Value<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::Constant(T::default())
    }
}

/// A type that can be converted into a [`Value`].
pub trait IntoValue<T> {
    /// Returns this type as a [`Value`].
    fn into_value(self) -> Value<T>;
}

impl<T> IntoValue<T> for T {
    fn into_value(self) -> Value<T> {
        Value::Constant(self)
    }
}

impl<'a> IntoValue<String> for &'a str {
    fn into_value(self) -> Value<String> {
        Value::Constant(self.to_owned())
    }
}

impl IntoValue<String> for Dynamic<&'static str> {
    fn into_value(self) -> Value<String> {
        self.map_each(ToString::to_string).into_value()
    }
}

impl<T> IntoValue<T> for Dynamic<T> {
    fn into_value(self) -> Value<T> {
        Value::Dynamic(self)
    }
}

impl<T> IntoValue<T> for Value<T> {
    fn into_value(self) -> Value<T> {
        self
    }
}

impl<T> IntoValue<Option<T>> for T {
    fn into_value(self) -> Value<Option<T>> {
        Value::Constant(Some(self))
    }
}

/// A type that can have a `for_each` operation applied to it.
pub trait ForEach<T> {
    /// The borrowed representation of T to pass into the `for_each` function.
    type Ref<'a>;

    /// Apply `for_each` to each value contained within `self`.
    fn for_each<F>(&self, for_each: F)
    where
        F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static;
}

macro_rules! impl_tuple_for_each {
    ($($type:ident $field:tt $var:ident),+) => {
        impl<$($type,)+> ForEach<($($type,)+)> for ($(&Dynamic<$type>,)+)
        where
            $($type: Send + 'static,)+
        {
            type Ref<'a> = ($(&'a $type,)+);

            #[allow(unused_mut)]
            fn for_each<F>(&self, mut for_each: F)
            where
                F: for<'a> FnMut(Self::Ref<'a>) + Send + 'static,
            {
                impl_tuple_for_each!(self for_each [] [$($type $field $var),+]);
            }
        }
    };
    ($self:ident $for_each:ident [] [$type:ident $field:tt $var:ident]) => {
        $self.$field.for_each(move |field: &$type| $for_each((field,)));
    };
    ($self:ident $for_each:ident [] [$($type:ident $field:tt $var:ident),+]) => {
        let $for_each = Arc::new(Mutex::new($for_each));
        $(let $var = $self.$field.clone();)*


        impl_tuple_for_each!(invoke $self $for_each [] [$($type $field $var),+]);
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // List of all tuple fields that have already been positioned as the focused call
        [$($ltype:ident $lfield:tt $lvar:ident),*]
        //
        [$type:ident $field:tt $var:ident, $($rtype:ident $rfield:tt $rvar:ident),+]
    ) => {
        impl_tuple_for_each!(
            invoke
            $self $for_each
            $type $field $var
            [$($ltype $lfield $lvar,)* $type $field $var, $($rtype $rfield $rvar),+]
            [$($ltype $lfield $lvar,)* $($rtype $rfield $rvar),+]
        );
        impl_tuple_for_each!(
            invoke
            $self $for_each
            [$($ltype $lfield $lvar,)* $type $field $var]
            [$($rtype $rfield $rvar),+]
        );
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // List of all tuple fields that have already been positioned as the focused call
        [$($ltype:ident $lfield:tt $lvar:ident),+]
        //
        [$type:ident $field:tt $var:ident]
    ) => {
        impl_tuple_for_each!(
            invoke
            $self $for_each
            $type $field $var
            [$($ltype $lfield $lvar,)+ $type $field $var]
            [$($ltype $lfield $lvar),+]
        );
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // Tuple field that for_each is being invoked on
        $type:ident $field:tt $var:ident
        // The list of all tuple fields in this invocation, in the correct order.
        [$($atype:ident $afield:tt $avar:ident),+]
        // The list of tuple fields excluding the one being invoked.
        [$($rtype:ident $rfield:tt $rvar:ident),+]
    ) => {
        $var.for_each((&$for_each, $(&$rvar,)+).with_clone(|(for_each, $($rvar,)+)| {
            move |$var: &$type| {
                $(let $rvar = $rvar.lock();)+
                let mut for_each =
                    for_each.lock().ignore_poison();
                (for_each)(($(&$avar,)+));
            }
        }));
    };
}

impl_all_tuples!(impl_tuple_for_each);

/// A type that can create a `Dynamic<U>` from a `T` passed into a mapping
/// function.
pub trait MapEach<T, U> {
    /// The borrowed representation of `T` passed into the mapping function.
    type Ref<'a>;

    /// Apply `map_each` to each value in `self`, storing the result in the
    /// returned dynamic.
    fn map_each<F>(&self, map_each: F) -> Dynamic<U>
    where
        F: for<'a> FnMut(Self::Ref<'a>) -> U + Send + 'static;
}

macro_rules! impl_tuple_map_each {
    ($($type:ident $field:tt $var:ident),+) => {
        impl<U, $($type),+> MapEach<($($type,)+), U> for ($(&Dynamic<$type>,)+)
        where
            U: PartialEq + Send + 'static,
            $($type: Send + 'static),+
        {
            type Ref<'a> = ($(&'a $type,)+);

            fn map_each<F>(&self, mut map_each: F) -> Dynamic<U>
            where
                F: for<'a> FnMut(Self::Ref<'a>) -> U + Send + 'static,
            {
                let dynamic = {
                    $(let $var = self.$field.lock();)+

                    Dynamic::new(map_each(($(&$var,)+)))
                };
                self.for_each({
                    let dynamic = dynamic.clone();

                    move |tuple| {
                        dynamic.set(map_each(tuple));
                    }
                });
                dynamic
            }
        }
    };
}

impl_all_tuples!(impl_tuple_map_each);

/// A type that can have a `for_each` operation applied to it.
pub trait ForEachCloned<T> {
    /// Apply `for_each` to each value contained within `self`.
    fn for_each_cloned<F>(&self, for_each: F)
    where
        F: for<'a> FnMut(T) + Send + 'static;
}

macro_rules! impl_tuple_for_each_cloned {
    ($($type:ident $field:tt $var:ident),+) => {
        impl<$($type,)+> ForEachCloned<($($type,)+)> for ($(&Dynamic<$type>,)+)
        where
            $($type: Clone + Send + 'static,)+
        {

            #[allow(unused_mut)]
            fn for_each_cloned<F>(&self, mut for_each: F)
            where
                F: for<'a> FnMut(($($type,)+)) + Send + 'static,
            {
                impl_tuple_for_each_cloned!(self for_each [] [$($type $field $var),+]);
            }
        }
    };
    ($self:ident $for_each:ident [] [$type:ident $field:tt $var:ident]) => {
        $self.$field.for_each(move |field: &$type| $for_each((field.clone(),)));
    };
    ($self:ident $for_each:ident [] [$($type:ident $field:tt $var:ident),+]) => {
        let $for_each = Arc::new(Mutex::new($for_each));
        $(let $var = $self.$field.clone();)*


        impl_tuple_for_each_cloned!(invoke $self $for_each [] [$($type $field $var),+]);
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // List of all tuple fields that have already been positioned as the focused call
        [$($ltype:ident $lfield:tt $lvar:ident),*]
        //
        [$type:ident $field:tt $var:ident, $($rtype:ident $rfield:tt $rvar:ident),+]
    ) => {
        impl_tuple_for_each_cloned!(
            invoke
            $self $for_each
            $type $field $var
            [$($ltype $lfield $lvar,)* $type $field $var, $($rtype $rfield $rvar),+]
            [$($ltype $lfield $lvar,)* $($rtype $rfield $rvar),+]
        );
        impl_tuple_for_each_cloned!(
            invoke
            $self $for_each
            [$($ltype $lfield $lvar,)* $type $field $var]
            [$($rtype $rfield $rvar),+]
        );
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // List of all tuple fields that have already been positioned as the focused call
        [$($ltype:ident $lfield:tt $lvar:ident),+]
        //
        [$type:ident $field:tt $var:ident]
    ) => {
        impl_tuple_for_each_cloned!(
            invoke
            $self $for_each
            $type $field $var
            [$($ltype $lfield $lvar,)+ $type $field $var]
            [$($ltype $lfield $lvar),+]
        );
    };
    (
        invoke
        // Identifiers used from the outer method
        $self:ident $for_each:ident
        // Tuple field that for_each is being invoked on
        $type:ident $field:tt $var:ident
        // The list of all tuple fields in this invocation, in the correct order.
        [$($atype:ident $afield:tt $avar:ident),+]
        // The list of tuple fields excluding the one being invoked.
        [$($rtype:ident $rfield:tt $rvar:ident),+]
    ) => {
        $var.for_each_cloned((&$for_each, $(&$rvar,)+).with_clone(|(for_each, $($rvar,)+)| {
            move |$var: $type| {
                $(let $rvar = $rvar.get();)+
                if let Ok(mut for_each) =
                    for_each.try_lock() {
                (for_each)(($($avar,)+));
                    }
            }
        }));
    };
}

impl_all_tuples!(impl_tuple_for_each_cloned);

/// A type that can create a `Dynamic<U>` from a `T` passed into a mapping
/// function.
pub trait MapEachCloned<T, U> {
    /// Apply `map_each` to each value in `self`, storing the result in the
    /// returned dynamic.
    fn map_each_cloned<F>(&self, map_each: F) -> Dynamic<U>
    where
        F: for<'a> FnMut(T) -> U + Send + 'static;
}

macro_rules! impl_tuple_map_each_cloned {
    ($($type:ident $field:tt $var:ident),+) => {
        impl<U, $($type),+> MapEachCloned<($($type,)+), U> for ($(&Dynamic<$type>,)+)
        where
            U: PartialEq + Send + 'static,
            $($type: Clone + Send + 'static),+
        {

            fn map_each_cloned<F>(&self, mut map_each: F) -> Dynamic<U>
            where
                F: for<'a> FnMut(($($type,)+)) -> U + Send + 'static,
            {
                let dynamic = {
                    $(let $var = self.$field.get();)+

                    Dynamic::new(map_each(($($var,)+)))
                };
                self.for_each_cloned({
                    let dynamic = dynamic.clone();

                    move |tuple| {
                        dynamic.set(map_each(tuple));
                    }
                });
                dynamic
            }
        }
    };
}

impl_all_tuples!(impl_tuple_map_each_cloned);

/// The status of validating data.
#[derive(Debug, Default, Clone, Eq, PartialEq)]
pub enum Validation {
    /// No validation has been performed yet.
    ///
    /// This status represents that the data is still in its initial state, so
    /// errors should be delayed until it is changed.
    #[default]
    None,
    /// The data is valid.
    Valid,
    /// The data is invalid. The string contains a human-readable message.
    Invalid(String),
}

impl Validation {
    /// Returns the effective text to display along side the field.
    ///
    /// When there is a validation error, it is returned, otherwise the hint is
    /// returned.
    #[must_use]
    pub fn message<'a>(&'a self, hint: &'a str) -> &'a str {
        match self {
            Validation::None | Validation::Valid => hint,
            Validation::Invalid(err) => err,
        }
    }

    /// Returns true if there is a validation error.
    #[must_use]
    pub const fn is_error(&self) -> bool {
        matches!(self, Self::Invalid(_))
    }

    /// Returns the result of merging both validations.
    #[must_use]
    pub fn and(&self, other: &Self) -> Self {
        match (self, other) {
            (Validation::Valid, Validation::Valid) => Validation::Valid,
            (Validation::Invalid(error), _) | (_, Validation::Invalid(error)) => {
                Validation::Invalid(error.clone())
            }
            (Validation::None, _) | (_, Validation::None) => Validation::None,
        }
    }
}

/// A grouping of validations that can be checked simultaneously.
#[derive(Debug, Default, Clone)]
pub struct Validations {
    state: Dynamic<ValidationsState>,
    invalid: Dynamic<usize>,
}

#[derive(Default, Debug, Eq, PartialEq, Clone)]
enum ValidationsState {
    #[default]
    Initial,
    Resetting,
    Checked,
    Disabled,
}

impl Validations {
    /// Validates `dynamic`'s contents using `check`, returning a dynamic
    /// containing the validation status.
    ///
    /// The validation is linked with `self` such that checking `self`'s
    /// validation status will include this validation.
    #[must_use]
    pub fn validate<T, E, Valid>(
        &self,
        dynamic: &Dynamic<T>,
        mut check: Valid,
    ) -> Dynamic<Validation>
    where
        T: Send + 'static,
        Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static,
        E: Display,
    {
        let validation = Dynamic::new(Validation::None);
        let mut message_mapping = Self::map_to_message(move |value| check(value));
        let error_message = dynamic.map_each_generational(move |value| message_mapping(value));

        (&self.state, &error_message).for_each_cloned({
            let mut f = self.generate_validation(dynamic);
            let validation = validation.clone();

            move |(current_state, message)| {
                validation.set(f(current_state, message));
            }
        });

        validation
    }

    fn map_to_message<T, E, Valid>(
        mut check: Valid,
    ) -> impl for<'a> FnMut(&'a GenerationalValue<T>) -> GenerationalValue<Option<String>> + Send + 'static
    where
        T: Send + 'static,
        Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static,
        E: Display,
    {
        move |value| {
            value.map_ref(|value| match check(value) {
                Ok(()) => None,
                Err(err) => Some(err.to_string()),
            })
        }
    }

    fn generate_validation<T>(
        &self,
        dynamic: &Dynamic<T>,
    ) -> impl FnMut(ValidationsState, GenerationalValue<Option<String>>) -> Validation
    where
        T: Send + 'static,
    {
        self.invalid.map_mut(|invalid| *invalid += 1);

        let invalid_count = self.invalid.clone();
        let dynamic = dynamic.clone();
        let mut initial_generation = dynamic.generation();
        let mut invalid = true;

        move |current_state, generational| {
            let new_invalid = match (&current_state, &generational.value) {
                (ValidationsState::Disabled, _) | (_, None) => false,
                (_, Some(_)) => true,
            };
            if invalid != new_invalid {
                if new_invalid {
                    invalid_count.map_mut(|invalid| *invalid += 1);
                } else {
                    invalid_count.map_mut(|invalid| *invalid -= 1);
                }
                invalid = new_invalid;
            }
            let new_status = if let Some(err) = generational.value {
                Validation::Invalid(err.to_string())
            } else {
                Validation::Valid
            };
            match current_state {
                ValidationsState::Resetting => {
                    initial_generation = dynamic.generation();
                    Validation::None
                }
                ValidationsState::Initial if initial_generation == dynamic.generation() => {
                    Validation::None
                }
                _ => new_status,
            }
        }
    }

    /// Returns a builder that can be used to create validations that only run
    /// when `condition` is true.
    pub fn when(&self, condition: impl IntoDynamic<bool>) -> WhenValidation<'_> {
        WhenValidation {
            validations: self,
            condition: condition.into_dynamic(),
            not: false,
        }
    }

    /// Returns a builder that can be used to create validations that only run
    /// when `condition` is false.
    pub fn when_not(&self, condition: impl IntoDynamic<bool>) -> WhenValidation<'_> {
        WhenValidation {
            validations: self,
            condition: condition.into_dynamic(),
            not: true,
        }
    }

    /// Returns true if this set of validations are all valid.
    #[must_use]
    pub fn is_valid(&self) -> bool {
        self.invoke_callback((), &mut |()| true)
    }

    fn invoke_callback<T, R, F>(&self, t: T, handler: &mut F) -> R
    where
        F: FnMut(T) -> R + UnwindSafe + Send + 'static,
        R: Default,
    {
        let mut state = self.state.lock();
        if let ValidationsState::Initial = &*state {
            *state = ValidationsState::Checked;
        }
        drop(state);
        if self.invalid.get() == 0 {
            handler(t)
        } else {
            R::default()
        }
    }

    /// Returns a function that invokes `handler` only when all tracked
    /// validations are valid.
    ///
    /// The returned function can be use in a
    /// [`Callback`](crate::widget::Callback).
    ///
    /// When the contents are invalid, `R::default()` is returned.
    pub fn when_valid<T, R, F>(
        self,
        mut handler: F,
    ) -> impl FnMut(T) -> R + UnwindSafe + Send + 'static
    where
        F: FnMut(T) -> R + UnwindSafe + Send + 'static,
        R: Default,
    {
        move |t: T| self.invoke_callback(t, &mut handler)
    }

    /// Resets the validation status for all related validations.
    pub fn reset(&self) {
        self.state.set(ValidationsState::Resetting);
        self.state.set(ValidationsState::Initial);
    }
}

/// A builder for validations that only run when a precondition is met.
pub struct WhenValidation<'a> {
    validations: &'a Validations,
    condition: Dynamic<bool>,
    not: bool,
}

impl WhenValidation<'_> {
    /// Validates `dynamic`'s contents using `check`, returning a dynamic
    /// containing the validation status.
    ///
    /// The validation is linked with `self` such that checking `self`'s
    /// validation status will include this validation.
    ///
    /// Each change to `dynamic` is validated, but the result of the validation
    /// will be ignored if the required prerequisite isn't met.
    #[must_use]
    pub fn validate<T, E, Valid>(
        &self,
        dynamic: &Dynamic<T>,
        mut check: Valid,
    ) -> Dynamic<Validation>
    where
        T: Send + 'static,
        Valid: for<'a> FnMut(&'a T) -> Result<(), E> + Send + 'static,
        E: Display,
    {
        let validation = Dynamic::new(Validation::None);
        let mut map_to_message = Validations::map_to_message(move |value| check(value));
        let error_message =
            dynamic.map_each_generational(move |generational| map_to_message(generational));
        let mut f = self.validations.generate_validation(dynamic);
        let not = self.not;

        (&self.condition, &self.validations.state, &error_message).map_each_cloned({
            let validation = validation.clone();
            move |(condition, state, message)| {
                let enabled = if not { !condition } else { condition };
                let state = if enabled {
                    state
                } else {
                    ValidationsState::Disabled
                };
                let result = f(state, message);
                if enabled {
                    validation.set(result);
                } else {
                    validation.set(Validation::None);
                }
            }
        });

        validation
    }

    /// Returns a dynamic validation status that is created by transforming the
    /// `Err` variant of `result` using [`Display`].
    ///
    /// The validation is linked with `self` such that checking `self`'s
    /// validation status will include this validation.
    #[must_use]
    pub fn validate_result<E>(&self, result: impl IntoDynamic<Result<(), E>>) -> Dynamic<Validation>
    where
        E: Display + Send + 'static,
    {
        let result = result.into_dynamic();
        let error_message = result.map_each(move |value| match value {
            Ok(()) => None,
            Err(err) => Some(err.to_string()),
        });

        self.validate(&error_message, |error_message| match error_message {
            None => Ok(()),
            Some(message) => Err(message.clone()),
        })
    }
}

struct Debounce<T> {
    destination: Dynamic<T>,
    period: Duration,
    delay: Option<AnimationHandle>,
    buffer: Dynamic<T>,
    extend: bool,
}

impl<T> Debounce<T>
where
    T: Clone + PartialEq + Send + Sync + 'static,
{
    pub fn new(destination: Dynamic<T>, period: Duration) -> Self {
        Self {
            buffer: Dynamic::new(destination.get()),
            destination,
            period,
            delay: None,
            extend: false,
        }
    }

    pub fn extending(mut self) -> Self {
        self.extend = true;
        self
    }

    pub fn update(&mut self, value: T) {
        if self.buffer.replace(value).is_some() {
            let create_delay = if self.extend {
                true
            } else {
                self.delay
                    .as_ref()
                    .map_or(true, AnimationHandle::is_complete)
            };

            if create_delay {
                let destination = self.destination.clone();
                let buffer = self.buffer.clone();
                self.delay = Some(
                    self.period
                        .on_complete(move || {
                            destination.set(buffer.get());
                        })
                        .spawn(),
                );
            }
        }
    }
}
