//! RangeIndex 存根结构 (1:1 对标 Garnet RangeIndexManager.Index.cs 中 RangeIndexStub)
//!
//! 定长 35 字节二进制结构,存储于底层 Tsavorite / HybridLog 主存储日志中,记录 BfTree 配置与在线实例指针。

use crate::{
  error::{Error, Result},
  types::StorageBackendType,
};

/// 存根字节总长度 (1:1 对标 Garnet RangeIndexStub.Size = 35)
pub const RANGE_INDEX_STUB_SIZE: usize = 35;

/// 从定长存根缓冲区的 `off` 偏移读取 N 字节小端整数
///
/// 安全:buf 恒为 35 字节,off 与 N 均为编译期常量且落在界内,切片绝不越界
#[inline]
fn le<const N: usize>(buf: &[u8; RANGE_INDEX_STUB_SIZE], off: usize) -> [u8; N] {
  buf[off..off + N].try_into().unwrap()
}

/// 字段偏移量 (小端定长布局)
const TREE_HANDLE_OFFSET: usize = 0;
const CACHE_SIZE_OFFSET: usize = 8;
const MIN_RECORD_SIZE_OFFSET: usize = 16;
const MAX_RECORD_SIZE_OFFSET: usize = 20;
const MAX_KEY_LEN_OFFSET: usize = 24;
const LEAF_PAGE_SIZE_OFFSET: usize = 28;
const STORAGE_BACKEND_OFFSET: usize = 32;
const FLAGS_OFFSET: usize = 33;
const SERIALIZATION_PHASE_OFFSET: usize = 34;

/// 标志位掩码定义
const FLUSHED_BIT_MASK: u8 = 1 << 0;
const RECOVERED_BIT_MASK: u8 = 1 << 1;
const TRANSFERRED_BIT_MASK: u8 = 1 << 2;

/// 存储在底层存储引擎日志中的定长元数据存根 (35 字节二进制定长结构)
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub struct RangeIndexStub {
  /// 在线 BfTreeService 句柄裸指针 (8B)
  pub tree_handle: u64,
  /// 环形缓冲区大小 (8B)
  pub cache_size: u64,
  /// 最小记录大小 (4B)
  pub min_record_size: u32,
  /// 最大记录大小 (4B)
  pub max_record_size: u32,
  /// 最大键长度 (4B)
  pub max_key_len: u32,
  /// 叶子页面大小 (4B)
  pub leaf_page_size: u32,
  /// 存储后端 (1B: 0=Disk/Std, 1=Memory)
  pub storage_backend: u8,
  /// 标志位 (1B: Flushed, Recovered, Transferred)
  pub flags: u8,
  /// 检查点快照协调阶段号 (1B)
  pub serialization_phase: u8,
}

impl RangeIndexStub {
  /// 创建全新未刷盘的存根
  pub fn new(
    tree_handle: u64,
    cache_size: u64,
    min_record_size: u32,
    max_record_size: u32,
    max_key_len: u32,
    leaf_page_size: u32,
    storage_backend: impl Into<StorageBackendType>,
  ) -> Self {
    Self {
      tree_handle,
      cache_size,
      min_record_size,
      max_record_size,
      max_key_len,
      leaf_page_size,
      storage_backend: storage_backend.into().to_u8(),
      flags: 0,
      serialization_phase: 0,
    }
  }

  /// 检查是否已被刷入冷存储区
  #[inline]
  pub const fn is_flushed(&self) -> bool {
    (self.flags & FLUSHED_BIT_MASK) != 0
  }

  /// 设置刷盘标志位
  #[inline]
  pub fn set_flushed(&mut self, flushed: bool) {
    if flushed {
      self.flags |= FLUSHED_BIT_MASK;
    } else {
      self.flags &= !FLUSHED_BIT_MASK;
    }
  }

  /// 检查是否从快照文件恢复
  #[inline]
  pub const fn is_recovered(&self) -> bool {
    (self.flags & RECOVERED_BIT_MASK) != 0
  }

