use std::{io, io::Write, marker::PhantomData};
use serde::{ser, Serialize};
use bytes::Bytes;
use byteorder::{BigEndian, ByteOrder, LittleEndian, WriteBytesExt};
use crate::{
  dds::{
    adapters::{no_key, with_key},
    key::Keyed,
  },
  RepresentationIdentifier,
};
struct CountingWrite<W: io::Write> {
  writer: W,
  bytes_written: usize,
}
impl<W> CountingWrite<W>
where
  W: io::Write,
{
  pub fn new(w: W) -> Self {
    Self {
      writer: w,
      bytes_written: 0,
    }
  }
  pub fn count(&self) -> usize {
    self.bytes_written
  }
}
impl<W> io::Write for CountingWrite<W>
where
  W: io::Write,
{
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.writer.write(buf) {
      Ok(c) => {
        self.bytes_written += c;
        Ok(c)
      }
      e => e,
    }
  }
  fn flush(&mut self) -> io::Result<()> {
    self.writer.flush()
  }
}
pub struct CDRSerializerAdapter<D, BO = LittleEndian>
where
  BO: ByteOrder,
{
  phantom: PhantomData<D>,
  ghost: PhantomData<BO>,
}
impl<D, BO> no_key::SerializerAdapter<D> for CDRSerializerAdapter<D, BO>
where
  D: Serialize,
  BO: ByteOrder,
{
  type Error = Error;
  fn output_encoding() -> RepresentationIdentifier {
    RepresentationIdentifier::CDR_LE
  }
  fn to_bytes(value: &D) -> Result<Bytes> {
    let size_estimate = std::mem::size_of_val(value) * 2; let mut buffer: Vec<u8> = Vec::with_capacity(size_estimate);
    to_writer::<D, BO, &mut Vec<u8>>(&mut buffer, value)?;
    Ok(Bytes::from(buffer))
  }
}
impl<D, BO> with_key::SerializerAdapter<D> for CDRSerializerAdapter<D, BO>
where
  D: Keyed + Serialize,
  <D as Keyed>::K: Serialize,
  BO: ByteOrder,
{
  fn key_to_bytes(value: &D::K) -> Result<Bytes> {
    let size_estimate = std::mem::size_of_val(value) * 2; let mut buffer: Vec<u8> = Vec::with_capacity(size_estimate);
    to_writer::<D::K, BO, &mut Vec<u8>>(&mut buffer, value)?;
    Ok(Bytes::from(buffer))
  }
}
pub struct CdrSerializer<W, BO>
where
  W: io::Write,
{
  writer: CountingWrite<W>, phantom: PhantomData<BO>, }
