use data_encoding::HEXUPPER;

use super::value::{List, Value, ValueWithId};

impl From<bool> for Value {
    fn from(val: bool) -> Self {
        Value::Bool(val)
    }
}

impl From<i32> for Value {
    fn from(val: i32) -> Self {
        Value::I64(val as i64)
    }
}

impl From<i64> for Value {
    fn from(val: i64) -> Self {
        Value::I64(val)
    }
}

impl From<u32> for Value {
    fn from(val: u32) -> Self {
        Value::U64(val as u64)
    }
}

impl From<u64> for Value {
    fn from(val: u64) -> Self {
        Value::U64(val)
    }
}

impl From<String> for Value {
    fn from(val: String) -> Self {
        Value::Str(val)
    }
}

impl From<&str> for Value {
    fn from(val: &str) -> Self {
        Value::Str(String::from(val))
    }
}

impl From<time::Duration> for Value {
    fn from(val: time::Duration) -> Self {
        let secs = val.whole_seconds();
        Value::from(secs)
    }
}

impl From<time::OffsetDateTime> for Value {
    fn from(val: time::OffsetDateTime) -> Self {
        let secs = val.unix_timestamp();
        Value::from(secs)
    }
}

impl From<time::PrimitiveDateTime> for Value {
    fn from(val: time::PrimitiveDateTime) -> Self {
        let secs = val.assume_utc().unix_timestamp();
        Value::from(secs)
    }
}

impl From<time::Date> for Value {
    fn from(val: time::Date) -> Self {
        let days = val.to_julian_day();
        Value::from(days)
    }
}

/**
convert time::Time to u32
*/
const fn time_into_u32(time: &time::Time) -> u32 {
    let (h, m, s) = time.as_hms();
    u32::from_le_bytes([h, m, s, 0])
}

impl From<time::Time> for Value {
    fn from(val: time::Time) -> Self {
        let u = time_into_u32(&val);
        Value::from(u)
    }
}

// impl<T: Into<Value>> From<Vec<T>> for Value {
//     fn from(val: Vec<T>) -> Self {
//         let len = val.len();
//         let mut vec: Vec<Value> = Vec::with_capacity(len);
//         for item in val {
//             let val = item.into();
//             vec.push(val);
//         }
//         Value::Vec(vec)
//     }
// }

// impl<'a, T: IntoValue> From<&'a [T]> for Value {
//     fn from(_: &[T]) -> Self {}
// }

impl<T: Into<Value>> From<Option<T>> for Value {
    fn from(val: Option<T>) -> Self {
        match val {
            Some(v) => v.into(),
            None => Value::Void,
        }
    }
}

impl<T: Into<Value>> From<Box<T>> for Value {
    fn from(val: Box<T>) -> Self {
        let v = *val;
        v.into()
    }
}

impl<T1, T2> From<(T1, T2)> for Value
where
    Value: From<T1> + From<T2>,
{
    fn from(val: (T1, T2)) -> Self {
        let (v1, v2) = val;
        let v1 = Value::from(v1);
        let v2 = Value::from(v2);
        let v1 = ValueWithId { id: 0, value: v1 };
        let v2 = ValueWithId { id: 1, value: v2 };
        let vec: Vec<ValueWithId> = vec![v1, v2];
        Value::List(List::Pair(vec))
    }
}

// impl<K: Into<Value>, V: Into<Value>> From<HashMap<K, V>> for Value {
//     fn from(val: HashMap<K, V>) -> Self {
//         let len = val.len();
//         let mut vec: Vec<Value> = Vec::with_capacity(len);
//         for item in val.into_iter() {
//             let value = item.into();
//             vec.push(value);
//         }
//         Value::Vec(vec)
//     }
// }

// impl<K, V> From<BTreeMap<K, V>> for Value
// where
//     K: Into<Value>,
//     V: Into<Value>,
// {
//     fn from(val: BTreeMap<K, V>) -> Self {
//         let len = val.len();
//         let mut vec: List<Value> = Vec::with_capacity(len);
//         for item in val.into_iter() {
//             let value = item.into();
//             vec.push(value);
//         }
//         Value::List(vec)
//     }
// }

impl<const CAP: usize> From<[u8; CAP]> for Value {
    fn from(val: [u8; CAP]) -> Self {
        let s = HEXUPPER.encode(&val);
        Value::Str(s)
    }
}

impl From<Vec<u8>> for Value {
    fn from(val: Vec<u8>) -> Self {
        let s = HEXUPPER.encode(&val);
        Value::Str(s)
    }
}

impl<'a> From<&'a [u8]> for Value {
    fn from(val: &'a [u8]) -> Self {
        let s = HEXUPPER.encode(val);
        Value::Str(s)
    }
}
