// src/api/sdk.rs
//! SDK for interacting with mem0 from Rust applications.

use std::sync::Arc;
use serde_json::Value;

use crate::memory::core_manager::MemoryManager;
use crate::memory::vector::vector_search::{VectorSearch, SearchOptions};
// Use domain types for traits and provider clients for completion services
use cyrup_domain::{
    completion::CompletionProvider,
    chat::Message,
    error::CompletionError};
// REMOVED: cyrup_provider - use model-info + http3 directly
// use cyrup_provider::{
//     openai::OpenAIClient,
//     anthropic::AnthropicClient};
use crate::memory::utils::error::Result;
use crate::memory::schema::memory_schema::Memory;
use crate::memory::schema::relationship_schema::Relationship;

/// Content analysis result for backward compatibility
#[derive(Debug, Clone)]
pub struct ContentAnalysis {
    pub summary: String,
    pub key_concepts: Vec<String>,
    pub sentiment: Option<String>,
    pub topics: Vec<String>,
    pub confidence: f64}

/// Relationship analysis result for backward compatibility
#[derive(Debug, Clone)]
pub struct RelationshipAnalysis {
    pub relationship_type: String,
    pub strength: f64,
    pub description: String,
    pub confidence: f64}

/// Memory SDK for interacting with mem0
pub struct MemorySDK {
    /// Memory manager
    memory_manager: Arc<dyn MemoryManager>,
    /// Vector search
    vector_search: Arc<VectorSearch>,
    /// Completion provider
    completion_provider: Arc<dyn CompletionProvider>}

impl MemorySDK {
    /// Create a new MemorySDK
    pub fn new(
        memory_manager: Arc<dyn MemoryManager>,
        vector_search: Arc<VectorSearch>,
        completion_provider: Arc<dyn CompletionProvider>,
    ) -> Self {
        Self {
            memory_manager,
            vector_search,
            completion_provider}
    }
    
    /// Create a memory
    pub async fn create_memory(
        &self,
        content: &str,
        metadata: Option<Value>,
        embedding: Option<&[f32]>,
    ) -> Result<String> {
        self.memory_manager.create_memory(content, metadata, embedding).await
    }
    
    /// Get a memory by ID
    pub async fn get_memory(&self, id: &str) -> Result<Memory> {
        self.memory_manager.get_memory(id).await
    }
    
    /// Update a memory
    pub async fn update_memory(
        &self,
        id: &str,
        content: Option<&str>,
        metadata: Option<Value>,
        embedding: Option<&[f32]>,
    ) -> Result<()> {
        self.memory_manager.update_memory(id, content, metadata, embedding).await
    }
    
    /// Delete a memory
    pub async fn delete_memory(&self, id: &str) -> Result<()> {
        self.memory_manager.delete_memory(id).await
    }
    
    /// List memories
    pub async fn list_memories(
        &self,
        limit: usize,
        offset: usize,
        filter: Option<&str>,
    ) -> Result<Vec<Memory>> {
        self.memory_manager.list_memories(limit, offset, filter).await
    }
    
    /// Search memories by text
    pub async fn search_memories(
        &self,
        query: &str,
        limit: Option<usize>,
        min_similarity: Option<f32>,
    ) -> Result<Vec<Memory>> {
        let search_options = SearchOptions {
            limit,
            min_similarity,
            filters: None,
            include_vectors: Some(false),
            include_metadata: Some(true)};
        
        let search_results = self.vector_search.search_by_text(query, Some(search_options)).await?;
        
        let mut memories = Vec::new();
        for result in search_results {
            if let Ok(memory) = self.memory_manager.get_memory(&result.id).await {
                memories.push(memory);
            }
        }
        
        Ok(memories)
    }
    
    /// Create a relationship between memories
    pub async fn create_relationship(
        &self,
        source_id: &str,
        target_id: &str,
        relationship_type: &str,
        metadata: Option<Value>,
    ) -> Result<String> {
        self.memory_manager.create_relationship(source_id, target_id, relationship_type, metadata).await
    }
    
