use bytemuck::{Pod, Zeroable};

// A wrapper struct for spatial indexing, containing the node's ID and its 3D position.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct NodePoint {
    pub id: u64,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct NodeRec {
    pub id: u64,
    pub morton_code: u64, // Changed back to u64 for alignment
    pub x: f32,
    pub y: f32,
    pub z: f32,
    pub edge_off: u32,
    pub edge_len: u32,
    pub flags: u32,
    // MVCC fields for Tuple-MVCC
    pub begin_ts: u64, // Transaction timestamp when this version was created
    pub end_ts: u64,   // Transaction timestamp when this version was superseded (0 = current)
    // Transaction tracking fields (Phase 1: WAL-MVCC Integration)
    pub tx_id: u64, // Transaction ID that created this version (0 = system/bootstrap)
    pub visibility: u8, // VERSION_UNCOMMITTED(0), VERSION_COMMITTED(1), VERSION_ABORTED(2)
    pub _padding: [u8; 7], // Padding for 8-byte alignment (Pod trait requirement)
}
// Size: 72 bytes (was 56 bytes, increased by 16 bytes for transaction tracking)

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct EdgeRec {
    pub src: u64, // Source node index
    pub dst: u64,
    pub w: f32, // Semantic weight
    pub flags: u32,
    // MVCC fields for Tuple-MVCC
    pub begin_ts: u64, // Transaction timestamp when this version was created
    pub end_ts: u64,   // Transaction timestamp when this version was superseded (0 = current)
    // Transaction tracking fields (Phase 1: WAL-MVCC Integration)
    pub tx_id: u64, // Transaction ID that created this version (0 = system/bootstrap)
    pub visibility: u8, // VERSION_UNCOMMITTED(0), VERSION_COMMITTED(1), VERSION_ABORTED(2)
    pub _padding: [u8; 7], // Padding for 8-byte alignment (Pod trait requirement)
}
// Size: 48 bytes (was 32 bytes, increased by 16 bytes for transaction tracking)

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
#[allow(dead_code)]
pub struct OctreeNode {
    pub min_x: f32,
    pub min_y: f32,
    pub min_z: f32,
    pub max_x: f32,
    pub max_y: f32,
    pub max_z: f32,
    pub children_ptr: u64, // Pointer to children nodes or 0 if leaf
    pub data_ptr: u64,     // Pointer to data (e.g., NodeRec offsets)
    pub data_len: u32,     // Number of data items
    pub _padding: u32,     // For Pod compatibility
}

pub const WAL_ENTRY_NODE_CREATE: u8 = 1;
pub const WAL_ENTRY_EDGE_CREATE: u8 = 2;
pub const WAL_ENTRY_NODE_DELETE: u8 = 3;
pub const WAL_ENTRY_EDGE_DELETE: u8 = 4;
pub const WAL_ENTRY_PROPERTY_UPDATE: u8 = 5;
pub const WAL_ENTRY_BEGIN_TX: u8 = 6;
pub const WAL_ENTRY_COMMIT_TX: u8 = 7;
pub const WAL_ENTRY_ABORT_TX: u8 = 8;

pub const NODE_FLAG_TOMBSTONE: u32 = 0x1;
pub const EDGE_FLAG_TOMBSTONE: u32 = 0x1;

// Version visibility states for transaction tracking
pub const VERSION_UNCOMMITTED: u8 = 0; // Created by active transaction, invisible to others
pub const VERSION_COMMITTED: u8 = 1; // Committed, visible to snapshots >= commit_ts
pub const VERSION_ABORTED: u8 = 2; // Rolled back, should be GC'd

/// Fixed-size record for CFG block metadata (176 bytes for string storage)
/// Stores terminator type and location info for each block
#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct MetadataRec {
    /// Null-terminated string for block kind (max 31 bytes + null)
    pub block_kind: [u8; 32],
    /// Null-terminated string for terminator type (max 63 bytes + null)
    pub terminator: [u8; 64],
    pub byte_start: u64,
    pub byte_end: u64,
    pub start_line: u64,
    pub start_col: u64,
    pub end_line: u64,
    pub end_col: u64,
    pub _padding: [u8; 32],
}

impl MetadataRec {
    pub const SIZE: usize = 176; // 32 + 64 + 6*8 + 32 = 176 bytes

    /// Create from string values
    #[allow(clippy::too_many_arguments)]
    pub fn from_strings(
        block_kind: &str,
        terminator: &str,
        byte_start: u64,
        byte_end: u64,
        start_line: u64,
        start_col: u64,
        end_line: u64,
        end_col: u64,
    ) -> Self {
        let mut rec = Self {
            block_kind: [0u8; 32],
            terminator: [0u8; 64],
            byte_start,
            byte_end,
            start_line,
            start_col,
            end_line,
            end_col,
            _padding: [0u8; 32],
        };

        // Copy block_kind (truncate if needed) - already zero-initialized
        let kind_bytes = block_kind.as_bytes();
        let len = kind_bytes.len().min(31);
        if len > 0 {
            rec.block_kind[..len].copy_from_slice(&kind_bytes[..len]);
        }
        // block_kind[len..] is already 0 from initialization

        // Copy terminator (truncate if needed) - already zero-initialized
        let term_bytes = terminator.as_bytes();
        let len = term_bytes.len().min(63);
        if len > 0 {
            rec.terminator[..len].copy_from_slice(&term_bytes[..len]);
        }
        // terminator[len..] is already 0 from initialization

        rec
    }

    /// Get block kind as string
    pub fn get_block_kind(&self) -> String {
        let null_pos = self.block_kind.iter().position(|&b| b == 0).unwrap_or(32);
        String::from_utf8_lossy(&self.block_kind[..null_pos]).to_string()
    }

    /// Get terminator as string
    pub fn get_terminator(&self) -> String {
        let null_pos = self.terminator.iter().position(|&b| b == 0).unwrap_or(64);
        String::from_utf8_lossy(&self.terminator[..null_pos]).to_string()
    }
}

impl Default for MetadataRec {
    fn default() -> Self {
        Self {
            block_kind: [0u8; 32],
            terminator: [0u8; 64],
            byte_start: 0,
            byte_end: 0,
            start_line: 0,
            start_col: 0,
            end_line: 0,
            end_col: 0,
            _padding: [0u8; 32],
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct WalEntry {
    pub timestamp: u64,    // 8 bytes - Epoch when entry was created
    pub node_id: u64,      // 8 bytes - Node ID for node operations
    pub edge_dst: u64,     // 8 bytes - Edge destination for edge operations
    pub x: f32,            // 4 bytes - X coordinate
    pub y: f32,            // 4 bytes - Y coordinate
    pub z: f32,            // 4 bytes - Z coordinate
    pub edge_w: f32,       // 4 bytes - Edge weight
    pub entry_type: u8,    // 1 byte - Entry type (NODE_CREATE, BEGIN_TX, etc.)
    pub _padding: [u8; 7], // 7 bytes - Padding for alignment
    pub tx_id: u64,        // 8 bytes - Transaction ID (0 = auto-commit)
    pub lsn: u64,          // 8 bytes - Log Sequence Number
}
