//! # `Blazen` LLM
//!
//! Provides traits and implementations for large language model providers
//! (`OpenAI`, Anthropic, Gemini, Azure, fal.ai, and many `OpenAI`-compatible
//! services) with streaming support, tool calling, and structured output
//! via JSON Schema.
//!
//! ## Feature flags
//!
//! | Feature | Description |
//! |---------|-------------|
//! | `reqwest` | Enables the native HTTP client (for non-WASM targets) |
//! | `tiktoken` | Enables exact BPE token counting |
//!
//! All providers are always compiled -- no feature flags needed.
//!
//! ## Quick start
//!
//! ```rust,no_run
//! use blazen_llm::{CompletionModel, CompletionRequest, ChatMessage};
//! use blazen_llm::providers::openai::OpenAiProvider;
//!
//! # async fn example() -> Result<(), blazen_llm::BlazenError> {
//! let model = OpenAiProvider::new("sk-...");
//! let request = CompletionRequest::new(vec![
//!     ChatMessage::user("What is 2 + 2?"),
//! ]);
//! let response = model.complete(request).await?;
//! println!("{}", response.content.unwrap_or_default());
//! # Ok(())
//! # }
//! ```
//!
//! ## Multi-provider support
//!
//! Use [`providers::openai_compat::OpenAiCompatProvider`] to connect to any
//! OpenAI-compatible service:
//!
//! ```rust,no_run
//! use blazen_llm::providers::groq::GroqProvider;
//! use blazen_llm::providers::openrouter::OpenRouterProvider;
//! use blazen_llm::providers::together::TogetherProvider;
//!
//! # fn example() {
//! // Groq (fast inference)
//! let groq = GroqProvider::new("gsk-...");
//!
//! // OpenRouter (400+ models)
//! let openrouter = OpenRouterProvider::new("sk-or-...");
//!
//! // Together AI
//! let together = TogetherProvider::new("...");
//! # }
//! ```

pub mod agent;
pub mod artifacts;
pub mod batch;
pub mod cache;
pub mod chat_window;
pub mod compute;
pub mod content;
pub mod device;
pub mod error;
pub mod events;
pub mod fallback;
pub mod http;
#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
mod http_reqwest;
pub mod keys;
pub(crate) mod sleep;
#[cfg(all(feature = "reqwest", not(target_arch = "wasm32")))]
pub use http_reqwest::ReqwestHttpClient;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
mod http_fetch;
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
pub use http_fetch::FetchHttpClient;
#[cfg(all(target_arch = "wasm32", target_os = "wasi"))]
pub mod http_napi_wasi;

/// Returns the platform-appropriate default HTTP client.
#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
pub(crate) fn default_http_client() -> std::sync::Arc<dyn http::HttpClient> {
    FetchHttpClient::new().into_arc()
}

/// Returns the platform-appropriate default HTTP client.
#[cfg(all(not(target_arch = "wasm32"), feature = "reqwest"))]
pub(crate) fn default_http_client() -> std::sync::Arc<dyn http::HttpClient> {
    ReqwestHttpClient::new().into_arc()
}

/// Returns the platform-appropriate default HTTP client.
///
/// On wasi, this is a [`http_napi_wasi::LazyHttpClient`] proxy that forwards
/// to whatever client the host registered via
/// [`http_napi_wasi::register_default`] (typically the napi
/// `setDefaultHttpClient` binding wrapping `globalThis.fetch`).
#[cfg(all(target_arch = "wasm32", target_os = "wasi"))]
pub(crate) fn default_http_client() -> std::sync::Arc<dyn http::HttpClient> {
    http_napi_wasi::LazyHttpClient::new().into_arc()
}

pub mod media;
pub mod middleware;
pub mod pricing;
pub mod providers;
pub mod quantization;
pub mod retry;
pub mod tokens;
pub mod traits;
pub mod typed_tool;
pub mod types;
pub mod usage_recording;

pub use providers::custom::{CustomProvider, HostDispatch};

