//! see [Packet]

use std::fmt::Display;

use half::f16;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};

/// A `u16` encoded in little-endian.
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable, PartialEq, Eq)]
#[repr(C, packed)]
pub struct u16_le([u8; 2]);

/// An `f16` encoded in little-endian.
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, FromBytes, IntoBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
pub struct f16_le(u16_le);

/// Top-level type describing the handwriting disk-format.
#[derive(FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
pub struct DiskFormat {
    pub header: Header,

    /// A packed array of [Stroke]s.
    pub strokes: [u8],
}

pub const V1: u16_le = u16_le::new(1);

#[derive(FromBytes, IntoBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
pub struct Header {
    /// Version of the disk format
    pub version: u16_le,
}

#[derive(FromBytes, IntoBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
pub struct RawStrokeHeader {
    /// Number of points in the stroke.
    pub len: u16_le,
}

#[derive(FromBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
pub struct RawStroke {
    pub header: RawStrokeHeader,
    pub positions: [f16_le],
}

impl RawStroke {
    pub const MIN_LEN: usize = size_of::<RawStrokeHeader>();
}

impl u16_le {
    pub const fn new(init: u16) -> Self {
        u16_le(init.to_le_bytes())
    }
}

impl f16_le {
    pub const fn new(init: f16) -> Self {
        f16_le(u16_le::new(init.to_bits()))
    }
}

impl Display for u16_le {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        u16::from(*self).fmt(f)
    }
}

impl From<u16_le> for u16 {
    fn from(value: u16_le) -> Self {
        u16::from_le_bytes(value.0)
    }
}

impl From<f16_le> for f16 {
    fn from(value: f16_le) -> Self {
        f16::from_bits(u16::from(value.0))
    }
}

impl From<u16> for u16_le {
    fn from(value: u16) -> Self {
        u16_le::new(value)
    }
}

impl From<f16> for f16_le {
    fn from(value: f16) -> Self {
        f16_le::new(value)
    }
}