  /// 设置从快照恢复标志位
  #[inline]
  pub fn set_recovered(&mut self, recovered: bool) {
    if recovered {
      self.flags |= RECOVERED_BIT_MASK;
    } else {
      self.flags &= !RECOVERED_BIT_MASK;
    }
  }

  /// 检查所有权是否已转移到新记录
  #[inline]
  pub const fn is_transferred(&self) -> bool {
    (self.flags & TRANSFERRED_BIT_MASK) != 0
  }

  /// 设置所有权转移标志位
  #[inline]
  pub fn set_transferred(&mut self, transferred: bool) {
    if transferred {
      self.flags |= TRANSFERRED_BIT_MASK;
    } else {
      self.flags &= !TRANSFERRED_BIT_MASK;
    }
  }

  /// 重置所有标志位为 0 (1:1 对标 Garnet ResetFlags)
  #[inline]
  pub fn reset_flags(&mut self) {
    self.flags = 0;
  }

  /// 清零树句柄裸指针 (1:1 对标 Garnet ClearTreeHandle)
  #[inline]
  pub fn clear_tree_handle(&mut self) {
    self.tree_handle = 0;
  }

  /// 标记已从检查点恢复并清零句柄 (1:1 对标 Garnet MarkRecoveredFromCheckpoint)
  #[inline]
  pub fn mark_recovered_from_checkpoint(&mut self) {
    self.tree_handle = 0;
    self.set_recovered(true);
  }

  /// 重新激活恢复的句柄并清除恢复标记 (1:1 对标 Garnet RecreateIndex)
  #[inline]
  pub fn recreate_index(&mut self, new_tree_handle: u64) {
    self.tree_handle = new_tree_handle;
    self.set_recovered(false);
  }

  /// 编码为定长 35 字节切片 (零堆分配,小端对齐,1:1 对标 Garnet 与存储引擎规范)
  pub fn encode(&self) -> [u8; RANGE_INDEX_STUB_SIZE] {
    let mut buf = [0u8; RANGE_INDEX_STUB_SIZE];
    buf[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].copy_from_slice(&self.tree_handle.to_le_bytes());
    buf[CACHE_SIZE_OFFSET..MIN_RECORD_SIZE_OFFSET].copy_from_slice(&self.cache_size.to_le_bytes());
    buf[MIN_RECORD_SIZE_OFFSET..MAX_RECORD_SIZE_OFFSET]
      .copy_from_slice(&self.min_record_size.to_le_bytes());
    buf[MAX_RECORD_SIZE_OFFSET..MAX_KEY_LEN_OFFSET]
      .copy_from_slice(&self.max_record_size.to_le_bytes());
    buf[MAX_KEY_LEN_OFFSET..LEAF_PAGE_SIZE_OFFSET].copy_from_slice(&self.max_key_len.to_le_bytes());
    buf[LEAF_PAGE_SIZE_OFFSET..STORAGE_BACKEND_OFFSET]
      .copy_from_slice(&self.leaf_page_size.to_le_bytes());
    buf[STORAGE_BACKEND_OFFSET] = self.storage_backend;
    buf[FLAGS_OFFSET] = self.flags;
    buf[SERIALIZATION_PHASE_OFFSET] = self.serialization_phase;
    buf
  }

  /// 写入输出切片中 (零堆分配,就地编码)
  pub fn encode_into(&self, out: &mut [u8]) -> Result<()> {
    if out.len() < RANGE_INDEX_STUB_SIZE {
      return Err(Error::InvalidArgument(format!(
        "输出切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
        out.len()
      )));
    }
    out[..RANGE_INDEX_STUB_SIZE].copy_from_slice(&self.encode());
    Ok(())
  }