    /// Get a relationship by ID
    pub async fn get_relationship(&self, id: &str) -> Result<Relationship> {
        self.memory_manager.get_relationship(id).await
    }
    
    /// Delete a relationship
    pub async fn delete_relationship(&self, id: &str) -> Result<()> {
        self.memory_manager.delete_relationship(id).await
    }
    
    /// List relationships
    pub async fn list_relationships(
        &self,
        limit: usize,
        offset: usize,
        filter: Option<&str>,
    ) -> Result<Vec<Relationship>> {
        self.memory_manager.list_relationships(limit, offset, filter).await
    }
    
    /// Get relationships for a memory
    pub async fn get_memory_relationships(
        &self,
        memory_id: &str,
        relationship_type: Option<&str>,
        direction: Option<&str>,
    ) -> Result<Vec<Relationship>> {
        self.memory_manager.get_memory_relationships(memory_id, relationship_type, direction).await
    }
    
    /// Analyze content using completion provider
    pub async fn analyze_content(&self, content: &str) -> Result<ContentAnalysis> {
        let analysis_prompt = format!(
            "Analyze the following content and provide a summary, key concepts, sentiment, and topics:\n\n{}",
            content
        );

        // Use streaming interface and collect result
        let stream = self.completion_provider.prompt(&analysis_prompt);
        let mut response = String::new();
        
        use futures_util::StreamExt;
        let mut stream = stream;
        while let Some(chunk) = stream.next().await {
            if let Some(content) = chunk.content {
                response.push_str(&content);
            }
        }

        // Parse response into ContentAnalysis (simplified parsing)
        Ok(ContentAnalysis {
            summary: response.lines().take(2).collect::<Vec<_>>().join(" "),
            key_concepts: vec!["concept1".to_string(), "concept2".to_string()], // Placeholder
            sentiment: Some("neutral".to_string()),
            topics: vec!["general".to_string()], // Placeholder  
            confidence: 0.8})
    }
    
    /// Analyze relationship between contents using completion provider
    pub async fn analyze_relationship(
        &self,
        content1: &str,
        content2: &str,
    ) -> Result<RelationshipAnalysis> {
        let relationship_prompt = format!(
            "Analyze the relationship between these two pieces of content:\n\nContent 1: {}\n\nContent 2: {}",
            content1, content2
        );

        // Use streaming interface and collect result
        let stream = self.completion_provider.prompt(&relationship_prompt);
        let mut response = String::new();
        
        use futures_util::StreamExt;
        let mut stream = stream;
        while let Some(chunk) = stream.next().await {
            if let Some(content) = chunk.content {
                response.push_str(&content);
            }
        }

        // Parse response into RelationshipAnalysis (simplified parsing)
        Ok(RelationshipAnalysis {
            relationship_type: "related".to_string(),
            strength: 0.7,
            description: response.lines().take(1).collect::<Vec<_>>().join(""),
            confidence: 0.8})
    }
    
    /// Generate completion using provider streaming interface
    pub async fn generate_completion(
        &self,
        messages: Vec<std::collections::HashMap<String, String>>,
    ) -> Result<String> {
        // Convert messages to simple prompt (simplified approach)
        let prompt = messages
            .iter()
            .map(|msg| msg.get("content").unwrap_or(&String::new()).clone())
            .collect::<Vec<_>>()
            .join("\n");

        // Use streaming interface and collect result
        let stream = self.completion_provider.prompt(&prompt);
        let mut response = String::new();
        
        use futures_util::StreamExt;
        let mut stream = stream;
        while let Some(chunk) = stream.next().await {
            if let Some(content) = chunk.content {
                response.push_str(&content);
            }
        }

        Ok(response)
    }
    
