//! Configuration for Concurrent HNSW Index

use crate::types::HNSWConfig;
use crate::storage::concurrent::{
    WriteQueueConfig, BatchConfig, BackpressureConfig, ShardStrategy,
};

/// Configuration for ConcurrentHNSWIndex
#[derive(Debug, Clone)]
pub struct ConcurrentHNSWConfig {
    /// Base HNSW configuration (applied to each shard)
    pub hnsw: HNSWConfig,
    
    /// Number of shards (0 = auto based on CPU count)
    pub shard_count: usize,
    
    /// Shard routing strategy
    pub shard_strategy: ShardStrategy,
    
    /// Write queue configuration
    pub queue_config: WriteQueueConfig,
    
    /// Batch aggregation configuration
    pub batch_config: BatchConfig,
    
    /// Backpressure configuration
    pub backpressure_config: BackpressureConfig,
    
    /// Whether to auto-start batch workers
    pub auto_start: bool,
}

impl Default for ConcurrentHNSWConfig {
    fn default() -> Self {
        Self {
            hnsw: HNSWConfig::default(),
            shard_count: 0, // Auto
            shard_strategy: ShardStrategy::Hash,
            queue_config: WriteQueueConfig {
                capacity: 10_000,
                ..Default::default()
            },
            batch_config: BatchConfig {
                max_batch_size: 200, // HNSW batch insert is efficient
                max_wait_ms: 20,
                ..Default::default()
            },
            backpressure_config: BackpressureConfig::default(),
            auto_start: true,
        }
    }
}

impl ConcurrentHNSWConfig {
    /// Create with custom HNSW config
    pub fn with_hnsw(hnsw: HNSWConfig) -> Self {
        Self {
            hnsw,
            ..Default::default()
        }
    }
    
    /// Create high-throughput configuration
    /// 
    /// Optimized for maximum write throughput with larger batches.
    pub fn high_throughput(hnsw: HNSWConfig) -> Self {
        Self {
            hnsw,
            shard_count: 0, // Auto
            shard_strategy: ShardStrategy::Hash,
            queue_config: WriteQueueConfig {
                capacity: 20_000,
                ..Default::default()
            },
            batch_config: BatchConfig {
                max_batch_size: 500,
                max_wait_ms: 50,
                ..Default::default()
            },
            backpressure_config: BackpressureConfig::permissive(),
            auto_start: true,
        }
    }
    
    /// Create low-latency configuration
    /// 
    /// Optimized for fast individual writes with smaller batches.
    pub fn low_latency(hnsw: HNSWConfig) -> Self {
        Self {
            hnsw,
            shard_count: 0,
            shard_strategy: ShardStrategy::Hash,
            queue_config: WriteQueueConfig {
                capacity: 5_000,
                ..Default::default()
            },
            batch_config: BatchConfig {
                max_batch_size: 50,
                max_wait_ms: 5,
                ..Default::default()
            },
            backpressure_config: BackpressureConfig::strict(),
            auto_start: true,
        }
    }
    
    /// Set shard count
    pub fn with_shards(mut self, count: usize) -> Self {
        self.shard_count = count;
        self
    }
    
    /// Set shard strategy
    pub fn with_strategy(mut self, strategy: ShardStrategy) -> Self {
        self.shard_strategy = strategy;
        self
    }
    
    /// Set batch size
    pub fn with_batch_size(mut self, size: usize) -> Self {
        self.batch_config.max_batch_size = size;
        self
    }
    
    /// Set max wait time for batching
    pub fn with_max_wait_ms(mut self, ms: u64) -> Self {
        self.batch_config.max_wait_ms = ms;
        self
    }
    
    /// Get effective shard count (resolves 0 to CPU count)
    pub fn effective_shard_count(&self) -> usize {
        if self.shard_count == 0 {
            // Use number of CPU cores, minimum 4, maximum 64
            let cpus = num_cpus::get();
            cpus.max(4).min(64)
        } else {
            self.shard_count
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_default_config() {
        let config = ConcurrentHNSWConfig::default();
        assert_eq!(config.shard_count, 0);
        assert_eq!(config.batch_config.max_batch_size, 200);
    }
    
    #[test]
    fn test_high_throughput_config() {
        let hnsw = HNSWConfig::default();
        let config = ConcurrentHNSWConfig::high_throughput(hnsw);
        assert_eq!(config.batch_config.max_batch_size, 500);
        assert_eq!(config.batch_config.max_wait_ms, 50);
    }
    
    #[test]
    fn test_low_latency_config() {
        let hnsw = HNSWConfig::default();
        let config = ConcurrentHNSWConfig::low_latency(hnsw);
        assert_eq!(config.batch_config.max_batch_size, 50);
        assert_eq!(config.batch_config.max_wait_ms, 5);
    }
    
    #[test]
    fn test_effective_shard_count() {
        let config = ConcurrentHNSWConfig::default();
        let effective = config.effective_shard_count();
        assert!(effective >= 4);
        assert!(effective <= 64);
        
        let config = ConcurrentHNSWConfig::default().with_shards(16);
        assert_eq!(config.effective_shard_count(), 16);
    }
}