// Re-export primary types at crate root for ergonomic imports.
pub use agent::{
    AgentConfig, AgentEvent, AgentResult, FINISH_WORKFLOW_TOOL_NAME, finish_workflow_tool,
    run_agent, run_agent_with_callback,
};
pub use artifacts::extract_inline_artifacts;
pub use batch::{BatchConfig, BatchResult, complete_batch};
pub use cache::{CacheConfig, CacheStrategy, CachedCompletionModel};
pub use chat_window::ChatWindow;
pub use compute::{
    // Audio
    AudioGeneration,
    AudioResult,
    // Background removal
    BackgroundRemoval,
    BackgroundRemovalRequest,
    // Core compute
    ComputeProvider,
    ComputeRequest,
    ComputeResult,
    // Image
    ImageGeneration,
    ImageModel,
    ImageRequest,
    ImageResult,
    JobHandle,
    JobStatus,
    MusicRequest,
    SpeechRequest,
    // 3D
    ThreeDGeneration,
    ThreeDRequest,
    ThreeDResult,
    // Transcription
    Transcription,
    TranscriptionRequest,
    TranscriptionResult,
    TranscriptionSegment,
    UpscaleRequest,
    // Video
    VideoGeneration,
    VideoRequest,
    VideoResult,
};
pub use device::Device;
#[allow(deprecated)]
pub use error::LlmError;
pub use error::{BlazenError, CompletionErrorKind, ComputeErrorKind, MediaErrorKind};
pub use events::{StreamChunkEvent, StreamCompleteEvent};
pub use fallback::FallbackModel;
pub use media::{
    Generated3DModel, GeneratedAudio, GeneratedImage, GeneratedVideo, MediaOutput, MediaType,
};
pub use middleware::{CacheMiddleware, Middleware, MiddlewareStack, RetryMiddleware};
pub use pricing::{PricingEntry, compute_cost, lookup_pricing, register_pricing};
pub use quantization::Quantization;
pub use retry::{RetryCompletionModel, RetryConfig};
#[cfg(feature = "tiktoken")]
pub use tokens::TiktokenCounter;
pub use tokens::{EstimateCounter, TokenCounter};
pub use traits::{
    CompletionModel, EmbeddingModel, LocalModel, ModelCapabilities, ModelInfo, ModelPricing,
    ModelRegistry, ProviderCapabilities, ProviderConfig, ProviderInfo, StructuredOutput, Tool,
};
pub use typed_tool::{TypedTool, typed_tool_simple};
pub use types::{
    Artifact, AudioContent, ChatMessage, Citation, CompletionRequest, CompletionResponse,
    ContentPart, EmbeddingResponse, FileContent, FinishReason, ImageContent, ImageSource,
    LlmPayload, MediaSource, MessageContent, ProviderId, ReasoningTrace, RequestTiming,
    ResponseFormat, Role, StreamChunk, StructuredResponse, TokenUsage, ToolCall, ToolDefinition,
    ToolOutput, VideoContent,
};
pub use usage_recording::{
    NoopUsageEmitter, UsageEmitter, UsageRecordingCompletionModel, UsageRecordingEmbeddingModel,
};

// ---------------------------------------------------------------------------
// Local inference backends (gated behind feature flags)
// ---------------------------------------------------------------------------

mod backends;

#[cfg(feature = "embed")]
pub use blazen_embed::{EmbedError, EmbedModel, EmbedOptions, EmbedResponse};

#[cfg(feature = "mistralrs")]
pub use blazen_llm_mistralrs::{
    ChatMessageInput, ChatRole, InferenceChunk, InferenceChunkStream, InferenceImage,
    InferenceImageSource, InferenceResult, InferenceToolCall, InferenceUsage, MistralRsError,
    MistralRsOptions, MistralRsProvider,
};

#[cfg(feature = "candle-embed")]
pub use blazen_embed_candle::{CandleEmbedError, CandleEmbedModel, CandleEmbedOptions};

#[cfg(feature = "whispercpp")]
pub use blazen_audio_whispercpp::{WhisperCppProvider, WhisperError, WhisperModel, WhisperOptions};

#[cfg(feature = "diffusion")]
pub use blazen_image_diffusion::{
    DiffusionError, DiffusionOptions, DiffusionProvider, DiffusionScheduler,
};

#[cfg(feature = "candle-llm")]
pub use backends::candle_llm::CandleLlmCompletionModel;
#[cfg(feature = "candle-llm")]
pub use blazen_llm_candle::{
    CandleInferenceResult, CandleLlmError, CandleLlmOptions, CandleLlmProvider,
};

#[cfg(feature = "llamacpp")]
pub use blazen_llm_llamacpp::{
    ChatMessageInput as LlamaCppChatMessageInput, ChatRole as LlamaCppChatRole,
    InferenceChunk as LlamaCppInferenceChunk, InferenceChunkStream as LlamaCppInferenceChunkStream,
    InferenceResult as LlamaCppInferenceResult, InferenceUsage as LlamaCppInferenceUsage,
    LlamaCppError, LlamaCppOptions, LlamaCppProvider,
};

#[cfg(feature = "piper")]
pub use blazen_audio_piper::{PiperError, PiperOptions, PiperProvider};