    /// Generate completion with tools (placeholder implementation)
    pub async fn generate_completion_with_tools(
        &self,
        messages: Vec<std::collections::HashMap<String, String>>,
        _tools: Vec<std::collections::HashMap<String, String>>,
    ) -> Result<std::collections::HashMap<String, String>> {
        let completion = self.generate_completion(messages).await?;
        
        let mut result = std::collections::HashMap::new();
        result.insert("content".to_string(), completion);
        result.insert("tool_calls".to_string(), "[]".to_string()); // Placeholder
        
        Ok(result)
    }
    
    /// Generate JSON completion
    pub async fn generate_json_completion(
        &self,
        messages: Vec<std::collections::HashMap<String, String>>,
    ) -> Result<String> {
        let mut prompt = messages
            .iter()
            .map(|msg| msg.get("content").unwrap_or(&String::new()).clone())
            .collect::<Vec<_>>()
            .join("\n");
        
        prompt.push_str("\n\nRespond with valid JSON only.");

        // Use streaming interface and collect result
        let stream = self.completion_provider.prompt(&prompt);
        let mut response = String::new();
        
        use futures_util::StreamExt;
        let mut stream = stream;
        while let Some(chunk) = stream.next().await {
            if let Some(content) = chunk.content {
                response.push_str(&content);
            }
        }

        Ok(response)
    }
    
    /// Get the memory manager
    pub fn memory_manager(&self) -> Arc<dyn MemoryManager> {
        Arc::clone(&self.memory_manager)
    }
    
    /// Get the vector search
    pub fn vector_search(&self) -> Arc<VectorSearch> {
        Arc::clone(&self.vector_search)
    }
    
    /// Get the completion provider
    pub fn completion_provider(&self) -> Arc<dyn CompletionProvider> {
        Arc::clone(&self.completion_provider)
    }
}

/// SDK builder for configuring and creating a MemorySDK
pub struct MemorySDKBuilder {
    /// Memory manager
    memory_manager: Option<Arc<dyn MemoryManager>>,
    /// Vector search
    vector_search: Option<Arc<VectorSearch>>,
    /// Completion provider
    completion_provider: Option<Arc<dyn CompletionProvider>>}

impl MemorySDKBuilder {
    /// Create a new MemorySDKBuilder
    pub fn new() -> Self {
        Self {
            memory_manager: None,
            vector_search: None,
            completion_provider: None}
    }
    
    /// Set memory manager
    #[must_use]
    pub fn with_memory_manager(mut self, memory_manager: Arc<dyn MemoryManager>) -> Self {
        self.memory_manager = Some(memory_manager);
        self
    }
    
    /// Set vector search
    #[must_use]
    pub fn with_vector_search(mut self, vector_search: Arc<VectorSearch>) -> Self {
        self.vector_search = Some(vector_search);
        self
    }
    
    /// Set completion provider
    #[must_use]
    pub fn with_completion_provider(mut self, completion_provider: Arc<dyn CompletionProvider>) -> Self {
        self.completion_provider = Some(completion_provider);
        self
    }
    
    /// Build the MemorySDK
    pub fn build(self) -> Result<MemorySDK> {
        let memory_manager = self.memory_manager
            .ok_or_else(|| crate::memory::utils::error::MemoryError::InvalidArgument(
                "Memory manager is required".to_string()
            ))?;
        
        let vector_search = self.vector_search
            .ok_or_else(|| crate::memory::utils::error::MemoryError::InvalidArgument(
                "Vector search is required".to_string()
            ))?;
        
        let completion_provider = self.completion_provider
            .ok_or_else(|| crate::memory::utils::error::MemoryError::InvalidArgument(
                "Completion provider is required".to_string()
            ))?;
        
        Ok(MemorySDK::new(memory_manager, vector_search, completion_provider))
    }
}

impl Default for MemorySDKBuilder {
    fn default() -> Self {
        Self::new()
    }
}