use core::mem::{align_of, size_of};

use bitcode::{Decode, Encode};

use crate::{
  codec::checked_record_size,
  error::{Error, Result},
};

/// 记录头字节大小(16 字节)
pub const HEADER_SIZE: usize = 16;

/// 48 位逻辑地址掩码(低 48 位全 1: 0x0000_FFFF_FFFF_FFFF,最大寻址 256TB)
pub const ADDRESS_MASK: u64 = (1u64 << 48) - 1;

/// 8 位填充词偏移量(bits 48..55,每词 8 字节,最多 255 * 8 = 2040 字节松弛空间,对标 Garnet RecordDataHeader.FillerWords)
pub const FILLER_WORDS_SHIFT: u32 = 48;
pub const FILLER_WORDS_MASK: u64 = 0xFFu64 << FILLER_WORDS_SHIFT;

/// 3 位单字节填充余数偏移量(bits 56..58,支持 0..7 字节精细填充,消除非 8 字节对齐差值的物理长度漂移)
pub const FILLER_REM_SHIFT: u32 = 56;
pub const FILLER_REM_MASK: u64 = 0x07u64 << FILLER_REM_SHIFT;

/// 复合松弛空间掩码(bits 48..58,覆盖 8 字节块与单字节余数)
pub const FILLER_TOTAL_MASK: u64 = FILLER_WORDS_MASK | FILLER_REM_MASK;

/// 最大可表示的单记录松弛填充字节数(255 * 8 + 7 = 2047 字节)
pub const MAX_FILLER_BYTES: usize = 2047;

/// 修改位掩码(第 59 位,对标 C# Tsavorite RecordInfo.Modified)
pub const MODIFIED_BIT: u64 = 1u64 << 59;

/// 密封位掩码(第 60 位,对标 C# Tsavorite RecordInfo.IsSealed / TrySeal,复活槽位锁定与冻结)
pub const SEALED_BIT: u64 = 1u64 << 60;

/// Checkpoint 检查点新版本标记位掩码(第 61 位,对标 C# Tsavorite RecordInfo.IsInNewVersion)
pub const IN_NEW_VERSION_BIT: u64 = 1u64 << 61;

/// 读缓存标记位掩码(第 62 位,对标 C# Tsavorite RecordInfo.IsReadCache / LogAddress.kIsReadCacheBitMask)
pub const READ_CACHE_BIT: u64 = 1u64 << 62;

/// 墓碑标记位掩码(第 63 位: 0x8000_0000_0000_0000)
pub const TOMBSTONE_BIT: u64 = 1u64 << 63;

// 编译期静态断言 1:位域封闭性 —— 48 位地址 + 11 位松弛填充(8+3)+ 5 个标志位
// 恰好无缝铺满 64 位字,任何位既不重叠也不遗漏,宽度分配在编译期即可证明正确。
const _: () = assert!(
  (ADDRESS_MASK
    | FILLER_TOTAL_MASK
    | MODIFIED_BIT
    | SEALED_BIT
    | IN_NEW_VERSION_BIT
    | READ_CACHE_BIT
    | TOMBSTONE_BIT)
    == u64::MAX
);

// 编译期静态断言 2:内存布局与磁盘序列化布局严格一致(16 字节、8 字节对齐,
// 对标 C# Constants.FixedHeaderSize = RecordInfo.Size + RecordDataHeader.Size 与 kRecordAlignment)
const _: () = assert!(size_of::<RecordHeader>() == HEADER_SIZE);
const _: () = assert!(align_of::<RecordHeader>() == 8);

