extern crate alloc;

use serde::{Deserialize, Serialize};

use crate::encode::*;
use crate::*;

#[test]
fn null() {
    let mut data = [0u8; 1];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    ().serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        (),
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn reserved() {
    let mut data = [0b11011111; 1];
    let mut buffer = ReadBuffer::from(&mut data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<(), Error> = serde::de::Deserialize::deserialize(&mut de);
    assert!(res.is_err_and(|error| matches!(error, Error::Unexpected)))
}

#[test]
fn boolean() {
    let mut data = [0u8; 2];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    true.serialize(&mut ser).unwrap_or_else(|_| panic!());
    false.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        true,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );

    assert_eq!(
        false,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn unexpected() {
    let mut data = [0u8; 1];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    true.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<u8, Error> = serde::de::Deserialize::deserialize(&mut de);
    assert!(res.is_err_and(|error| matches!(error, Error::Unexpected)));
}

#[test]
fn u64() {
    let data = [0b11001011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        18446744073709551615u64,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn u32() {
    let data = [0b11001010, 0xff, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        4294967295u32,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn u32_from_u64() {
    let data = [0b11001011, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<u32, Error> = serde::de::Deserialize::deserialize(&mut de);
    assert!(res.is_err_and(|error| matches!(error, Error::OutOfRange)));
}

#[test]
fn u16() {
    let data = [0b11001001, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        65535u16,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn u8() {
    let data = [0b11001000, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        255u8,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn u8_from_64() {
    let data = [0b11001011, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        42u8,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn usize() {
    let data = [0b11001000, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        255usize,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn i64() {
    let data = [0b11001111, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        9223372036854775807i64,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn i32() {
    let data = [0b11001110, 0x7f, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        2147483647i32,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn i16() {
    let data = [0b11001101, 0x7f, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        32767i16,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn i8() {
    let data = [0b11001100, 0x7f];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        127i8,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn isize() {
    let data = [0b11001100, 0x7f];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        127isize,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn f32() {
    let data = [0b11011010, 0x7f, 0x7f, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        3.4028234e38_f32,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn f64() {
    let data = [0b11011011, 0x40, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        42f64,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[ignore = "numeric conversions not finalized"]
#[test]
fn i8_as_f32() {
    let data = [0b11001000, 0x7f];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        127f32,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[ignore = "numeric conversions not finalized"]
#[test]
fn u32_as_f64() {
    let data = [0b11001010, 0xff, 0xff, 0xff, 0xff];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        4294967295f64,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn ascii() {
    let input = "it works!";

    let mut data = [0u8; 10];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<&str, Error> = serde::de::Deserialize::deserialize(&mut de);
    assert_eq!(input, res.unwrap_or_else(|_| panic!()));
}

#[test]
fn tuple() {
    let input = (0u8, "perfect");

    let mut data = [0u8; 10];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        input,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn tuple_len_mismatch() {
    let input = (0u8, "perfect", 1.4);

    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<(u8, &str), Error> = serde::de::Deserialize::deserialize(&mut de);
    assert!(res.is_err_and(|error| matches!(error, Error::Unexpected)));
}

#[test]
fn option_some() {
    let input = Some(4);

    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        input,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn option_none() {
    let input = Option::<u8>::None;

    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        input,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn nested_option_some() {
    let data = [0x1f];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Option<Option<u8>> =
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!());
    assert_eq!(Some(Some(31)), res);
}

#[test]
fn nested_option_none() {
    let data = [0b11011110];
    let mut buffer = ReadBuffer::from(&data);
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Option<Option<u8>> =
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!());
    assert_eq!(None, res);
}

#[test]
fn pass_seq() {
    let input = alloc::vec![1, 2, 3, 4];

    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Result<alloc::vec::Vec<_>, Error> = serde::de::Deserialize::deserialize(&mut de);
    assert_eq!(input, res.unwrap_or_else(|_| panic!()));
}

#[test]
fn map() {
    let input = alloc::collections::BTreeMap::from([(1, "ok"), (2, "nok")]);

    let mut data = [0u8; 30];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        input,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn complex() {
    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    enum DummyOptions {
        A,
        B(u16),
        C { x: Option<u32> },
        D(u8, bool),
    }

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct DummyInner {
        f: f32,
        opt: DummyOptions,
    }

    #[derive(Debug, Serialize, Deserialize, PartialEq)]
    struct Dummy<'a> {
        a: u8,
        b: alloc::string::String,
        c: DummyInner,
        d: DummyInner,
        e: DummyInner,
        f: [u8; 4],
        g: DummyInner,
        h: &'a str,
    }

    let input = Dummy {
        a: 30,
        b: "ok".into(),
        c: DummyInner {
            f: 3.14,
            opt: DummyOptions::A,
        },
        d: DummyInner {
            f: -1.42,
            opt: DummyOptions::B(99),
        },
        e: DummyInner {
            f: 0.25,
            opt: DummyOptions::C { x: Some(99) },
        },
        f: [1, 2, 3, 4],
        g: DummyInner {
            f: 892.345,
            opt: DummyOptions::D(8, true),
        },
        h: "perfect",
    };

    let mut data = [0u8; 128];
    let mut buffer = WriteBuffer::from(&mut data);
    let mut ser = ser::Serializer::from_buffer(&mut buffer);

    input.serialize(&mut ser).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    assert_eq!(
        input,
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!())
    );
}

#[test]
fn nested_flex_map() {
    use alloc::collections::BTreeMap;

    let input = BTreeMap::from([
        (0u8, BTreeMap::from([("it", true), ("works", false)])),
        (1u8, BTreeMap::from([("works", true), ("well", false)])),
    ]);

    let mut data = [0u8; 100];
    let mut buffer = WriteBuffer::from(&mut data);

    write_map(&mut buffer, None).unwrap_or_else(|_| panic!());
    for (key, value) in input.iter() {
        write_unsigned(&mut buffer, *key as _).unwrap_or_else(|_| panic!());
        write_map(&mut buffer, None).unwrap_or_else(|_| panic!());

        for (key, value) in value {
            write_str(&mut buffer, key).unwrap_or_else(|_| panic!());
            write_bool(&mut buffer, *value).unwrap_or_else(|_| panic!());
        }

        write_terminator(&mut buffer).unwrap_or_else(|_| panic!());
    }

    write_terminator(&mut buffer).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res = serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!());
    assert_eq!(input, res);
}

#[test]
fn nested_flex_array() {
    use alloc::vec::Vec;

    let input = Vec::from([Vec::from(["it", "works"]), Vec::from(["works", "well"])]);

    let mut data = [0u8; 100];
    let mut buffer = WriteBuffer::from(&mut data);

    write_array(&mut buffer, None).unwrap_or_else(|_| panic!());
    for value in input.iter() {
        write_array(&mut buffer, None).unwrap_or_else(|_| panic!());

        for value in value {
            write_str(&mut buffer, value).unwrap_or_else(|_| panic!());
        }

        write_terminator(&mut buffer).unwrap_or_else(|_| panic!());
    }

    write_terminator(&mut buffer).unwrap_or_else(|_| panic!());

    let mut buffer = buffer.into_read_buffer();
    let mut de = de::Deserializer::from_buffer(&mut buffer);

    let res: Vec<Vec<&str>> =
        serde::de::Deserialize::deserialize(&mut de).unwrap_or_else(|_| panic!());
    assert_eq!(input, res);
}
