use std::{
    collections::{BTreeMap, HashMap},
    hash::Hash,
};

use thiserror::Error;

use super::value::{Optional, Tuple, Value, ValueWithId};

#[derive(Error, Debug)]
pub enum FromValueError {
    #[error("time parse error")]
    TimeParseError,
    #[error("nested type try from error")]
    NestedTypeFromError,
    #[error("array bytes from error")]
    ArrayBytesError,
    #[error("value match error")]
    ValueMatchError,
    #[error("enum from u8 error")]
    EnumFromU8Error,
    #[error("iter next error")]
    IterNextError,
}

pub trait TryFromValue: Sized {
    fn try_from(value: Value) -> Result<Self, FromValueError>
    where
        Self: Sized;
}

impl TryFromValue for bool {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Bool(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for u8 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::U8(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for i32 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::I32(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for i64 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::I64(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for u32 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::U32(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for u64 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::U64(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for f32 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::F32(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for f64 {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::F64(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for time::Duration {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::I64(val) => {
                let duration = time::Duration::seconds(val);
                Ok(duration)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for time::OffsetDateTime {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::I64(val) => {
                let dt = time::OffsetDateTime::from_unix_timestamp(val);
                dt.map_err(|_| FromValueError::TimeParseError)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for time::Date {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::I32(val) => {
                let date = time::Date::from_julian_day(val);
                date.map_err(|_| FromValueError::TimeParseError)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

/**
convert u32 to time::Time
 */
pub(crate) const fn time_from_u32(u: u32) -> Result<time::Time, time::error::ComponentRange> {
    let bytes: [u8; 4] = u.to_le_bytes();
    let hour = bytes[0];
    let minute = bytes[1];
    let second = bytes[2];
    time::Time::from_hms(hour, minute, second)
}

impl TryFromValue for time::Time {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::U32(val) => {
                let time = time_from_u32(val).map_err(|_| FromValueError::TimeParseError)?;
                Ok(time)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl TryFromValue for String {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Str(val) => Ok(val),
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<T: TryFromValue> TryFromValue for Box<T> {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        let v: T = T::try_from(value)?;
        Ok(v.into())
    }
}

impl<T: TryFromValue> TryFromValue for Option<T> {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Optional(Optional(v)) => {
                let value = v.map(|v| *v);
                let value: Option<Result<T, FromValueError>> = value.map(T::try_from);
                value.transpose()
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<T: TryFromValue> TryFromValue for Vec<T> {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Vec(val) => {
                let len = val.len();
                let mut vec: Vec<T> = Vec::with_capacity(len);
                for item in val {
                    let v = T::try_from(item).map_err(|_| FromValueError::IterNextError)?;
                    vec.push(v);
                }
                Ok(vec)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<T1: TryFromValue, T2: TryFromValue> TryFromValue for (T1, T2) {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Tuple(Tuple(val)) => {
                let mut iter = val.into_iter();
                let ValueWithId(_, v1) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v2) = iter.next().ok_or(FromValueError::IterNextError)?;
                let v1 = T1::try_from(v1).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v2 = T2::try_from(v2).map_err(|_| FromValueError::NestedTypeFromError)?;
                Ok((v1, v2))
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<T1: TryFromValue, T2: TryFromValue, T3: TryFromValue> TryFromValue for (T1, T2, T3) {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Tuple(Tuple(val)) => {
                let mut iter = val.into_iter();
                let ValueWithId(_, v1) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v2) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v3) = iter.next().ok_or(FromValueError::IterNextError)?;
                let v1 = T1::try_from(v1).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v2 = T2::try_from(v2).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v3 = T3::try_from(v3).map_err(|_| FromValueError::NestedTypeFromError)?;
                Ok((v1, v2, v3))
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<T1: TryFromValue, T2: TryFromValue, T3: TryFromValue, T4: TryFromValue> TryFromValue
    for (T1, T2, T3, T4)
{
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Tuple(Tuple(val)) => {
                let mut iter = val.into_iter();
                let ValueWithId(_, v1) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v2) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v3) = iter.next().ok_or(FromValueError::IterNextError)?;
                let ValueWithId(_, v4) = iter.next().ok_or(FromValueError::IterNextError)?;
                let v1 = T1::try_from(v1).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v2 = T2::try_from(v2).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v3 = T3::try_from(v3).map_err(|_| FromValueError::NestedTypeFromError)?;
                let v4 = T4::try_from(v4).map_err(|_| FromValueError::NestedTypeFromError)?;
                Ok((v1, v2, v3, v4))
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<K: TryFromValue, V: TryFromValue> TryFromValue for HashMap<K, V>
where
    K: Eq + Hash,
{
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Vec(val) => {
                let len = val.len();
                let mut map: HashMap<K, V> = HashMap::with_capacity(len);
                for item in val {
                    let (k, v) = <(K, V) as TryFromValue>::try_from(item)
                        .map_err(|_| FromValueError::IterNextError)?;
                    map.insert(k, v);
                }
                Ok(map)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<K: TryFromValue, V: TryFromValue> TryFromValue for BTreeMap<K, V>
where
    K: Ord,
{
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::Vec(val) => {
                let mut map: BTreeMap<K, V> = BTreeMap::new();
                for item in val {
                    let (k, v) = <(K, V) as TryFromValue>::try_from(item)
                        .map_err(|_| FromValueError::IterNextError)?;
                    map.insert(k, v);
                }
                Ok(map)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}

impl<const CAP: usize> TryFromValue for [u8; CAP] {
    fn try_from(value: Value) -> Result<Self, FromValueError> {
        match value {
            Value::ArrayBytes(val) => {
                let arr: [u8; CAP] = val.try_into()?;
                Ok(arr)
            }
            _ => Err(FromValueError::ValueMatchError),
        }
    }
}
