//! LLM Provider abstraction for TypeDialog AI service
//!
//! Provides a trait-based abstraction for multiple LLM backends:
//! - OpenAI (GPT-3.5, GPT-4)
//! - Claude (Anthropic)
//! - Ollama (local models)
//!
//! # Example
//!
//! ```ignore
//! use typedialog_ai::llm::{LlmProvider, Message, Role};
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//!     let provider = OpenAiProvider::new("sk-...", "gpt-4")?;
//!
//!     let messages = vec![
//!         Message {
//!             role: Role::System,
//!             content: "You are a helpful assistant".into(),
//!         },
//!         Message {
//!             role: Role::User,
//!             content: "Hello".into(),
//!         },
//!     ];
//!
//!     let response = provider.generate(&messages).await?;
//!     println!("{}", response);
//!
//!     Ok(())
//! }
//! ```

pub mod error;
pub mod messages;
pub mod options;
pub mod prompts;
pub mod providers;
pub mod rag_integration;

pub use error::Result;
#[allow(unused_imports)]
pub use messages::{Message, Role};
pub use options::GenerationOptions;

use async_trait::async_trait;
use futures::stream::Stream;
use std::pin::Pin;

/// Type alias for LLM streaming response
pub type StreamResponse = Pin<Box<dyn Stream<Item = Result<String>> + Send>>;

/// LLM Provider trait
///
/// All LLM backends must implement this trait to be used with TypeDialog AI service.
#[async_trait]
pub trait LlmProvider: Send + Sync {
    /// Generate a completion from messages
    ///
    /// # Arguments
    /// * `messages` - Conversation history with system prompt
    /// * `options` - Generation options (temperature, max tokens, etc.)
    ///
    /// # Returns
    /// Complete response text
    async fn generate(&self, messages: &[Message], options: &GenerationOptions) -> Result<String>;

    /// Stream a completion token-by-token
    ///
    /// # Arguments
    /// * `messages` - Conversation history
    /// * `options` - Generation options
    ///
    /// # Returns
    /// Stream of tokens
    async fn stream(
        &self,
        messages: &[Message],
        options: &GenerationOptions,
    ) -> Result<StreamResponse>;

    /// Get provider name
    fn name(&self) -> &str;

    /// Get model name
    fn model(&self) -> &str;

    /// Check if provider is available (e.g., API key configured)
    async fn is_available(&self) -> bool;
}

#[cfg(all(test, feature = "openai"))]
mod tests {
    use super::*;

    #[test]
    fn test_message_creation() {
        let msg = Message {
            role: Role::User,
            content: "Hello".into(),
        };

        assert_eq!(msg.role, Role::User);
        assert_eq!(msg.content, "Hello");
    }

    #[test]
    fn test_generation_options_default() {
        let opts = GenerationOptions::default();
        assert_eq!(opts.temperature, 0.7);
        assert_eq!(opts.max_tokens, Some(2048));
    }
}
