use std::ops::{Deref, DerefMut};

use futures_signals::signal_vec::{MutableVec, MutableVecLockMut};

pub struct Entry<'a, V> {
    key: Option<usize>,
    lock: MutableVecLockMut<'a, V>,
}

impl<'a, V: Copy> Entry<'a, V> {
    fn existing(self, key: usize) -> Value<'a, V> {
        let value = self.lock.get(key).copied().unwrap();
        Value::existing(self, value)
    }

    #[inline]
    pub fn is_vacant(&self) -> bool {
        self.key.is_none()
    }

    #[inline]
    pub fn is_occupied(&self) -> bool {
        self.key.is_some()
    }

    #[inline]
    pub fn key(&self) -> Option<usize> {
        self.key
    }

    pub fn value(self) -> Option<Value<'a, V>> {
        self.key.map(|key| self.existing(key))
    }

    pub fn or_insert(self, value: V) -> Value<'a, V> {
        match self.key {
            Some(key) => self.existing(key),
            None => Value::new(self, value),
        }
    }

    pub fn or_insert_with<F: FnOnce() -> V>(self, value: F) -> Value<'a, V> {
        match self.key {
            Some(key) => self.existing(key),
            None => Value::new(self, value()),
        }
    }

    pub fn and_modify<F>(self, f: F) -> Self
    where
        F: FnOnce(&mut Value<'a, V>),
    {
        match self.key {
            Some(key) => {
                let mut existing = self.existing(key);
                f(&mut existing);
                existing.commit()
            }
            None => self,
        }
    }

    pub fn and_set(mut self, value: V) -> Self {
        match self.key {
            Some(key) => {
                self.lock.set(key, value);
                self
            }
            None => self,
        }
    }

    pub fn and_set_or_insert(mut self, value: V) -> Value<'a, V> {
        self.set(value);
        // after set key always exists
        let key = self.key.unwrap();
        self.existing(key)
    }

    fn set(&mut self, value: V) {
        match self.key {
            Some(index) => {
                self.lock.set(index, value);
            }
            None => {
                let index = self.lock.len();
                self.lock.push(value);
                self.key = Some(index);
            }
        }
    }

    pub fn remove(mut self) -> Option<V> {
        self.key.map(|key| self.lock.remove(key))
    }
}

impl<'a, V: Copy + Default> Entry<'a, V> {
    pub fn or_default(self) -> Value<'a, V> {
        self.or_insert(V::default())
    }
}

pub struct Value<'a, V: Copy> {
    entry: Option<Entry<'a, V>>,
    value: V,
    modified: bool,
}

impl<'a, V: Copy> Value<'a, V> {
    fn new(entry: Entry<'a, V>, value: V) -> Self {
        Self {
            entry: Some(entry),
            value,
            modified: true,
        }
    }

    fn existing(entry: Entry<'a, V>, value: V) -> Self {
        Self {
            entry: Some(entry),
            value,
            modified: false,
        }
    }

    pub fn inspect_mut<F>(&mut self, mut f: F) -> bool
    where
        F: FnMut(&mut V) -> bool,
    {
        self.modified = f(&mut self.value);
        self.modified
    }

    pub fn set(&mut self, value: V) {
        self.value = value;
        self.modified = true;
    }

    pub fn set_neq(&mut self, value: V)
    where
        V: PartialEq,
    {
        if self.value != value {
            self.value = value;
            self.modified = true;
        }
    }

    #[inline]
    pub fn modified(self) -> bool {
        self.modified
    }

    fn commit(mut self) -> Entry<'a, V> {
        let mut entry = self.entry.take().unwrap();
        if self.modified {
            entry.set(self.value);
        }
        entry
    }
}

impl<V: Copy> Deref for Value<'_, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.value
    }
}

impl<V: Copy> DerefMut for Value<'_, V> {
    fn deref_mut(&mut self) -> &mut V {
        self.modified = true;
        &mut self.value
    }
}

impl<V: Copy> Drop for Value<'_, V> {
    fn drop(&mut self) {
        if self.modified
            && let Some(mut entry) = self.entry.take()
        {
            entry.set(self.value);
        }
    }
}

pub struct EntryCloned<'a, V> {
    key: Option<usize>,
    lock: MutableVecLockMut<'a, V>,
}

