use std::collections::HashMap;

use crate::exid::ExId;
use crate::types::Prop;
use crate::{PatchAction, ScalarValue, SequenceTree, TextEncoding};

use super::{HydrateError, Value};

#[derive(Clone, Default, PartialEq)]
pub struct List(SequenceTree<ListValue>);

impl std::fmt::Debug for List {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_list().entries(self.0.iter()).finish()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct ListValue {
    pub value: Value,
    pub marks: HashMap<String, ScalarValue>,
    pub conflict: bool,
}

impl List {
    pub fn iter(&self) -> impl Iterator<Item = &ListValue> {
        self.0.iter()
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub(crate) fn apply(
        &mut self,
        text_encoding: TextEncoding,
        patch: PatchAction,
    ) -> Result<(), HydrateError> {
        match patch {
            PatchAction::PutSeq {
                index,
                value,
                conflict,
            } => {
                let h_value = Value::new(value.0, text_encoding);
                *self
                    .0
                    .get_mut(index)
                    .ok_or(HydrateError::InvalidIndex(index))? = ListValue::new(h_value, conflict);
                Ok(())
            }
            PatchAction::Insert { index, values, .. } => {
                for (n, value) in values.into_iter().enumerate() {
                    let h_value = Value::new(value.0.clone(), text_encoding);
                    self.0.insert(index + n, ListValue::new(h_value, value.2));
                }
                Ok(())
            }
            PatchAction::DeleteSeq { index, length } => {
                for _ in 0..length {
                    self.0.remove(index);
                }
                Ok(())
            }
            PatchAction::Increment {
                prop: Prop::Seq(index),
                value,
            } => {
                self.0
                    .get_mut(index)
                    .ok_or(HydrateError::InvalidIndex(index))?
                    .increment(value)?;
                Ok(())
            }
            PatchAction::Mark { marks: _ } => {
                todo!()
            }
            _ => Err(HydrateError::InvalidListOp),
        }
    }

    pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
        self.0.get_mut(index).map(|lv| &mut lv.value)
    }

    pub fn get(&mut self, index: usize) -> Option<&Value> {
        self.0.get(index).map(|lv| &lv.value)
    }

    pub(crate) fn push<V: Into<Value>>(&mut self, value: V, _id: ExId, conflict: bool) {
        self.0.push(ListValue::new(value.into(), conflict))
    }

    pub(crate) fn new() -> Self {
        Self(Default::default())
    }
}

impl ListValue {
    pub(crate) fn increment(&mut self, n: i64) -> Result<(), HydrateError> {
        if let Value::Scalar(ScalarValue::Counter(c)) = &mut self.value {
            c.increment(n);
            Ok(())
        } else {
            Err(HydrateError::BadIncrement)
        }
    }

    pub(crate) fn new(value: Value, conflict: bool) -> Self {
        Self {
            value,
            conflict,
            marks: Default::default(),
        }
    }
}

impl From<Vec<Value>> for List {
    fn from(values: Vec<Value>) -> Self {
        let mut s = SequenceTree::new();
        for value in values {
            s.push(ListValue {
                value,
                conflict: false,
                marks: Default::default(),
            })
        }
        List(s)
    }
}

impl From<Vec<Value>> for Value {
    fn from(values: Vec<Value>) -> Self {
        Value::List(List::from(values))
    }
}