/// 16 字节紧凑记录头结构体(C 对齐)
///
/// 内存排布(小端 16 字节):
/// - `[0..8)`: `prev_address: u64`(低 48 位为前驱版本逻辑地址形成反向链表,bits 48..55 为 FillerWords 动态松弛填充词,bits 56..58 为 FillerRem 单字节余数,bit 59 为 MODIFIED 修改位,bit 60 为 SEALED 密封位,bit 61 为 IN_NEW_VERSION 纪元位,bit 62 为 READ_CACHE 读缓存位,最高位 1<<63 为 TOMBSTONE 墓碑标记)
/// - `[8..12)`: `key_len: u32`(键长度)
/// - `[12..16)`: `val_len: u32`(值长度)
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)]
#[repr(C)]
pub struct RecordHeader {
  /// 前驱版本逻辑地址与墓碑标记复合字段
  pub prev_address: u64,
  /// 键长度(字节数)
  pub key_len: u32,
  /// 值长度(字节数)
  pub val_len: u32,
}

impl RecordHeader {
  /// 构造新的记录头并校验 48 位地址有效性(const fn)
  #[inline]
  pub const fn new(prev_addr: u64, key_len: u32, val_len: u32, is_tombstone: bool) -> Result<Self> {
    if prev_addr & !ADDRESS_MASK != 0 {
      return Err(Error::AddressOverflow(prev_addr));
    }
    Ok(Self {
      prev_address: prev_addr | if is_tombstone { TOMBSTONE_BIT } else { 0 },
      key_len,
      val_len,
    })
  }

  /// 直接从原始数据快速构造(无地址检查,适用于内部或高性能路径)
  #[inline]
  pub const fn from_raw(prev_address: u64, key_len: u32, val_len: u32) -> Self {
    Self {
      prev_address,
      key_len,
      val_len,
    }
  }

  /// 提取 48 位前驱版本逻辑地址
  #[inline]
  pub const fn address(&self) -> u64 {
    self.prev_address & ADDRESS_MASK
  }

  /// 是否带有墓碑删除标记
  #[inline(always)]
  pub const fn is_tombstone(&self) -> bool {
    (self.prev_address & TOMBSTONE_BIT) != 0
  }

  /// 是否带有修改标记(对标 C# RecordInfo.Modified)
  #[inline(always)]
  pub const fn is_modified(&self) -> bool {
    (self.prev_address & MODIFIED_BIT) != 0
  }

  /// 设置或清除修改标记(const fn)
  #[inline(always)]
  pub const fn set_modified(&mut self, modified: bool) {
    if modified {
      self.prev_address |= MODIFIED_BIT;
    } else {
      self.prev_address &= !MODIFIED_BIT;
    }
  }

  /// 是否带有密封标记(对标 C# RecordInfo.IsSealed / TrySeal)
  #[inline(always)]
  pub const fn is_sealed(&self) -> bool {
    (self.prev_address & SEALED_BIT) != 0
  }

  /// 设置或清除密封标记(const fn)
  #[inline(always)]
  pub const fn set_sealed(&mut self, sealed: bool) {
    if sealed {
      self.prev_address |= SEALED_BIT;
    } else {
      self.prev_address &= !SEALED_BIT;
    }
  }

  /// 是否属于 Checkpoint 新版本纪元(对标 C# RecordInfo.IsInNewVersion)
  #[inline(always)]
  pub const fn is_in_new_version(&self) -> bool {
    (self.prev_address & IN_NEW_VERSION_BIT) != 0
  }

  /// 设置或清除 Checkpoint 新版本纪元标记(const fn)
  #[inline(always)]
  pub const fn set_in_new_version(&mut self, in_new_version: bool) {
    if in_new_version {
      self.prev_address |= IN_NEW_VERSION_BIT;
    } else {
      self.prev_address &= !IN_NEW_VERSION_BIT;
    }
  }

  /// 是否标记为读缓存记录(对标 C# RecordInfo.IsReadCache / LogAddress.kIsReadCacheBitMask)
  #[inline(always)]
  pub const fn is_read_cache(&self) -> bool {
    (self.prev_address & READ_CACHE_BIT) != 0
  }

  /// 设置或清除读缓存标记(const fn)
  #[inline(always)]
  pub const fn set_read_cache(&mut self, is_read_cache: bool) {
    if is_read_cache {
      self.prev_address |= READ_CACHE_BIT;
    } else {
      self.prev_address &= !READ_CACHE_BIT;
    }
  }