  /// 从定长切片解码为 RangeIndexStub (小端对齐,零堆分配)
  pub fn decode(bytes: &[u8]) -> Result<Self> {
    let buf: &[u8; RANGE_INDEX_STUB_SIZE] = bytes
      .get(..RANGE_INDEX_STUB_SIZE)
      .and_then(|s| s.try_into().ok())
      .ok_or_else(|| {
        Error::InvalidArgument(format!(
          "RangeIndexStub 切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
          bytes.len()
        ))
      })?;

    Ok(Self {
      tree_handle: u64::from_le_bytes(le(buf, TREE_HANDLE_OFFSET)),
      cache_size: u64::from_le_bytes(le(buf, CACHE_SIZE_OFFSET)),
      min_record_size: u32::from_le_bytes(le(buf, MIN_RECORD_SIZE_OFFSET)),
      max_record_size: u32::from_le_bytes(le(buf, MAX_RECORD_SIZE_OFFSET)),
      max_key_len: u32::from_le_bytes(le(buf, MAX_KEY_LEN_OFFSET)),
      leaf_page_size: u32::from_le_bytes(le(buf, LEAF_PAGE_SIZE_OFFSET)),
      storage_backend: buf[STORAGE_BACKEND_OFFSET],
      flags: buf[FLAGS_OFFSET],
      serialization_phase: buf[SERIALIZATION_PHASE_OFFSET],
    })
  }

  /// 直接在二进制切片上就地清零树指针 (1:1 对标 Garnet ClearTreeHandle / InvalidateStub)
  #[inline]
  pub fn slice_clear_tree_handle(slice: &mut [u8]) -> Result<()> {
    if slice.len() < CACHE_SIZE_OFFSET {
      return Err(Error::InvalidArgument("切片长度不足 8 字节".into()));
    }
    slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].fill(0);
    Ok(())
  }

  /// 直接在二进制切片上就地置位刷盘标志 (1:1 对标 Garnet SetFlushedFlag)
  #[inline]
  pub fn slice_set_flushed(slice: &mut [u8], flushed: bool) -> Result<()> {
    Self::validate_slice(slice)?;
    if flushed {
      slice[FLAGS_OFFSET] |= FLUSHED_BIT_MASK;
    } else {
      slice[FLAGS_OFFSET] &= !FLUSHED_BIT_MASK;
    }
    Ok(())
  }

  /// 直接在二进制切片上就地置位转移标志 (1:1 对标 Garnet SetTransferredFlag)
  #[inline]
  pub fn slice_set_transferred(slice: &mut [u8], transferred: bool) -> Result<()> {
    Self::validate_slice(slice)?;
    if transferred {
      slice[FLAGS_OFFSET] |= TRANSFERRED_BIT_MASK;
    } else {
      slice[FLAGS_OFFSET] &= !TRANSFERRED_BIT_MASK;
    }
    Ok(())
  }

  /// 直接在二进制切片上标记从检查点恢复 (1:1 对标 Garnet MarkRecoveredFromCheckpoint)
  #[inline]
  pub fn slice_mark_recovered_from_checkpoint(slice: &mut [u8]) -> Result<()> {
    Self::validate_slice(slice)?;
    slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].fill(0);
    slice[FLAGS_OFFSET] |= RECOVERED_BIT_MASK;
    Ok(())
  }

  /// 直接在二进制切片上更新重新激活句柄 (1:1 对标 Garnet RecreateIndex)
  #[inline]
  pub fn slice_recreate_index(slice: &mut [u8], new_tree_handle: u64) -> Result<()> {
    Self::validate_slice(slice)?;
    slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].copy_from_slice(&new_tree_handle.to_le_bytes());
    slice[FLAGS_OFFSET] &= !RECOVERED_BIT_MASK;
    Ok(())
  }

  /// 校验切片长度至少容纳完整存根
  #[inline]
  fn validate_slice(slice: &[u8]) -> Result<()> {
    if slice.len() < RANGE_INDEX_STUB_SIZE {
      return Err(Error::InvalidArgument(format!(
        "切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
        slice.len()
      )));
    }
    Ok(())
  }
}