impl<'a, V: Clone> EntryCloned<'a, V> {
    fn existing(self, key: usize) -> ValueCloned<'a, V> {
        let value = self.lock.get(key).cloned().unwrap();
        ValueCloned::existing(self, value)
    }

    #[inline]
    pub fn is_vacant(&self) -> bool {
        self.key.is_none()
    }

    #[inline]
    pub fn is_occupied(&self) -> bool {
        self.key.is_some()
    }

    #[inline]
    pub fn key(&self) -> Option<usize> {
        self.key
    }

    pub fn value(self) -> Option<ValueCloned<'a, V>> {
        self.key.map(|key| self.existing(key))
    }

    pub fn or_insert(self, value: V) -> ValueCloned<'a, V> {
        match self.key {
            Some(key) => self.existing(key),
            None => ValueCloned::new(self, value),
        }
    }

    pub fn or_insert_with<F: FnOnce() -> V>(self, value: F) -> ValueCloned<'a, V> {
        match self.key {
            Some(key) => self.existing(key),
            None => ValueCloned::new(self, value()),
        }
    }

    pub fn and_modify<F>(self, f: F) -> Self
    where
        F: FnOnce(&mut ValueCloned<'a, V>),
    {
        match self.key {
            Some(key) => {
                let mut existing = self.existing(key);
                f(&mut existing);
                existing.commit()
            }
            None => self,
        }
    }

    pub fn and_set(mut self, value: V) -> Self {
        match self.key {
            Some(key) => {
                self.lock.set_cloned(key, value);
                self
            }
            None => self,
        }
    }

    pub fn and_set_or_insert(mut self, value: V) -> ValueCloned<'a, V> {
        self.set(value);
        // after set key always exists
        let key = self.key.unwrap();
        self.existing(key)
    }

    fn set(&mut self, value: V) {
        match self.key {
            Some(index) => {
                self.lock.set_cloned(index, value);
            }
            None => {
                let index = self.lock.len();
                self.lock.push_cloned(value);
                self.key = Some(index);
            }
        }
    }

    pub fn remove(mut self) -> Option<V> {
        self.key.map(|key| self.lock.remove(key))
    }
}

impl<'a, V: Clone + Default> EntryCloned<'a, V> {
    pub fn or_default(self) -> ValueCloned<'a, V> {
        self.or_insert(V::default())
    }
}

pub struct ValueCloned<'a, V: Clone> {
    entry: Option<EntryCloned<'a, V>>,
    value: V,
    modified: bool,
}

impl<'a, V: Clone> ValueCloned<'a, V> {
    fn new(entry: EntryCloned<'a, V>, value: V) -> Self {
        Self {
            entry: Some(entry),
            value,
            modified: true,
        }
    }

    fn existing(entry: EntryCloned<'a, V>, value: V) -> Self {
        Self {
            entry: Some(entry),
            value,
            modified: false,
        }
    }

    pub fn inspect_mut<F>(&mut self, mut f: F) -> bool
    where
        F: FnMut(&mut V) -> bool,
    {
        self.modified = f(&mut self.value);
        self.modified
    }

    pub fn set(&mut self, value: V) {
        self.value = value;
        self.modified = true;
    }

    pub fn set_neq(&mut self, value: V)
    where
        V: PartialEq,
    {
        if self.value != value {
            self.value = value;
            self.modified = true;
        }
    }

    #[inline]
    pub fn modified(self) -> bool {
        self.modified
    }

    fn commit(mut self) -> EntryCloned<'a, V> {
        let mut entry = self.entry.take().unwrap();
        if self.modified {
            entry.set(self.value.clone());
        }
        entry
    }
}

impl<V: Clone> Deref for ValueCloned<'_, V> {
    type Target = V;

    fn deref(&self) -> &V {
        &self.value
    }
}

impl<V: Clone> DerefMut for ValueCloned<'_, V> {
    fn deref_mut(&mut self) -> &mut V {
        self.modified = true;
        &mut self.value
    }
}

impl<V: Clone> Drop for ValueCloned<'_, V> {
    fn drop(&mut self) {
        if self.modified
            && let Some(mut entry) = self.entry.take()
        {
            entry.set(self.value.clone());
        }
    }
}

pub trait MutableVecEntry<V> {
    fn entry<F>(&self, f: F) -> Entry<'_, V>
    where
        F: FnMut(&V) -> bool;

    fn entry_cloned<F>(&self, f: F) -> EntryCloned<'_, V>
    where
        F: FnMut(&V) -> bool;
}

impl<V> MutableVecEntry<V> for MutableVec<V> {
    fn entry<F>(&self, f: F) -> Entry<'_, V>
    where
        F: FnMut(&V) -> bool,
    {
        let lock = self.lock_mut();
        let key = lock.iter().position(f);
        Entry { key, lock }
    }

    fn entry_cloned<F>(&self, f: F) -> EntryCloned<'_, V>
    where
        F: FnMut(&V) -> bool,
    {
        let lock = self.lock_mut();
        let key = lock.iter().position(f);
        EntryCloned { key, lock }
    }
}