  /// 提取 8 位松弛填充词数量(每词代表 8 字节填充,对标 Garnet RecordDataHeader.FillerWords)
  #[inline(always)]
  pub const fn filler_words(&self) -> u8 {
    ((self.prev_address & FILLER_WORDS_MASK) >> FILLER_WORDS_SHIFT) as u8
  }

  /// 提取 3 位单字节填充余数(0..7 字节)
  #[inline(always)]
  pub const fn filler_rem(&self) -> u8 {
    ((self.prev_address & FILLER_REM_MASK) >> FILLER_REM_SHIFT) as u8
  }

  /// 获取松弛填充字节总数(FillerWords * 8 + FillerRem,单字节级高精度)
  #[inline(always)]
  pub const fn filler_bytes(&self) -> usize {
    ((self.filler_words() as usize) << 3) | (self.filler_rem() as usize)
  }

  /// 一步设置完整的松弛填充字节数(自动分解为 8 字节词与单字节余数,超出 [MAX_FILLER_BYTES] 时静默钳位)
  #[inline(always)]
  pub const fn set_filler_bytes(&mut self, total_bytes: usize) {
    let clamped = if total_bytes > MAX_FILLER_BYTES {
      MAX_FILLER_BYTES
    } else {
      total_bytes
    };
    let words = ((clamped >> 3) as u64) << FILLER_WORDS_SHIFT;
    let rem = ((clamped & 7) as u64) << FILLER_REM_SHIFT;
    self.prev_address = (self.prev_address & !FILLER_TOTAL_MASK) | words | rem;
  }

  /// 设置 8 位松弛填充词数量(保留余数与其他高位标记)
  #[inline(always)]
  pub const fn set_filler_words(&mut self, words: u8) {
    self.prev_address =
      (self.prev_address & !FILLER_WORDS_MASK) | ((words as u64) << FILLER_WORDS_SHIFT);
  }

  /// 获取当前记录槽位物理容纳值的最大字节容量(val_len + filler_bytes)
  #[inline(always)]
  pub const fn val_capacity(&self) -> usize {
    (self.val_len as usize).saturating_add(self.filler_bytes())
  }

  /// 获取键长度
  #[inline]
  pub const fn key_len(&self) -> u32 {
    self.key_len
  }

  /// 获取值长度
  #[inline]
  pub const fn val_len(&self) -> u32 {
    self.val_len
  }

  /// 获取整条记录(头 + 键 + 值)的理论逻辑字节长度
  #[inline]
  pub const fn record_size(&self) -> usize {
    HEADER_SIZE
      .saturating_add(self.key_len as usize)
      .saturating_add(self.val_len as usize)
  }

  /// 获取整条记录在物理上占据的总字节大小(头 + 键 + 值 + 松弛填充)
  #[inline(always)]
  pub const fn physical_size(&self) -> usize {
    self.record_size().saturating_add(self.filler_bytes())
  }

  /// 安全计算整条记录理论字节长度(包含 16B 记录头),若计算溢出 usize 则返回 None
  #[inline]
  pub const fn checked_record_size(&self) -> Option<usize> {
    checked_record_size(self.key_len as usize, self.val_len as usize)
  }

  /// 安全计算整条记录物理字节大小(头 + 键 + 值 + 松弛填充),若溢出返回 None
  #[inline(always)]
  pub const fn checked_physical_size(&self) -> Option<usize> {
    match self.checked_record_size() {
      Some(s) => s.checked_add(self.filler_bytes()),
      None => None,
    }
  }

  /// 更新前驱版本逻辑地址(保留高位所有元数据,const fn)
  #[inline]
  pub const fn set_address(&mut self, prev_addr: u64) -> Result<()> {
    if prev_addr & !ADDRESS_MASK != 0 {
      return Err(Error::AddressOverflow(prev_addr));
    }
    self.prev_address = (prev_addr & ADDRESS_MASK) | (self.prev_address & !ADDRESS_MASK);
    Ok(())
  }

