use std::ops::Range;

use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};

use super::{
    cid::Cid,
    ident::{IdHasher, ID},
    ArmourError,
};
use crate::{
    bytes_unsafe,
    collections::Result,
    dyn_types::key_type::{GetKeyType, KeyBytes, KeyType},
};
use primitive_enum::{FromU8, UnsafeFromU8};

/// Active: 0, Disabled: 1, Deleted: 255
#[derive(
    PartialOrd, Ord, Eq, PartialEq, Clone, Copy, Hash, Serialize, Deserialize, Debug, FromU8,
)]
#[repr(u8)]
pub enum RecordStatus {
    /// 0
    Active = 0,
    /// 1
    Disabled = 1,
    /// 255
    Deleted = 255,
}

impl RecordStatus {
    pub fn is_active(self) -> bool {
        self == RecordStatus::Active
    }
}

impl PartialEq<RecordStatus> for u8 {
    fn eq(&self, other: &RecordStatus) -> bool {
        *self == *other as u8
    }
}

impl Default for RecordStatus {
    fn default() -> Self {
        RecordStatus::Active
    }
}

/// (deleted-disabled, sequence_id)
/// deleted - навсегда, disabled - можно потом восстановить.
/// сохраняем в одном байте информацию о удаленном или отключенном id
/// так так сущность может быть либо удаленной, либо отключенной.
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy)]
#[repr(C)]
pub struct Id<T: IdHasher> {
    pub status: RecordStatus,
    id: ID<T>,
}

// impl custom scalar
// scalar!(Id);

/// ( [0, 0, 0, 0, 0] .. [255, 0, 0, 0, 0] )
const fn not_deleted_range() -> Range<[u8; ID_SIZE]> {
    let from_first_byte = RecordStatus::Active as u8;
    let to_first_byte = RecordStatus::Deleted as u8;
    let from: [u8; ID_SIZE] = [from_first_byte, 0, 0, 0, 0];
    let to: [u8; ID_SIZE] = [to_first_byte, 0, 0, 0, 0];
    from..to
}

const fn deleted_prefix() -> [u8; 1] {
    let byte = RecordStatus::Deleted as u8;
    [byte]
}

impl<T: IdHasher> Id<T> {
    #[inline]
    pub fn get_u32(self) -> u32 {
        self.id.get()
    }

    pub fn get_id(self) -> ID<T> {
        self.id
    }

    pub fn new(id: ID<T>) -> Self {
        Id {
            status: RecordStatus::Active,
            id,
        }
    }

    pub fn new_unsafe(id: u32) -> Self {
        Id {
            status: RecordStatus::Active,
            id: ID::new_unsafe(id),
        }
    }

    pub fn create_with_status(id: ID<T>, status: RecordStatus) -> Self {
        Id { status, id }
    }

    pub fn create_with_status_unsafe(id: u32, status: RecordStatus) -> Self {
        Id {
            status,
            id: ID::new_unsafe(id),
        }
    }

    #[inline]
    pub fn get_bytes(self) -> [u8; ID_SIZE] {
        let first_byte = self.status as u8;
        let bytes: [u8; 4] = self.id.to_le_bytes();
        [first_byte, bytes[3], bytes[2], bytes[1], bytes[0]]
    }

    #[inline]
    pub fn from_bytes(bytes: [u8; ID_SIZE]) -> Self {
        let first_byte = bytes[0];
        let status = RecordStatus::from_unsafe(first_byte);

        let id_bytes: [u8; 4] = [bytes[4], bytes[3], bytes[2], bytes[1]];
        let id = ID::new_unsafe(u32::from_le_bytes(id_bytes));

        Id { status, id }
    }

    #[inline]
    pub fn deleted_prefix() -> [u8; 1] {
        deleted_prefix()
    }

    /// ( [0, 0, 0, 0, 0] .. [255, 0, 0, 0, 0] )
    #[inline]
    pub fn not_deleted_range() -> Range<[u8; ID_SIZE]> {
        not_deleted_range()
    }

    #[inline]
    pub fn get_record_status(self) -> RecordStatus {
        self.status
    }

    pub fn set_record_status(&mut self, status: RecordStatus) {
        self.status = status;
    }

    pub fn copy_with_status(self, status: RecordStatus) -> Self {
        Self::create_with_status_unsafe(self.id.get(), status)
    }
}

impl<T: IdHasher> From<u32> for Id<T> {
    fn from(val: u32) -> Self {
        Id::new_unsafe(val)
    }
}

impl<T: IdHasher> From<u64> for Id<T> {
    fn from(val: u64) -> Self {
        Id::new_unsafe(val as u32)
    }
}

impl<T: IdHasher> From<Id<T>> for u32 {
    fn from(val: Id<T>) -> u32 {
        val.get_u32()
    }
}

impl<T: IdHasher> Serialize for Id<T> {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        let id = self.id.ser();
        let mut s = serializer.serialize_struct("Id", 2)?;
        s.serialize_field("status", &self.status)?;
        s.serialize_field("id", &id)?;
        s.end()
    }
}

const ID_SIZE: usize = 5;

impl<T: IdHasher> Cid for Id<T> {
    type B = [u8; ID_SIZE];

    fn bytes(&self) -> Self::B {
        self.get_bytes()
    }

    fn from_bytes(bytes: &[u8]) -> Result<Self> {
        let bytes: [u8; ID_SIZE] = bytes.try_into().map_err(|_| ArmourError::FromBytesError)?;
        Ok(Id::from_bytes(bytes))
    }

    fn from_bytes_unsafe(bytes: &[u8]) -> Self {
        let bytes: [u8; ID_SIZE] = *bytes_unsafe(bytes);
        Id::from_bytes(bytes)
    }
}

impl<T: IdHasher> GetKeyType for Id<T> {
    /// 5
    const SIZE: u8 = ID_SIZE as u8;

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

    fn as_bytes(&self) -> KeyBytes {
        let mut key = KeyBytes::new_const::<{ ID_SIZE as u8 }>();

        let first_byte = self.status as u8;
        let bytes: [u8; 4] = self.id.to_be_bytes();

        unsafe {
            *key.get_unchecked_mut(0) = first_byte;
            key.get_unchecked_mut(1..5).copy_from_slice(&bytes)
        }

        // key.copy_from_slice(&self.get_bytes());
        key
    }
}
