use core::any::type_name;
use serde::{de::DeserializeOwned, Serialize};
use crate::Binary;
use crate::{StdError, StdResult};
pub fn from_msgpack<T: DeserializeOwned>(value: impl AsRef<[u8]>) -> StdResult<T> {
    rmp_serde::from_read(value.as_ref()).map_err(|e| StdError::parse_err(type_name::<T>(), e))
}
pub fn to_msgpack_vec<T>(data: &T) -> StdResult<Vec<u8>>
where
    T: Serialize + ?Sized,
{
    rmp_serde::to_vec_named(data).map_err(|e| StdError::serialize_err(type_name::<T>(), e))
}
pub fn to_msgpack_binary<T>(data: &T) -> StdResult<Binary>
where
    T: Serialize + ?Sized,
{
    to_msgpack_vec(data).map(Binary::new)
}
#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Int128, Int256, Int512, Int64, Uint128, Uint256, Uint512, Uint64};
    use serde::Deserialize;
    #[derive(Serialize, Deserialize, Debug, PartialEq)]
    #[serde(rename_all = "snake_case")]
    enum SomeMsg {
        Refund {},
        ReleaseAll {
            image: String,
            amount: u32,
            time: u64,
            karma: i32,
        },
        Cowsay {
            text: String,
        },
    }
    fn refund_test_vector() -> (SomeMsg, &'static [u8]) {
        let msg = SomeMsg::Refund {};
        let serialized = &[129, 166, 114, 101, 102, 117, 110, 100, 128];
        (msg, serialized)
    }
    fn release_all_test_vector() -> (SomeMsg, &'static [u8]) {
        let msg = SomeMsg::ReleaseAll {
            image: "foo".to_string(),
            amount: 42,
            time: 18446744073709551615,
            karma: -17,
        };
        let serialized = &[
            129, 171, 114, 101, 108, 101, 97, 115, 101, 95, 97, 108, 108, 132, 165, 105, 109, 97,
            103, 101, 163, 102, 111, 111, 166, 97, 109, 111, 117, 110, 116, 42, 164, 116, 105, 109,
            101, 207, 255, 255, 255, 255, 255, 255, 255, 255, 165, 107, 97, 114, 109, 97, 239,
        ];
        (msg, serialized)
    }
    fn special_chars_test_vector() -> (SomeMsg, &'static [u8]) {
        let msg = SomeMsg::Cowsay {
            text: "foo\"bar\\\"bla🦴👁🦶🏻".to_string(),
        };
        let serialized = &[
            129, 166, 99, 111, 119, 115, 97, 121, 129, 164, 116, 101, 120, 116, 188, 102, 111, 111,
            34, 98, 97, 114, 92, 34, 98, 108, 97, 240, 159, 166, 180, 240, 159, 145, 129, 240, 159,
            166, 182, 240, 159, 143, 187,
        ];
        (msg, serialized)
    }
    #[test]
    fn to_msgpack_vec_works() {
        let (msg, expected) = refund_test_vector();
        let serialized = to_msgpack_vec(&msg).unwrap();
        assert_eq!(serialized, expected);
        let (msg, expected) = release_all_test_vector();
        let serialized = to_msgpack_vec(&msg).unwrap();
        assert_eq!(serialized, expected);
    }
    #[test]
    fn from_msgpack_works() {
        let (msg, serialized) = refund_test_vector();
        let deserialized: SomeMsg = from_msgpack(serialized).unwrap();
        assert_eq!(deserialized, msg);
        let (msg, serialized) = release_all_test_vector();
        let deserialized: SomeMsg = from_msgpack(serialized).unwrap();
        assert_eq!(deserialized, msg);
    }
    #[test]
    fn from_msgpack_or_binary() {
        let msg = SomeMsg::Refund {};
        let serialized: Binary = to_msgpack_binary(&msg).unwrap();
        let parse_binary: SomeMsg = from_msgpack(&serialized).unwrap();
        assert_eq!(parse_binary, msg);
        let parse_slice: SomeMsg = from_msgpack(serialized.as_slice()).unwrap();
        assert_eq!(parse_slice, msg);
    }
    #[test]
    fn from_msgpack_works_for_special_chars() {
        let (msg, serialized) = special_chars_test_vector();
        let deserialized: SomeMsg = from_msgpack(serialized).unwrap();
        assert_eq!(deserialized, msg);
    }
    #[test]
    fn deserialize_modified_field_order() {
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV1 {
            a: String,
            b: u32,
            c: u64,
        }
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV2 {
            b: u32,
            c: u64,
            a: String,
        }
        let v1 = TestV1 {
            a: "foo".to_string(),
            b: 42,
            c: 18446744073709551615,
        };
        let v2: TestV2 = from_msgpack(to_msgpack_vec(&v1).unwrap()).unwrap();
        assert_eq!(
            v2,
            TestV2 {
                b: 42,
                c: 18446744073709551615,
                a: "foo".to_string()
            }
        );
    }
    #[test]
    fn deserialize_new_fields() {
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV1 {
            a: String,
        }
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV2 {
            a: String,
            #[serde(default)]
            b: u32,
        }
        let v1 = TestV1 {
            a: "foo".to_string(),
        };
        let v2: TestV2 = from_msgpack(to_msgpack_vec(&v1).unwrap()).unwrap();
        assert_eq!(
            v2,
            TestV2 {
                a: "foo".to_string(),
                b: 0
            }
        );
    }
    #[test]
    fn deserialize_new_fields_in_the_middle() {
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV1 {
            a: String,
            b: u32,
        }
        #[derive(Serialize, Deserialize, Debug, PartialEq)]
        struct TestV2 {
            a: String,
            #[serde(default)]
            c: u8,
            b: u32,
        }
        let v1 = TestV1 {
            a: "foo".to_string(),
            b: 999999,
        };
        let v2: TestV2 = from_msgpack(to_msgpack_vec(&v1).unwrap()).unwrap();
        assert_eq!(
            v2,
            TestV2 {
                a: "foo".to_string(),
                c: 0,
                b: 999999,
            }
        );
    }
    #[test]
    fn msgpack_serialization_for_boolean_types() {
        let serialized = to_msgpack_vec(&false).unwrap();
        assert_eq!(serialized, [0xc2]);
        let serialized = to_msgpack_vec(&true).unwrap();
        assert_eq!(serialized, [0xc3]);
    }
    #[test]
    fn msgpack_serialization_for_integer_types() {
        {
            let serialized = to_msgpack_vec(&0u8).unwrap();
            assert_eq!(serialized, [0]);
            let serialized = to_msgpack_vec(&0u16).unwrap();
            assert_eq!(serialized, [0]);
            let serialized = to_msgpack_vec(&0u32).unwrap();
            assert_eq!(serialized, [0]);
            let serialized = to_msgpack_vec(&0u64).unwrap();
            assert_eq!(serialized, [0]);
            let serialized = to_msgpack_vec(&0i64).unwrap();
            assert_eq!(serialized, [0]);
            let serialized = to_msgpack_vec(&7u8).unwrap();
            assert_eq!(serialized, [7]);
            let serialized = to_msgpack_vec(&7u16).unwrap();
            assert_eq!(serialized, [7]);
            let serialized = to_msgpack_vec(&7u32).unwrap();
            assert_eq!(serialized, [7]);
            let serialized = to_msgpack_vec(&7u64).unwrap();
            assert_eq!(serialized, [7]);
            let serialized = to_msgpack_vec(&127u32).unwrap();
            assert_eq!(serialized, [127]);
            let serialized = to_msgpack_vec(&-1i32).unwrap();
            assert_eq!(serialized, [255]);
            let serialized = to_msgpack_vec(&-1i64).unwrap();
            assert_eq!(serialized, [255]);
            let serialized = to_msgpack_vec(&-10i64).unwrap();
            assert_eq!(serialized, [246]);
            let serialized = to_msgpack_vec(&-24i64).unwrap();
            assert_eq!(serialized, [232]);
            let serialized = to_msgpack_vec(&128u32).unwrap();
            assert_eq!(serialized, [0xcc, 128]);
            let serialized = to_msgpack_vec(&237u32).unwrap();
            assert_eq!(serialized, [0xcc, 237]);
            let serialized = to_msgpack_vec(&1000u32).unwrap();
            assert_eq!(serialized, [0xcd, 3, 232]);
            let serialized = to_msgpack_vec(&u32::MAX).unwrap();
            assert_eq!(serialized, [0xce, 255, 255, 255, 255]);
            let serialized = to_msgpack_vec(&575747839886u64).unwrap();
            assert_eq!(serialized, [0xcf, 0, 0, 0, 134, 13, 62, 215, 142]);
            let serialized = to_msgpack_vec(&u64::MAX).unwrap();
            assert_eq!(serialized, [0xcf, 255, 255, 255, 255, 255, 255, 255, 255]);
            let serialized = to_msgpack_vec(&i8::MIN).unwrap();
            assert_eq!(serialized, [0xd0, 128]);
            let serialized = to_msgpack_vec(&-111i8).unwrap();
            assert_eq!(serialized, [0xd0, 145]);
            let serialized = to_msgpack_vec(&i16::MIN).unwrap();
            assert_eq!(serialized, [0xd1, 128, 0]);
            let serialized = to_msgpack_vec(&i32::MIN).unwrap();
            assert_eq!(serialized, [0xd2, 128, 0, 0, 0]);
            let serialized = to_msgpack_vec(&i64::MIN).unwrap();
            assert_eq!(serialized, [0xd3, 128, 0, 0, 0, 0, 0, 0, 0]);
        }
        {
            assert_eq!(
                to_msgpack_vec(&0u128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            );
            assert_eq!(
                to_msgpack_vec(&1u128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
            );
            assert_eq!(
                to_msgpack_vec(&17u128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17]
            );
            assert_eq!(
                to_msgpack_vec(&u128::MAX).unwrap(),
                [
                    0xc4, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255
                ]
            );
            assert_eq!(
                to_msgpack_vec(&0i128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            );
            assert_eq!(
                to_msgpack_vec(&1i128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
            );
            assert_eq!(
                to_msgpack_vec(&17i128).unwrap(),
                [0xc4, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17]
            );
            assert_eq!(
                to_msgpack_vec(&-1i128).unwrap(),
                [
                    0xc4, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255
                ]
            );
            assert_eq!(
                to_msgpack_vec(&i128::MIN).unwrap(),
                [0xc4, 16, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            );
            assert_eq!(
                to_msgpack_vec(&i128::MAX).unwrap(),
                [
                    0xc4, 16, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
                    255, 255
                ]
            );
        }
        {
            let s = to_msgpack_vec(&Uint64::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Uint128::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Uint256::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Uint512::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Uint64::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Uint128::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Uint256::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Uint512::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Uint64::MAX).unwrap();
            assert_eq!(
                s,
                [
                    0b10100000 ^ 20,
                    b'1',
                    b'8',
                    b'4',
                    b'4',
                    b'6',
                    b'7',
                    b'4',
                    b'4',
                    b'0',
                    b'7',
                    b'3',
                    b'7',
                    b'0',
                    b'9',
                    b'5',
                    b'5',
                    b'1',
                    b'6',
                    b'1',
                    b'5'
                ]
            ); }
        {
            let s = to_msgpack_vec(&Int64::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Int128::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Int256::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Int512::zero()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'0']); let s = to_msgpack_vec(&Int64::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Int128::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Int256::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Int512::one()).unwrap();
            assert_eq!(s, [0b10100000 ^ 1, b'1']); let s = to_msgpack_vec(&Int64::from(15i32)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'1', b'5']); let s = to_msgpack_vec(&Int128::from(15i32)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'1', b'5']); let s = to_msgpack_vec(&Int256::from(15i32)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'1', b'5']); let s = to_msgpack_vec(&Int512::from(15i32)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'1', b'5']); let s = to_msgpack_vec(&Int64::from(-1i64)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'-', b'1']); let s = to_msgpack_vec(&Int128::from(-1i64)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'-', b'1']); let s = to_msgpack_vec(&Int256::from(-1i64)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'-', b'1']); let s = to_msgpack_vec(&Int512::from(-1i64)).unwrap();
            assert_eq!(s, [0b10100000 ^ 2, b'-', b'1']); }
    }
}