impl<W, BO> CdrSerializer<W, BO>
where
  BO: ByteOrder,
  W: io::Write,
{
  pub fn new(w: W) -> Self {
    Self {
      writer: CountingWrite::new(w),
      phantom: PhantomData,
    }
  }
  fn calculate_padding_need_and_write_padding(&mut self, alignment: usize) -> Result<()> {
    let modulo = self.writer.count() % alignment;
    if modulo != 0 {
      let padding_need: usize = alignment - modulo;
      for _x in 0..padding_need {
        self.writer.write_u8(0)?;
      }
    }
    Ok(())
  }
} pub fn to_writer<T, BO, W>(writer: W, value: &T) -> Result<()>
where
  T: Serialize,
  BO: ByteOrder,
  W: io::Write,
{
  value.serialize(&mut CdrSerializer::<W, BO>::new(writer))
}
pub fn to_writer_endian<T, W>(
  writer: W,
  value: &T,
  encoding: RepresentationIdentifier,
) -> Result<()>
where
  T: Serialize,
  W: io::Write,
{
  match encoding {
    RepresentationIdentifier::CDR_LE => {
      value.serialize(&mut CdrSerializer::<W, LittleEndian>::new(writer))
    }
    _ => value.serialize(&mut CdrSerializer::<W, BigEndian>::new(writer)),
  }
}
#[cfg(test)]
pub(crate) fn to_little_endian_binary<T>(value: &T) -> Result<Vec<u8>>
where
  T: Serialize,
{
  to_bytes::<T, LittleEndian>(value)
}
#[cfg(test)]
fn to_big_endian_binary<T>(value: &T) -> Result<Vec<u8>>
where
  T: Serialize,
{
  to_bytes::<T, BigEndian>(value)
}
pub(crate) fn to_bytes<T, BO>(value: &T) -> Result<Vec<u8>>
where
  T: Serialize,
  BO: ByteOrder,
{
  let mut buffer: Vec<u8> = Vec::with_capacity(std::mem::size_of_val(value) * 2);
  to_writer::<T, BO, &mut Vec<u8>>(&mut buffer, value)?;
  Ok(buffer)
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
  #[error("CDR serialization requires sequence length to be specified at the start.")]
  SequenceLengthUnknown,
  #[error("Serde says:{0}")]
  Serde(String),
  #[error("std::io::Error {0}")]
  Io(#[from] std::io::Error),
}
impl ser::Error for Error {
  fn custom<T: std::fmt::Display>(msg: T) -> Self {
    Self::Serde(msg.to_string())
  }
}
impl<'a, W, BO> ser::Serializer for &'a mut CdrSerializer<W, BO>
where
  BO: ByteOrder,
  W: io::Write,
{
  type Ok = ();
  type Error = Error;
  type SerializeSeq = Self;
  type SerializeTuple = Self;
  type SerializeTupleStruct = Self;
  type SerializeTupleVariant = Self;
  type SerializeMap = Self;
  type SerializeStruct = Self;
  type SerializeStructVariant = Self;
  fn serialize_bool(self, v: bool) -> Result<()> {
    if v {
      self.writer.write_u8(1u8)?;
    } else {
      self.writer.write_u8(0u8)?;
    }
    Ok(())
  }
  fn serialize_u8(self, v: u8) -> Result<()> {
    self.writer.write_u8(v)?;
    Ok(())
  }
  fn serialize_u16(self, v: u16) -> Result<()> {
    self.calculate_padding_need_and_write_padding(2)?;
    self.writer.write_u16::<BO>(v)?;
    Ok(())
  }
  fn serialize_u32(self, v: u32) -> Result<()> {
    self.calculate_padding_need_and_write_padding(4)?;
    self.writer.write_u32::<BO>(v)?;
    Ok(())
  }
  fn serialize_u64(self, v: u64) -> Result<()> {
    self.calculate_padding_need_and_write_padding(8)?;
    self.writer.write_u64::<BO>(v)?;
    Ok(())
  }
  fn serialize_u128(self, v: u128) -> Result<()> {
    self.calculate_padding_need_and_write_padding(16)?;
    self.writer.write_u128::<BO>(v)?;
    Ok(())
  }
  fn serialize_i8(self, v: i8) -> Result<()> {
    self.writer.write_i8(v)?;
    Ok(())
  }
  fn serialize_i16(self, v: i16) -> Result<()> {
    self.calculate_padding_need_and_write_padding(2)?;
    self.writer.write_i16::<BO>(v)?;
    Ok(())
  }
  fn serialize_i32(self, v: i32) -> Result<()> {
    self.calculate_padding_need_and_write_padding(4)?;
    self.writer.write_i32::<BO>(v)?;
    Ok(())
  }
  fn serialize_i64(self, v: i64) -> Result<()> {
    self.calculate_padding_need_and_write_padding(8)?;
    self.writer.write_i64::<BO>(v)?;
    Ok(())
  }
  fn serialize_f32(self, v: f32) -> Result<()> {
    self.calculate_padding_need_and_write_padding(4)?;
    self.writer.write_f32::<BO>(v)?;
    Ok(())
  }
  fn serialize_f64(self, v: f64) -> Result<()> {
    self.calculate_padding_need_and_write_padding(8)?;
    self.writer.write_f64::<BO>(v)?;
    Ok(())
  }
  fn serialize_char(self, v: char) -> Result<()> {
    self.serialize_u32(v as u32)?;
    Ok(())
  }
  fn serialize_str(self, v: &str) -> Result<()> {
    let byte_count: u32 = v.as_bytes().len() as u32 + 1;
    self.serialize_u32(byte_count)?; self.writer.write_all(v.as_bytes())?;
    self.writer.write_u8(0)?; Ok(())
    }
  fn serialize_bytes(self, v: &[u8]) -> Result<()> {
    self.writer.write_all(v)?;
    Ok(())
  }
  fn serialize_none(self) -> Result<()> {
    self.serialize_u32(0) }
  fn serialize_some<T>(self, t: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    self.serialize_u32(1)?; t.serialize(self)?;
    Ok(())
  }
  fn serialize_unit(self) -> Result<()> {
    Ok(())
  }
  fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
    self.serialize_unit()
  }
  fn serialize_unit_variant(
    self,
    _name: &'static str,
    variant_index: u32,
    _variant: &'static str,
  ) -> Result<()> {
    self.serialize_u32(variant_index)
  }
  fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(self)
  }
  fn serialize_newtype_variant<T>(
    self,
    _name: &'static str,
    variant_index: u32,
    _variant: &'static str,
    value: &T,
  ) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    self.serialize_u32(variant_index)?;
    value.serialize(self)
  }
  fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
    match len {
      None => Err(Error::SequenceLengthUnknown),
      Some(elem_count) => {
        self.serialize_u32(elem_count as u32)?;
        Ok(self)
      }
    } } fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
    Ok(self)
  }
  fn serialize_tuple_struct(
    self,
    _name: &'static str,
    _len: usize,
  ) -> Result<Self::SerializeTupleStruct> {
    Ok(self)
  }
  fn serialize_tuple_variant(
    self,
    _name: &'static str,
    variant_index: u32,
    _variant: &'static str,
    _len: usize,
  ) -> Result<Self::SerializeTupleVariant> {
    self.serialize_u32(variant_index)?;
    Ok(self)
  }
  fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
    match len {
      None => Err(Error::SequenceLengthUnknown),
      Some(elem_count) => {
        self.serialize_u32(elem_count as u32)?;
        Ok(self)
      }
    } }
  fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
    Ok(self)
  }
  fn serialize_struct_variant(
    self,
    _name: &'static str,
    variant_index: u32,
    _variant: &'static str,
    _len: usize,
  ) -> Result<Self::SerializeStructVariant> {
    self.serialize_u32(variant_index)?;
    Ok(self)
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeSeq for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_element<T>(&mut self, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeTuple for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_element<T>(&mut self, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeTupleStruct for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_field<T>(&mut self, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeTupleVariant for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_field<T>(&mut self, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeMap for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_key<T>(&mut self, key: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    key.serialize(&mut **self)
  }
  fn serialize_value<T>(&mut self, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeStruct for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)?;
    Ok(())
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
impl<'a, W: io::Write, BO: ByteOrder> ser::SerializeStructVariant for &'a mut CdrSerializer<W, BO> {
  type Ok = ();
  type Error = Error;
  fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
  where
    T: ?Sized + Serialize,
  {
    value.serialize(&mut **self)?;
    Ok(())
  }
  fn end(self) -> Result<()> {
    Ok(())
  }
}
#[cfg(test)]
mod tests {
  use log::info;
  use serde::{Deserialize, Serialize};
  use serde_repr::{Deserialize_repr, Serialize_repr};
  use crate::serialization::{
    cdr_deserializer::deserialize_from_little_endian,
    cdr_serializer::{to_big_endian_binary, to_little_endian_binary},
  };
  #[test]
  fn cdr_serialize_and_deserialize_sequence_of_structs() {
    #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)]
    pub struct MyType {
      first_value: i16,
      second: u8,
    }
    impl MyType {
      pub fn new(first_value: i16, second: u8) -> Self {
        Self {
          first_value,
          second,
        }
      }
    }
    let sequence_of_structs: Vec<MyType> =
      vec![MyType::new(1, 23), MyType::new(2, 34), MyType::new(-3, 45)];
    let serialized = to_little_endian_binary(&sequence_of_structs).unwrap();
    let deserialized: Vec<MyType> = deserialize_from_little_endian(&serialized).unwrap();
    info!("deserialized    {:?}", deserialized);
    info!("serialized    {:?}", serialized);
    assert_eq!(deserialized, sequence_of_structs);
  }
  #[test]
  fn cdr_serialize_enum() {
    #[derive(Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)]
    #[repr(u32)]
    pub enum MyEnumeration {
      First,
      Second,
      Third,
      SevenHundredth = 700,
      }
    let enum_object_1 = MyEnumeration::First;
    let enum_object_2 = MyEnumeration::Second;
    let enum_object_3 = MyEnumeration::Third;
    let enum_object_7 = MyEnumeration::SevenHundredth;
    let serialized_1 = to_little_endian_binary(&enum_object_1).unwrap();
    info!("{:?}", serialized_1);
    let u32_value_1: u32 = deserialize_from_little_endian(&serialized_1).unwrap();
    let deserialized_1: MyEnumeration = deserialize_from_little_endian(&serialized_1).unwrap();
    info!("Deserialized 1: {:?}", deserialized_1);
    assert_eq!(deserialized_1, enum_object_1);
    assert_eq!(u32_value_1, 0);
    let serialized_2 = to_little_endian_binary(&enum_object_2).unwrap();
    info!("{:?}", serialized_2);
    let u32_value_2: u32 = deserialize_from_little_endian(&serialized_2).unwrap();
    let deserialized_2: MyEnumeration = deserialize_from_little_endian(&serialized_2).unwrap();
    info!("Deserialized 2: {:?}", deserialized_2);
    assert_eq!(deserialized_2, enum_object_2);
    assert_eq!(u32_value_2, 1);
    let serialized_3 = to_little_endian_binary(&enum_object_3).unwrap();
    info!("{:?}", serialized_3);
    let deserialized_3: MyEnumeration = deserialize_from_little_endian(&serialized_3).unwrap();
    let u32_value_3: u32 = deserialize_from_little_endian(&serialized_3).unwrap();
    info!("Deserialized 3: {:?}", deserialized_3);
    assert_eq!(deserialized_3, enum_object_3);
    assert_eq!(u32_value_3, 2);
    let serialized_7 = to_little_endian_binary(&enum_object_7).unwrap();
    info!("{:?}", serialized_7);
    let deserialized_7: MyEnumeration = deserialize_from_little_endian(&serialized_7).unwrap();
    let u32_value_7: u32 = deserialize_from_little_endian(&serialized_7).unwrap();
    info!("Deserialized 7: {:?}", deserialized_7);
    assert_eq!(deserialized_7, enum_object_7);
    assert_eq!(u32_value_7, 700);
    }
  #[test]
  fn cdr_serialization_example() {
    #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
    struct Example {
      a: u32,
      b: [u8; 4],
    }
    let o = Example {
      a: 1,
      b: [b'a', b'b', b'c', b'd'],
    };
    let expected_serialization_le: Vec<u8> = vec![0x01, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64];
    let expected_serialization_be: Vec<u8> = vec![0x00, 0x00, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64];
    let serialized_le = to_little_endian_binary(&o).unwrap();
    let serialized_be = to_big_endian_binary(&o).unwrap();
    assert_eq!(serialized_le, expected_serialization_le);
    assert_eq!(serialized_be, expected_serialization_be);
  }
  #[test]
  fn cdr_serialization_test() {
    #[derive(Serialize)]
    struct MyType {
      first_value: u8,
      second_value: i8,
      third_value: i32,
      fourth_value: u64,
      fifth: bool,
    }
    let micky_mouse = MyType {
      first_value: 1,
      second_value: -1,
      third_value: 23,
      fourth_value: 3434343,
      fifth: true,
    };
    let serialized = to_little_endian_binary(&micky_mouse).unwrap();
    let expected: Vec<u8> = vec![
      0x01, 0xff, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x67, 0x67, 0x34, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x01,
    ];
    assert_eq!(expected, serialized);
  }
  #[test]
  fn cdr_serialization_char() {
    #[derive(Serialize)]
    struct MyType {
      first_value: u8,
      second: u8,
      third: u8,
    }
    let micky_mouse = MyType {
      first_value: b'a',
      second: b'b',
      third: b'\xE4', };
    let serialized = to_little_endian_binary(&micky_mouse).unwrap();
    let expected: Vec<u8> = vec![0x61, 0x62, 0xe4];
    assert_eq!(expected, serialized);
  }
  #[test]
  fn cdr_serialization_string() {
    #[derive(Serialize)]
    struct MyType<'a> {
      first_value: &'a str,
    }
    let micky_mouse = MyType {
      first_value: "BLUE",
    };
    let serialized = to_little_endian_binary(&micky_mouse).unwrap();
    let expected: Vec<u8> = vec![0x05, 0x00, 0x00, 0x00, 0x42, 0x4c, 0x55, 0x45, 0x00];
    assert_eq!(expected, serialized);
  }
  #[test]
  fn cdr_serialization_little() {
    let number: u16 = 60000;
    let le = to_little_endian_binary(&number).unwrap();
    let be = to_big_endian_binary(&number).unwrap();
    assert_ne!(le, be);
  }
  #[test]
  fn cdr_serialize_seq() {
    #[derive(Serialize)]
    struct MyType {
      first_value: Vec<i32>,
    }
    let micky_mouse = MyType {
      first_value: vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 123123],
    };
    let serialized = to_little_endian_binary(&micky_mouse).unwrap();
    let expected: Vec<u8> = vec![
      0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
      0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00,
      0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf3,
      0xe0, 0x01, 0x00,
    ];
    assert_eq!(expected, serialized);
  }
}