pub mod anthropic;
pub mod openai;
pub mod stream;
pub mod traits;

pub use self::anthropic::AnthropicProvider;
pub use self::openai::OpenAIProvider;

use crate::config::LLMProviderConfig;
#[cfg(test)]
pub use stream::provider_stream_for_test;
pub use stream::{
    DynProviderError, FinishReason, ProviderChunk, ProviderResponseAccumulator, ProviderStream,
    ProviderStreamItem, collect_provider_stream,
};
pub use traits::{
    ChatCompletionRequest, ChatCompletionResponse, LLMProvider, Message, Tool, ToolCall,
    ToolFunction, Usage,
};

pub fn create_provider(config: LLMProviderConfig) -> Result<Box<dyn LLMProvider>, ProviderError> {
    match config.provider_type.as_str() {
        "openai" => Ok(Box::new(OpenAIProvider::new(
            config.name,
            config.api_key,
            config.base_url,
            config.extra_headers,
            config.model_id,
            config.temperature,
            config.max_tokens,
            config.model_extra,
        ))),
        "anthropic" => Ok(Box::new(AnthropicProvider::new(
            config.name,
            config.api_key,
            config.base_url,
            config.extra_headers,
            config.model_id,
            config.temperature,
            config.max_tokens,
            config.model_extra,
        ))),
        _ => Err(ProviderError::UnknownProviderType(config.provider_type)),
    }
}

#[derive(Debug)]
pub enum ProviderError {
    UnknownProviderType(String),
}

impl std::fmt::Display for ProviderError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ProviderError::UnknownProviderType(t) => write!(f, "Unknown provider type: {}", t),
        }
    }
}

impl std::error::Error for ProviderError {}
