//! `FastEmbed` local embedding provider

use crate::embeddings::EmbeddingProvider;
use crate::error::Result;

/// Local embedding provider using `FastEmbed`
///
/// Provides embedding generation without external API calls.
/// Uses local models for privacy and offline capability.
///
/// Default model: BAAI/bge-small-en-v1.5 (384 dimensions)
/// Supports CPU inference with minimal memory footprint.
#[cfg(feature = "fastembed")]
pub struct FastEmbedProvider {
    model: fastembed::FlagEmbedding,
    dimensions: usize,
}

#[cfg(feature = "fastembed")]
impl FastEmbedProvider {
    /// Create a new `FastEmbed` provider with default settings
    ///
    /// Uses BAAI/bge-small-en-v1.5 model by default (384 dimensions).
    ///
    /// # Errors
    ///
    /// Returns error if model initialization fails (e.g., download issues).
    pub fn new() -> Result<Self> {
        let model = fastembed::FlagEmbedding::try_new(Default::default()).map_err(|e| {
            crate::error::KbError::Embedding(format!("Failed to initialize FastEmbed: {}", e))
        })?;

        Ok(Self {
            dimensions: 384, // BAAI/bge-small-en-v1.5 dimensions
            model,
        })
    }

    /// Create with custom dimensions (for compatibility)
    ///
    /// Note: Actual dimensions will be determined by the model,
    /// this parameter is for API compatibility.
    ///
    /// # Errors
    ///
    /// Returns error if model initialization fails.
    pub fn with_dimensions(dimensions: usize) -> Result<Self> {
        let model = fastembed::FlagEmbedding::try_new(Default::default()).map_err(|e| {
            crate::error::KbError::Embedding(format!("Failed to initialize FastEmbed: {}", e))
        })?;

        Ok(Self { model, dimensions })
    }
}

#[cfg(feature = "fastembed")]
impl EmbeddingProvider for FastEmbedProvider {
    fn embed(&self, text: &str) -> Result<Vec<f32>> {
        let embeddings = self
            .model
            .embed(vec![text], None)
            .map_err(|e| crate::error::KbError::Embedding(format!("Embedding error: {}", e)))?;

        Ok(embeddings
            .into_iter()
            .next()
            .ok_or_else(|| crate::error::KbError::Embedding("No embedding returned".to_string()))?)
    }

    fn dimensions(&self) -> usize {
        self.dimensions
    }
}

/// Fallback for when feature is not enabled
#[cfg(not(feature = "fastembed"))]
pub struct FastEmbedProvider {
    dimensions: usize,
}

#[cfg(not(feature = "fastembed"))]
impl FastEmbedProvider {
    /// Create a new `FastEmbed` provider (stub when feature not enabled)
    ///
    /// # Errors
    ///
    /// Always returns error since fastembed feature is not enabled
    pub fn new() -> Result<Self> {
        Err(crate::error::KbError::Embedding(
            "fastembed feature not enabled. Enable with: cargo build --features fastembed"
                .to_string(),
        ))
    }

    /// Create with custom dimensions (stub when feature not enabled)
    #[must_use]
    pub fn with_dimensions(dimensions: usize) -> Self {
        Self { dimensions }
    }
}

#[cfg(not(feature = "fastembed"))]
impl EmbeddingProvider for FastEmbedProvider {
    fn embed(&self, _text: &str) -> Result<Vec<f32>> {
        Err(crate::error::KbError::Embedding(
            "fastembed feature not enabled".to_string(),
        ))
    }

    fn dimensions(&self) -> usize {
        self.dimensions
    }
}
