//! RAG Knowledge Base Indexer
//!
//! Indexes Nickel schemas and configuration examples into the RAG system
//! for retrieval-augmented generation. Supports both in-memory and persistent
//! indexing for efficient startup and search.

use anyhow::Result;
use std::path::PathBuf;
use typedialog_core::ai::rag::RagSystem;

/// Build knowledge base from available schemas and examples
///
/// Indexes all Nickel schema files and TOML configuration examples
/// found in the project's examples directories.
pub async fn build_knowledge_base(rag: &mut RagSystem) -> Result<()> {
    tracing::info!("Building RAG knowledge base from project examples");

    let mut documents = Vec::new();
    let _doc_count = documents.len();

    // Index Nickel schemas - looking in common example directories
    let schema_dirs = vec![
        "examples/07-nickel-generation",
        "examples/nickel",
        "examples/schemas",
    ];

    for dir in schema_dirs {
        if let Ok(entries) = std::fs::read_dir(dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.extension().map(|ext| ext == "ncl").unwrap_or(false) {
                    if let Ok(content) = std::fs::read_to_string(&path) {
                        let doc_id = path.display().to_string();
                        tracing::debug!(path = %doc_id, "Indexing Nickel schema");
                        documents.push((doc_id, content));
                    }
                }
            }
        }
    }

    // Index TOML configuration examples
    let form_dirs = vec!["examples", "examples/forms", "examples/configs"];

    for dir in form_dirs {
        if let Ok(entries) = std::fs::read_dir(dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.extension().map(|ext| ext == "toml").unwrap_or(false) {
                    if let Ok(content) = std::fs::read_to_string(&path) {
                        let doc_id = path.display().to_string();
                        tracing::debug!(path = %doc_id, "Indexing TOML configuration");
                        documents.push((doc_id, content));
                    }
                }
            }
        }
    }

    if documents.is_empty() {
        tracing::warn!("No documents found to index");
        return Ok(());
    }

    tracing::info!(count = documents.len(), "Adding documents to RAG index");

    // Batch add documents for efficiency
    rag.add_documents_batch(documents)?;

    // Save to persistent storage for faster startup
    let cache_path = ".typedialog/knowledge-base.bin";
    if let Some(parent) = PathBuf::from(cache_path).parent() {
        drop(std::fs::create_dir_all(parent));
    }

    rag.save_to_file(cache_path)?;
    tracing::info!(path = cache_path, "RAG knowledge base cached");

    Ok(())
}

/// Load knowledge base from cache if available
///
/// Attempts to load a previously indexed knowledge base from disk.
/// Falls back to building a new index if cache is unavailable.
pub async fn load_or_build_knowledge_base(rag: &mut RagSystem) -> Result<()> {
    let cache_path = ".typedialog/knowledge-base.bin";

    // Try to load from cache
    if PathBuf::from(cache_path).exists() {
        match RagSystem::load_from_file(cache_path) {
            Ok(cached_rag) => {
                tracing::info!(path = cache_path, "Loaded RAG knowledge base from cache");
                *rag = cached_rag;
                return Ok(());
            }
            Err(e) => {
                tracing::warn!(error = %e, "Failed to load cached knowledge base, rebuilding");
            }
        }
    }

    // Build new index if cache unavailable or corrupted
    build_knowledge_base(rag).await
}

/// Get statistics about the indexed knowledge base
///
/// Returns information about what's been indexed including
/// document counts by type.
pub struct KnowledgeBaseStats {
    /// Total number of indexed documents
    pub total_documents: usize,

    /// Number of Nickel schemas
    pub schema_count: usize,

    /// Number of TOML configurations
    pub config_count: usize,

    /// Cache file path
    pub cache_path: String,

    /// Whether cache exists
    pub cache_exists: bool,
}

/// Get knowledge base statistics
pub fn get_knowledge_base_stats() -> KnowledgeBaseStats {
    let cache_path = ".typedialog/knowledge-base.bin";

    // Count documents by scanning directories
    let mut schema_count = 0;
    let mut config_count = 0;

    let schema_dirs = vec![
        "examples/07-nickel-generation",
        "examples/nickel",
        "examples/schemas",
    ];

    for dir in schema_dirs {
        if let Ok(entries) = std::fs::read_dir(dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.extension().map(|ext| ext == "ncl").unwrap_or(false) {
                    schema_count += 1;
                }
            }
        }
    }

    let form_dirs = vec!["examples", "examples/forms", "examples/configs"];

    for dir in form_dirs {
        if let Ok(entries) = std::fs::read_dir(dir) {
            for entry in entries.flatten() {
                let path = entry.path();
                if path.extension().map(|ext| ext == "toml").unwrap_or(false) {
                    config_count += 1;
                }
            }
        }
    }

    let cache_exists = PathBuf::from(cache_path).exists();

    KnowledgeBaseStats {
        total_documents: schema_count + config_count,
        schema_count,
        config_count,
        cache_path: cache_path.to_string(),
        cache_exists,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_knowledge_base_stats_creation() {
        let stats = get_knowledge_base_stats();
        assert_eq!(stats.cache_path, ".typedialog/knowledge-base.bin");
    }

    #[test]
    fn test_knowledge_base_stats_total() {
        let stats = get_knowledge_base_stats();
        assert_eq!(
            stats.total_documents,
            stats.schema_count + stats.config_count
        );
    }

    #[test]
    fn test_cache_path_consistency() {
        let stats = get_knowledge_base_stats();
        assert!(stats.cache_path.contains("knowledge-base.bin"));
    }

    #[test]
    fn test_stats_has_expected_fields() {
        let stats = get_knowledge_base_stats();
        let _ = stats.schema_count;
        let _ = stats.config_count;
        let _ = stats.total_documents;
        // Stats created successfully with all fields
    }
}