  /// 设置或清除墓碑标记(保留原有前驱地址与松弛填充词,const fn)
  #[inline]
  pub const fn set_tombstone(&mut self, is_tombstone: bool) {
    if is_tombstone {
      self.prev_address |= TOMBSTONE_BIT;
    } else {
      self.prev_address &= !TOMBSTONE_BIT;
    }
  }

  /// 翻转墓碑标记位,并返回翻转后的墓碑状态(const fn)
  #[inline(always)]
  pub const fn flip_tombstone(&mut self) -> bool {
    self.prev_address ^= TOMBSTONE_BIT;
    self.is_tombstone()
  }

  /// 判断是否可以在原位等长更新指定长度的值(要求非墓碑且新值长度严格一致,const fn)
  #[inline(always)]
  pub const fn can_update_in_place(&self, new_val_len: usize) -> bool {
    !self.is_tombstone() && self.val_len as usize == new_val_len
  }

  /// 判断是否可以利用动态松弛原位更新指定长度的值(要求非墓碑且新值长度不超过槽位最大物理容量)
  #[inline(always)]
  pub const fn can_update_with_slack(&self, new_val_len: usize) -> bool {
    !self.is_tombstone()
      && new_val_len <= self.val_capacity()
      && (self.val_capacity() - new_val_len) <= MAX_FILLER_BYTES
  }

  /// 使用 bitcode 编码为二进制字节向量
  #[inline]
  pub fn encode_bitcode(&self) -> Vec<u8> {
    bitcode::encode(self)
  }

  /// 从 bitcode 二进制切片解码记录头
  #[inline]
  pub fn decode_bitcode(src: &[u8]) -> Result<Self> {
    bitcode::decode(src).map_err(Error::from)
  }

  /// 编码为 16 字节定长数组(小端编码,const fn)
  #[inline]
  pub const fn to_bytes(&self) -> [u8; HEADER_SIZE] {
    let p = self.prev_address.to_le_bytes();
    let k = self.key_len.to_le_bytes();
    let v = self.val_len.to_le_bytes();
    [
      p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], k[0], k[1], k[2], k[3], v[0], v[1], v[2],
      v[3],
    ]
  }

  /// 从 16 字节定长数组直接解码记录头(const fn)
  #[inline]
  pub const fn from_bytes(bytes: [u8; HEADER_SIZE]) -> Self {
    let prev_address = u64::from_le_bytes([
      bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
    ]);
    let key_len = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
    let val_len = u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
    Self {
      prev_address,
      key_len,
      val_len,
    }
  }

  /// 将记录头编码写入目标切片(零堆分配)
  #[inline]
  pub fn write_to_slice(&self, dst: &mut [u8]) -> Result<()> {
    if let Some(chunk) = dst.first_chunk_mut::<HEADER_SIZE>() {
      *chunk = self.to_bytes();
      Ok(())
    } else {
      Err(Error::BufferTooShort {
        expected: HEADER_SIZE,
        actual: dst.len(),
      })
    }
  }

  /// 从切片前 16 字节解码记录头(const fn,复用 [Self::from_bytes] 零中间拷贝)
  #[inline]
  pub const fn from_slice(src: &[u8]) -> Result<Self> {
    match src.first_chunk::<HEADER_SIZE>() {
      Some(chunk) => Ok(Self::from_bytes(*chunk)),
      None => Err(Error::BufferTooShort {
        expected: HEADER_SIZE,
        actual: src.len(),
      }),
    }
  }

  /// 头部是否为全零空记录(对标 C# RecordInfo.IsNull 与 RecordDataHeader.GetRecordLength 零头守卫)
  ///
  /// Rust 将 C# 的 RecordInfo(8B)与长度字段(RDH)合并为 16 字节头,故空记录判定覆盖
  /// 前驱地址、键长、值长三者同时为零(前驱地址为 0 但键值非零属合法创世记录,不算空头)。
  /// 扫描器遇到空头应按最小 16 字节记录推进,严格对标 C# 零 RDH 守卫语义。
  #[inline(always)]
  pub const fn is_null(&self) -> bool {
    self.prev_address == 0 && self.key_len == 0 && self.val_len == 0
  }
}