//! Type definitions for Concurrent HNSW

use std::time::Instant;
use tokio::sync::oneshot;

/// Vector write operation types
#[derive(Debug, Clone)]
pub enum VectorWriteOp {
    /// Insert a vector
    Insert {
        id: String,
        vector: Vec<f32>,
    },
    /// Delete a vector
    Delete {
        id: String,
    },
    /// Batch insert
    BatchInsert {
        items: Vec<(String, Vec<f32>)>,
    },
}

impl VectorWriteOp {
    /// Get the primary ID for routing
    pub fn primary_id(&self) -> Option<&str> {
        match self {
            VectorWriteOp::Insert { id, .. } => Some(id),
            VectorWriteOp::Delete { id } => Some(id),
            VectorWriteOp::BatchInsert { items } => items.first().map(|(id, _)| id.as_str()),
        }
    }
    
    /// Check if this is a batch operation
    pub fn is_batch(&self) -> bool {
        matches!(self, VectorWriteOp::BatchInsert { .. })
    }
    
    /// Get approximate size in bytes
    pub fn size_bytes(&self) -> usize {
        match self {
            VectorWriteOp::Insert { id, vector } => {
                id.len() + vector.len() * 4
            }
            VectorWriteOp::Delete { id } => id.len(),
            VectorWriteOp::BatchInsert { items } => {
                items.iter().map(|(id, v)| id.len() + v.len() * 4).sum()
            }
        }
    }
}

/// Vector write request with completion channel
pub struct VectorWriteRequest {
    /// Operation to perform
    pub op: VectorWriteOp,
    
    /// Request sequence number
    pub sequence: u64,
    
    /// Completion notification channel
    pub completion: Option<oneshot::Sender<VectorWriteResult>>,
    
    /// Request creation time
    pub created_at: Instant,
}

impl VectorWriteRequest {
    /// Create a new insert request
    pub fn insert(id: String, vector: Vec<f32>, sequence: u64) -> Self {
        Self {
            op: VectorWriteOp::Insert { id, vector },
            sequence,
            completion: None,
            created_at: Instant::now(),
        }
    }
    
    /// Create a new delete request
    pub fn delete(id: String, sequence: u64) -> Self {
        Self {
            op: VectorWriteOp::Delete { id },
            sequence,
            completion: None,
            created_at: Instant::now(),
        }
    }
    
    /// Create with completion channel
    pub fn with_completion(mut self, tx: oneshot::Sender<VectorWriteResult>) -> Self {
        self.completion = Some(tx);
        self
    }
    
    /// Get elapsed time since creation
    pub fn elapsed_us(&self) -> u64 {
        self.created_at.elapsed().as_micros() as u64
    }
}

/// Result of a vector write operation
#[derive(Debug, Clone)]
pub struct VectorWriteResult {
    /// Whether the operation succeeded
    pub success: bool,
    
    /// Internal ID assigned (for insert)
    pub internal_id: Option<usize>,
    
    /// Shard ID where the vector was stored
    pub shard_id: usize,
    
    /// Latency in microseconds
    pub latency_us: u64,
    
    /// Error message if failed
    pub error: Option<String>,
}

impl VectorWriteResult {
    /// Create a success result
    pub fn success(internal_id: usize, shard_id: usize, latency_us: u64) -> Self {
        Self {
            success: true,
            internal_id: Some(internal_id),
            shard_id,
            latency_us,
            error: None,
        }
    }
    
    /// Create a success result for delete
    pub fn delete_success(shard_id: usize, latency_us: u64) -> Self {
        Self {
            success: true,
            internal_id: None,
            shard_id,
            latency_us,
            error: None,
        }
    }
    
    /// Create a failure result
    pub fn failure(shard_id: usize, error: String, latency_us: u64) -> Self {
        Self {
            success: false,
            internal_id: None,
            shard_id,
            latency_us,
            error: Some(error),
        }
    }
}

/// Search result from concurrent HNSW
#[derive(Debug, Clone)]
pub struct VectorSearchResult {
    /// External ID of the vector
    pub id: String,
    /// Distance to query vector
    pub distance: f32,
    /// Shard ID where the vector is stored
    pub shard_id: usize,
}

/// Error type for vector shard operations
#[derive(Debug, Clone)]
pub enum VectorShardError {
    /// Dimension mismatch
    DimensionMismatch { expected: usize, got: usize },
    
    /// Duplicate ID
    DuplicateId(String),
    
    /// ID not found
    NotFound(String),
    
    /// Capacity exceeded
    CapacityExceeded,
    
    /// Queue full (backpressure)
    QueueFull,
    
    /// Write timeout
    WriteTimeout,
    
    /// Internal error
    Internal(String),
}

impl std::fmt::Display for VectorShardError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            VectorShardError::DimensionMismatch { expected, got } => {
                write!(f, "Dimension mismatch: expected {}, got {}", expected, got)
            }
            VectorShardError::DuplicateId(id) => {
                write!(f, "Duplicate ID: {}", id)
            }
            VectorShardError::NotFound(id) => {
                write!(f, "Vector not found: {}", id)
            }
            VectorShardError::CapacityExceeded => {
                write!(f, "Index capacity exceeded")
            }
            VectorShardError::QueueFull => {
                write!(f, "Write queue full (backpressure)")
            }
            VectorShardError::WriteTimeout => {
                write!(f, "Write operation timed out")
            }
            VectorShardError::Internal(msg) => {
                write!(f, "Internal error: {}", msg)
            }
        }
    }
}

impl std::error::Error for VectorShardError {}

impl From<crate::vector::hnsw::HNSWError> for VectorShardError {
    fn from(err: crate::vector::hnsw::HNSWError) -> Self {
        match err {
            crate::vector::hnsw::HNSWError::DimensionMismatch { expected, got } => {
                VectorShardError::DimensionMismatch { expected, got }
            }
            crate::vector::hnsw::HNSWError::DuplicateId(id) => {
                VectorShardError::DuplicateId(id)
            }
            crate::vector::hnsw::HNSWError::IdNotFound(id) => {
                VectorShardError::NotFound(id)
            }
            crate::vector::hnsw::HNSWError::CapacityExceeded => {
                VectorShardError::CapacityExceeded
            }
            err => VectorShardError::Internal(err.to_string()),
        }
    }
}
