use core::{
    num::NonZeroU32,
    ops::{Deref, DerefMut},
};

use primitive_enum::FromU8;
use serde::{Deserialize, Serialize};

use crate::collections::Result;

#[derive(Eq, PartialEq, Clone, Copy, Serialize, Deserialize, Debug, FromU8)]
#[repr(u8)]
pub enum KeyType {
    U8,
    U32,
    // U64,
    // ArrayBytes,
}

const SIZE: u8 = 24;
const SIZE_1: u8 = SIZE - 1;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
#[repr(transparent)]
pub struct KeyBytes([u8; SIZE as usize]);

impl KeyBytes {
    pub fn new(s: u8) -> Self {
        debug_assert!(
            s <= SIZE_1,
            "SIZE must be less than KeyBytes SIZE-1, s: {s}, {SIZE_1}"
        );
        let mut arr = [0u8; SIZE as usize];
        arr[0] = s;
        Self(arr)
    }

    pub const fn new_const<const S: u8>() -> Self {
        debug_assert!(S <= SIZE_1, "SIZE must be less than KeyBytes SIZE-1");
        let mut arr = [0u8; SIZE as usize];
        arr[0] = S;
        Self(arr)
    }
}

impl Deref for KeyBytes {
    type Target = [u8];

    fn deref(&self) -> &Self::Target {
        let len = unsafe { *self.0.get_unchecked(0) as usize };
        unsafe { self.0.get_unchecked(1..=len) }
    }
}

impl DerefMut for KeyBytes {
    fn deref_mut(&mut self) -> &mut Self::Target {
        let len = unsafe { *self.0.get_unchecked(0) as usize };
        unsafe { self.0.get_unchecked_mut(1..=len) }
    }
}

// for dyn sized types
// fn dyn_sized_bytes() -> SmallVec<[u8; 32]> {
//     todo!()
// }

pub trait GetKeyType: Sized {
    const SIZE: u8;

    fn typ() -> &'static [KeyType];

    fn as_bytes(&self) -> KeyBytes;

    /// s: string of values with '-' separated, e.: 1-5467-23
    fn from_str(s: &str) -> Option<KeyBytes> {
        let mut splitted = s.split('-').filter(|s| !s.is_empty());
        let typ = Self::typ();
        let size: u8 = typ.iter().fold(0, |acc, t| match t {
            KeyType::U8 => acc + 1,
            KeyType::U32 => acc + 4,
        });

        // let mut vec = vec![0; size];
        let mut key = KeyBytes::new(size);

        let mut cursor = 0;
        for t in typ {
            match t {
                KeyType::U8 => {
                    let s = splitted.next()?;
                    let u = s.parse::<u8>().ok()?;
                    unsafe {
                        *key.get_unchecked_mut(cursor) = u;
                    }
                    // vec[cursor] = u;
                    cursor += 1;
                }
                KeyType::U32 => {
                    let s = splitted.next()?;
                    let u = s.parse::<u32>().ok()?;
                    unsafe {
                        key.get_unchecked_mut(cursor..cursor + 4)
                            .copy_from_slice(&u.to_be_bytes());
                    }
                    // (&mut vec[cursor..cursor + 4]).copy_from_slice(&u.to_be_bytes());
                    cursor += 4;
                }
            }
        }
        Some(key)
    }
}

impl GetKeyType for u32 {
    const SIZE: u8 = 4;

    #[inline]
    fn typ() -> &'static [KeyType] {
        &[KeyType::U32]
    }

    fn as_bytes(&self) -> KeyBytes {
        let mut key = KeyBytes::new_const::<{ Self::SIZE }>();
        key.copy_from_slice(&self.to_be_bytes());
        key
    }
}

impl GetKeyType for NonZeroU32 {
    const SIZE: u8 = 4;

    #[inline]
    fn typ() -> &'static [KeyType] {
        &[KeyType::U32]
    }

    fn as_bytes(&self) -> KeyBytes {
        let mut key = KeyBytes::new_const::<{ Self::SIZE }>();
        key.copy_from_slice(&self.get().to_be_bytes());
        key
    }
}
