//! DeepSeek API client implementation for interacting with DeepSeek's AI models.
//!
//! This module provides a client implementation for making requests to DeepSeek's chat completion API.
//! It supports both streaming and non-streaming interactions, handling authentication, request
//! construction, and response parsing.
//!
//! # Features
//!
//! - Supports chat completions with DeepSeek's AI models
//! - Handles both streaming and non-streaming responses
//! - Configurable request parameters (model, max tokens, temperature)
//! - Custom header support
//! - Comprehensive error handling
//!
//! # Examples
//!
//! ```no_run
//! use crate::{
//!     clients::DeepSeekClient,
//!     models::{ApiConfig, Message},
//! };
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! // Initialize the client
//! let client = DeepSeekClient::new("your-api-key".to_string());
//!
//! // Prepare messages and configuration
//! let messages = vec![Message {
//!     role: "user".to_string(),
//!     content: "Hello, how are you?".to_string(),
//! }];
//!
//! let config = ApiConfig::default();
//!
//! // Make a non-streaming request
//! let response = client.chat(messages.clone(), &config).await?;
//!
//! // Or use streaming for real-time responses
//! let mut stream = client.chat_stream(messages, &config);
//! while let Some(chunk) = stream.next().await {
//!     println!("Received chunk: {:?}", chunk?);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Error Handling
//!
//! The client uses a custom error type `ApiError` to handle various failure cases:
//! - Network errors
//! - API authentication errors
//! - Invalid response formats
//! - Stream processing errors
//!
//! All public methods return `Result` types with appropriate error variants.

use crate::{
    error::{ApiError, Result},
    models::{ApiConfig, Message},
};
use futures::Stream;
use reqwest::{header::HeaderMap, Client};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, pin::Pin};
use futures::StreamExt;
use serde_json;

pub(crate) const DEEPSEEK_API_URL: &str = "https://api.deepseek.com/chat/completions";
const DEFAULT_MODEL: &str = "deepseek-reasoner";

/// Client for interacting with DeepSeek's AI models.
///
/// This client handles authentication, request construction, and response parsing
/// for both streaming and non-streaming interactions with DeepSeek's API.
///
/// # Examples
///
/// ```no_run
/// use deepclaude::clients::DeepSeekClient;
///
/// let client = DeepSeekClient::new("api_token".to_string());
/// ```
#[derive(Debug)]
pub struct DeepSeekClient {
    pub(crate) client: Client,
    api_token: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct DeepSeekResponse {
    pub id: String,
    pub object: String,
    pub created: i64,
    pub model: String,
    pub choices: Vec<Choice>,
    pub usage: Usage,
    pub system_fingerprint: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Choice {
    pub index: i32,
    pub message: AssistantMessage,
    pub logprobs: Option<serde_json::Value>,
    pub finish_reason: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AssistantMessage {
    pub role: String,
    pub content: Option<String>,
    pub reasoning_content: Option<String>,
}

// Streaming response types
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamChoice {
    pub index: i32,
    pub delta: StreamDelta,
    pub logprobs: Option<serde_json::Value>,
    pub finish_reason: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamDelta {
    pub role: Option<String>,
    pub content: Option<String>,
    pub reasoning_content: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamResponse {
    pub id: String,
    pub object: String,
    pub created: i64,
    pub model: String,
    pub choices: Vec<StreamChoice>,
    pub usage: Option<Usage>,
    pub system_fingerprint: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Usage {
    pub prompt_tokens: u32,
    pub completion_tokens: u32,
    pub total_tokens: u32,
    pub prompt_tokens_details: PromptTokensDetails,
    pub completion_tokens_details: CompletionTokensDetails,
    pub prompt_cache_hit_tokens: u32,
    pub prompt_cache_miss_tokens: u32,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PromptTokensDetails {
    pub cached_tokens: u32,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct CompletionTokensDetails {
    pub reasoning_tokens: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct DeepSeekRequest {
    messages: Vec<Message>,
    stream: bool,
    #[serde(flatten)]
    additional_params: serde_json::Value,
}

impl DeepSeekClient {
    pub fn new(api_token: String) -> Self {
        Self {
            client: Client::new(),
            api_token,
        }
    }

    /// Builds the HTTP headers required for DeepSeek API requests.
    ///
    /// # Arguments
    ///
    /// * `custom_headers` - Optional additional headers to include in requests
    ///
    /// # Returns
    ///
    /// * `Result<HeaderMap>` - The constructed headers on success, or an error if header construction fails
    ///
    /// # Errors
    ///
    /// Returns `ApiError::Internal` if:
    /// - The API token is invalid
    /// - Content-Type or Accept headers cannot be constructed

    /// Constructs a request object for the DeepSeek API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages to send to the model
    /// * `stream` - Whether to enable streaming mode
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// A `DeepSeekRequest` object configured with the provided parameters and defaults
    pub(crate) fn build_request(&self, messages: Vec<Message>, stream: bool, config: &ApiConfig) -> DeepSeekRequest {
        // Create a base request with required fields
        let mut request_value = serde_json::json!({
            "messages": messages,
            "stream": stream,
            // Set defaults only if not provided in config
            "model": config.body.get("model").unwrap_or(&serde_json::json!(DEFAULT_MODEL)),
            "max_tokens": config.body.get("max_tokens").unwrap_or(&serde_json::json!(8192)),
            "temperature": config.body.get("temperature").unwrap_or(&serde_json::json!(1.0)),
            "response_format": {
                "type": "text"
            }
        });

        // Merge additional configuration from config.body while protecting critical fields
        if let serde_json::Value::Object(mut map) = request_value {
            if let serde_json::Value::Object(mut body) = serde_json::to_value(&config.body).unwrap_or_default() {
                // Remove protected fields from config body
                body.remove("stream");
                body.remove("messages");

                // Merge remaining fields from config.body
                for (key, value) in body {
                    map.insert(key, value);
                }
            }
            request_value = serde_json::Value::Object(map);
        }

        // Convert the merged JSON value into our request structure
        serde_json::from_value(request_value).unwrap_or_else(|_| DeepSeekRequest {
            messages,
            stream,
            additional_params: config.body.clone(),
        })
    }

    /// Sends a non-streaming chat request to the DeepSeek API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Result<DeepSeekResponse>` - The model's response on success
    ///
    /// # Errors
    ///
    /// Returns `ApiError::DeepSeekError` if:
    /// - The API request fails
    /// - The response status is not successful
    /// - The response cannot be parsed
    pub async fn chat(
        &self,
        messages: Vec<Message>,
        config: &ApiConfig,
    ) -> Result<DeepSeekResponse> {
        let headers = self.build_headers(Some(&config.headers))?;
        let request = self.build_request(messages, false, config);

        let response = self
            .client
            .post(DEEPSEEK_API_URL)
            .headers(headers)
            .json(&request)
            .send()
            .await
            .map_err(|e| ApiError::DeepSeekError {
                message: format!("Request failed: {}", e),
                type_: "request_failed".to_string(),
                param: None,
                code: None
            })?;

        if !response.status().is_success() {
            let error = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(ApiError::DeepSeekError {
                message: error,
                type_: "api_error".to_string(),
                param: None,
                code: None
            });
        }

        response
            .json::<DeepSeekResponse>()
            .await
            .map_err(|e| ApiError::DeepSeekError {
                message: format!("Failed to parse response: {}", e),
                type_: "parse_error".to_string(),
                param: None,
                code: None
            })
    }

    /// Sends a streaming chat request to the DeepSeek API.
    ///
    /// Returns a stream that yields chunks of the model's response as they arrive.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Pin<Box<dyn Stream<Item = Result<StreamResponse>> + Send>>` - A stream of response chunks
    ///
    /// # Errors
    ///
    /// The stream may yield `ApiError::DeepSeekError` if:
    /// - The API request fails
    /// - Stream processing encounters an error
    /// - Response chunks cannot be parsed
    pub fn chat_stream(
        &self,
        messages: Vec<Message>,
        config: &ApiConfig,
    ) -> Pin<Box<dyn Stream<Item = Result<StreamResponse>> + Send>> {
        let headers = match self.build_headers(Some(&config.headers)) {
            Ok(h) => h,
            Err(e) => return Box::pin(futures::stream::once(async move { Err(e) })),
        };

        let request = self.build_request(messages, true, config);
        let client = self.client.clone();

        Box::pin(async_stream::try_stream! {
            let mut stream = client
                .post(DEEPSEEK_API_URL)
                .headers(headers)
                .json(&request)
                .send()
                .await
                .map_err(|e| ApiError::DeepSeekError {
                    message: format!("Request failed: {}", e),
                    type_: "request_failed".to_string(),
                    param: None,
                    code: None
                })?
                .bytes_stream();

            let mut data = String::new();

            while let Some(chunk) = stream.next().await {
                let chunk = chunk.map_err(|e| ApiError::DeepSeekError {
                    message: format!("Stream error: {}", e),
                    type_: "stream_error".to_string(),
                    param: None,
                    code: None
                })?;
                data.push_str(&String::from_utf8_lossy(&chunk));

                let mut start = 0;
                while let Some(end) = data[start..].find("\n\n") {
                    let end = start + end;
                    let line = &data[start..end].trim();
                    start = end + 2;

                    if line.starts_with("data: ") {
                        let json_data = &line["data: ".len()..];
                        if let Ok(response) = serde_json::from_str::<StreamResponse>(json_data) {
                            yield response;
                        }
                    }
                }

                if start > 0 {
                    data = data[start..].to_string();
                }
            }
        })
    }
}

pub(crate) fn build_headers(&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {
        let mut headers = HeaderMap::new();
        headers.insert(
            "Authorization",
            format!("Bearer {}", self.api_token)
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid API token: {}", e)
                })?,
        );
        headers.insert(
            "Content-Type",
            "application/json"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid content type: {}", e)
                })?,
        );
        headers.insert(
            "Accept",
            "application/json"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid accept header: {}", e)
                })?,
        );
        if let Some(custom) = custom_headers {
            headers.extend(super::build_headers(custom)?);
        }
        Ok(headers)
    }

//! DeepClaude - A high-performance LLM inference API and Chat UI that integrates DeepSeek R1's CoT reasoning traces with Anthropic Claude models..
//!
//! This application provides a REST API for chat interactions that:
//! - Processes messages through DeepSeek R1 for reasoning
//! - Uses Anthropic's Claude for final responses
//! - Supports both streaming and non-streaming responses
//! - Tracks token usage and costs
//! - Provides detailed usage statistics
//!
//! The API requires authentication tokens for both services and
//! supports custom configuration through a TOML config file.

mod clients;
mod config;
mod error;
mod handlers;
mod models;

use crate::{config::Config, handlers::AppState};
use axum::routing::{post, Router};
use std::{net::SocketAddr, sync::Arc};
use tower_http::{
    cors::{Any, CorsLayer},
    trace::TraceLayer,
};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

/// Application entry point.
///
/// Sets up logging, loads configuration, and starts the HTTP server
/// with the configured routes and middleware.
///
/// # Returns
///
/// * `anyhow::Result<()>` - Ok if server starts successfully, Err otherwise
///
/// # Errors
///
/// Returns an error if:
/// - Logging setup fails
/// - Server address binding fails
/// - Server encounters a fatal error while running
#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Initialize logging
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "deepclaude=debug,tower_http=debug".into()),
        )
        .with(tracing_subscriber::fmt::layer())
        .init();

    // Load configuration
    let config = Config::load().unwrap_or_else(|_| {
        tracing::warn!("Failed to load config.toml, using default configuration");
        Config::default()
    });

    // Create application state
    // Clone config for AppState
    let config_clone = config.clone();
    let state = Arc::new(AppState { config: config_clone });

    // Set up CORS
    let cors = CorsLayer::new()
        .allow_methods(Any)
        .allow_headers(Any)
        .allow_origin(Any);

    // Build router
    let app = Router::new()
        .route("/", post(handlers::handle_chat))
        .layer(TraceLayer::new_for_http())
        .layer(cors)
        .with_state(state);

    // Get host and port from config
    let addr: SocketAddr = format!("{}:{}", config.server.host, config.server.port)
        .parse()
        .expect("Invalid host/port configuration");

    tracing::info!("Starting server on {}", addr);

    // Start server
    axum::serve(
        tokio::net::TcpListener::bind(&addr).await?,
        app.into_make_service(),
    )
    .await?;

    Ok(())
}

pub(crate) fn build_headers (&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {}

This code segment functions to: Construct and validate HTTP headers for API requests, including authentication credentials and content type specifications, while incorporating optional custom headers and handling potential parsing errors.

```rust
[TASK_BEGIN]
    pub(crate) fn build_headers(&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {
        let mut headers = HeaderMap::new();

        // Process custom headers first to allow required headers to override them
        if let Some(custom) = custom_headers {
            for (key, value) in custom {
                let header_name = HeaderName::from_str(key).map_err(|e| {
                    ApiError::Internal(format!("Invalid custom header name '{}': {}", key, e))
                })?;
                let header_value = HeaderValue::from_str(value).map_err(|e| {
                    ApiError::Internal(format!("Invalid value for header '{}': {}", key, e))
                })?;
                headers.insert(header_name, header_value);
            }
        }

        // Add required headers (will override any existing values from custom headers)
        headers.insert(
            reqwest::header::AUTHORIZATION,
            HeaderValue::from_str(&format!("Bearer {}", self.api_token))
                .map_err(|e| ApiError::Internal(format!("Failed to construct Authorization header: {}", e)))?
        );

        headers.insert(
            reqwest::header::CONTENT_TYPE,
            HeaderValue::from_str("application/json")
                .map_err(|e| ApiError::Internal(format!("Invalid Content-Type header: {}", e)))?
        );

        headers.insert(
            reqwest::header::ACCEPT,
            HeaderValue::from_str("application/json")
                .map_err(|e| ApiError::Internal(format!("Invalid Accept header: {}", e)))?
        );

        Ok(headers)
    }
[TASK_END]
```

pub(crate) fn build_headers(&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {
        let mut headers = HeaderMap::new();
        if let Some(custom) = custom_headers {
            for (key, value) in custom {
                let header_name = HeaderName::from_str(key).map_err(|e| {
                    ApiError::Internal(format!("Invalid custom header name '{}': {}", key, e))
                })?;
                let header_value = HeaderValue::from_str(value).map_err(|e| {
                    ApiError::Internal(format!("Invalid value for header '{}': {}", key, e))
                })?;
                headers.insert(header_name, header_value);
            }
        }
        headers.insert(
            reqwest::header::AUTHORIZATION,
            HeaderValue::from_str(&format!("Bearer {}", self.api_token))
                .map_err(|e| ApiError::Internal(format!("Failed to construct Authorization header: {}", e)))?
        );
        headers.insert(
            reqwest::header::CONTENT_TYPE,
            HeaderValue::from_str("application/json")
                .map_err(|e| ApiError::Internal(format!("Invalid Content-Type header: {}", e)))?
        );
        headers.insert(
            reqwest::header::ACCEPT,
            HeaderValue::from_str("application/json")
                .map_err(|e| ApiError::Internal(format!("Invalid Accept header: {}", e)))?
        );
        Ok(headers)
    }


//! Request models for the API endpoints.
//!
//! This module defines the structures used to represent incoming API requests,
//! including chat messages, configuration options, and request parameters.

use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Primary request structure for chat API endpoints.
///
/// This structure represents a complete chat request, including messages,
/// system prompts, and configuration options for both DeepSeek and Anthropic APIs.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ApiRequest {
    #[serde(default)]
    pub stream: bool,

    #[serde(default)]
    pub verbose: bool,

    pub system: Option<String>,
    pub messages: Vec<Message>,

    #[serde(default)]
    pub deepseek_config: ApiConfig,

    #[serde(default)]
    pub anthropic_config: ApiConfig,
}

/// A single message in a chat conversation.
///
/// Represents one message in the conversation history, including
/// its role (system, user, or assistant) and content.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Message {
    pub role: Role,
    pub content: String,
}

/// Possible roles for a message in a chat conversation.
///
/// Each message must be associated with one of these roles to
/// properly structure the conversation flow.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum Role {
    System,
    User,
    Assistant,
}

/// Configuration options for external API requests.
///
/// Contains headers and body parameters that will be passed
/// to the external AI model APIs.
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
pub struct ApiConfig {
    #[serde(default)]
    pub headers: HashMap<String, String>,

    #[serde(default)]
    pub body: serde_json::Value,
}

impl ApiRequest {
    /// Validates that system prompts are not duplicated.
    ///
    /// Checks that a system prompt is not provided in both the root level
    /// and messages array. The system prompt itself is optional.
    ///
    /// # Returns
    ///
    /// * `bool` - True if system prompt validation passes (no duplicates), false otherwise
    pub fn validate_system_prompt(&self) -> bool {
        let system_in_messages = self.messages.iter().any(|msg| matches!(msg.role, Role::System));

        // Only invalid if system prompt is provided in both places
        !(self.system.is_some() && system_in_messages)
    }

    /// Returns messages with the system prompt in the correct position.
    ///
    /// Ensures the system prompt (if present) is the first message,
    /// followed by the conversation messages in order.
    ///
    /// # Returns
    ///
    /// * `Vec<Message>` - Messages with system prompt correctly positioned

    /// Retrieves the system prompt if one is present.
    ///
    /// Checks both the root level system field and the messages array
    /// for a system prompt.
    ///
    /// # Returns
    ///
    /// * `Option<&str>` - The system prompt if found, None otherwise
    pub fn get_system_prompt(&self) -> Option<&str> {
        self.system.as_deref().or_else(|| {
            self.messages
                .iter()
                .find(|msg| matches!(msg.role, Role::System))
                .map(|msg| msg.content.as_str())
        })
    }
}

pub fn get_messages_with_system(&self) -> Vec<Message> {
        let mut messages = Vec::new();
        if let Some(system) = &self.system {
            messages.push(Message {
                role: Role::System,
                content: system.clone(),
            });
        }
        messages.extend(self.messages.iter().filter(|msg| !matches!(msg.role, Role::System)).cloned());
        messages
    }

//! Anthropic API client implementation for interacting with Claude models.
//!
//! This module provides a client implementation for communicating with Anthropic's API,
//! specifically designed to work with Claude language models. It supports both streaming
//! and non-streaming interactions, handling all aspects of API communication including:
//!
//! - Authentication and request signing
//! - Message formatting and serialization
//! - Response parsing and deserialization
//! - Error handling and type conversion
//! - Streaming response processing
//!
//! # Main Components
//!
//! - [`AnthropicClient`]: The main client struct for making API requests
//! - [`AnthropicResponse`]: Represents the structured response from the API
//! - [`StreamEvent`]: Represents different types of events in streaming responses
//!
//! # Example Usage
//!
//! ```no_run
//! use deepclaude::clients::AnthropicClient;
//! use deepclaude::models::{Message, ApiConfig};
//!
//! async fn example() -> Result<(), Box<dyn std::error::Error>> {
//!     let client = AnthropicClient::new("your-api-key".to_string());
//!     let messages = vec![/* your messages */];
//!     let config = ApiConfig::default();
//!
//!     // Non-streaming request
//!     let response = client.chat(messages.clone(), None, &config).await?;
//!
//!     // Streaming request
//!     let stream = client.chat_stream(messages, None, &config);
//!     Ok(())
//! }
//! ```

use crate::{
    error::{ApiError, Result},
    models::{ApiConfig, Message, Role},
};
use futures::Stream;
use reqwest::{header::HeaderMap, Client};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, pin::Pin};
use futures::StreamExt;
use serde_json;

pub(crate) const ANTHROPIC_API_URL: &str = "https://api.anthropic.com/v1/messages";
const DEFAULT_MODEL: &str = "claude-3-5-sonnet-20241022";

/// Client for interacting with Anthropic's Claude models.
///
/// This client handles authentication, request construction, and response parsing
/// for both streaming and non-streaming interactions with Anthropic's API.
///
/// # Examples
///
/// ```no_run
/// use deepclaude::clients::AnthropicClient;
///
/// let client = AnthropicClient::new("api_token".to_string());
/// ```
#[derive(Debug)]
pub struct AnthropicClient {
    pub(crate) client: Client,
    api_token: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AnthropicResponse {
    pub id: String,
    #[serde(rename = "type")]
    pub response_type: String,
    pub role: String,
    pub model: String,
    pub content: Vec<ContentBlock>,
    pub stop_reason: Option<String>,
    pub stop_sequence: Option<String>,
    pub usage: Usage,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ContentBlock {
    #[serde(rename = "type")]
    pub content_type: String,
    pub text: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Usage {
    pub input_tokens: u32,
    pub output_tokens: u32,
    pub cache_creation_input_tokens: u32,
    pub cache_read_input_tokens: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct AnthropicRequest {
    messages: Vec<AnthropicMessage>,
    stream: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    system: Option<String>,
    #[serde(flatten)]
    additional_params: serde_json::Value,
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct AnthropicMessage {
    role: String,
    content: String,
}

// Event types for streaming responses
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum StreamEvent {
    #[serde(rename = "message_start")]
    MessageStart {
        message: AnthropicResponse,
    },
    #[serde(rename = "content_block_start")]
    #[allow(dead_code)]
    ContentBlockStart {
        index: usize,
        content_block: ContentBlock,
    },
    #[serde(rename = "content_block_delta")]
    #[allow(dead_code)]
    ContentBlockDelta {
        index: usize,
        delta: ContentDelta,
    },
    #[serde(rename = "content_block_stop")]
    #[allow(dead_code)]
    ContentBlockStop {
        index: usize,
    },
    #[serde(rename = "message_delta")]
    #[allow(dead_code)]
    MessageDelta {
        delta: MessageDelta,
        usage: Option<Usage>,
    },
    #[serde(rename = "message_stop")]
    MessageStop,
    #[serde(rename = "ping")]
    Ping,
}

#[derive(Debug, Deserialize, Clone)]
pub struct ContentDelta {
    #[serde(rename = "type")]
    pub delta_type: String,
    pub text: String,
}

#[derive(Debug, Deserialize, Clone)]
#[allow(dead_code)]
pub struct MessageDelta {
    pub stop_reason: Option<String>,
    pub stop_sequence: Option<String>,
}

impl AnthropicClient {
    /// Creates a new Anthropic client instance.
    ///
    /// # Arguments
    ///
    /// * `api_token` - API token for authentication with Anthropic's API
    ///
    /// # Returns
    ///
    /// A new `AnthropicClient` instance configured with the provided API token
    pub fn new(api_token: String) -> Self {
        Self {
            client: Client::new(),
            api_token,
        }
    }

    /// Builds the HTTP headers required for Anthropic API requests.
    ///
    /// # Arguments
    ///
    /// * `custom_headers` - Optional additional headers to include in requests
    ///
    /// # Returns
    ///
    /// * `Result<HeaderMap>` - The constructed headers on success, or an error if header construction fails
    ///
    /// # Errors
    ///
    /// Returns `ApiError::Internal` if:
    /// - The API token is invalid
    /// - Content-Type or Anthropic-Version headers cannot be constructed
    pub(crate) fn build_headers(&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {
        let mut headers = HeaderMap::new();
        headers.insert(
            "x-api-key",
            self.api_token
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid API token: {}", e)
                })?,
        );
        headers.insert(
            "content-type",
            "application/json"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid content type: {}", e)
                })?,
        );
        headers.insert(
            "anthropic-version",
            "2023-06-01"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid anthropic version: {}", e)
                })?,
        );

        if let Some(custom) = custom_headers {
            headers.extend(super::build_headers(custom)?);
        }

        Ok(headers)
    }

    /// Constructs a request object for the Anthropic API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages to send to the model
    /// * `system` - Optional system prompt to set context
    /// * `stream` - Whether to enable streaming mode
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// An `AnthropicRequest` object configured with the provided parameters and defaults
    pub(crate) fn build_request(
        &self,
        messages: Vec<Message>,
        system: Option<String>,
        stream: bool,
        config: &ApiConfig,
    ) -> AnthropicRequest {
        let filtered_messages = messages
            .into_iter()
            .filter(|msg| msg.role != Role::System)
            .map(|msg| AnthropicMessage {
                role: match msg.role {
                    Role::User => "user".to_string(),
                    Role::Assistant => "assistant".to_string(),
                    Role::System => unreachable!(),
                },
                content: msg.content,
            })
            .collect();

        // Create base request with required fields
        let default_model = serde_json::json!(DEFAULT_MODEL);
        let model_value = config.body.get("model").unwrap_or(&default_model);

        let default_max_tokens = if let Some(model_str) = model_value.as_str() {
            if model_str.contains("claude-3-opus") {
                4096
            } else {
                8192
            }
        } else {
            8192
        };
        let default_max_tokens_json = serde_json::json!(default_max_tokens);

        let mut request_value = serde_json::json!({
            "messages": filtered_messages,
            "stream": stream,
            "model": model_value,
            "max_tokens": config.body.get("max_tokens").unwrap_or(&default_max_tokens_json)
        });

        // Add system if present
        if let Some(ref sys) = system {
            if let serde_json::Value::Object(mut map) = request_value {
                map.insert("system".to_string(), serde_json::json!(sys));
                request_value = serde_json::Value::Object(map);
            }
        }

        // Merge additional configuration from config.body while protecting critical fields
        if let serde_json::Value::Object(mut map) = request_value {
            if let serde_json::Value::Object(mut body) = serde_json::to_value(&config.body).unwrap_or_default() {
                // Remove protected fields from config body
                body.remove("stream");
                body.remove("messages");
                body.remove("system");

                // Merge remaining fields from config.body
                for (key, value) in body {
                    map.insert(key, value);
                }
            }
            request_value = serde_json::Value::Object(map);
        }

        // Convert the merged JSON value into our request structure
        serde_json::from_value(request_value).unwrap_or_else(|_| AnthropicRequest {
            messages: filtered_messages,
            stream,
            system,
            additional_params: config.body.clone(),
        })
    }

    /// Sends a non-streaming chat request to the Anthropic API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `system` - Optional system prompt to set context
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Result<AnthropicResponse>` - The model's response on success
    ///
    /// # Errors
    ///
    /// Returns `ApiError::AnthropicError` if:
    /// - The API request fails
    /// - The response status is not successful
    /// - The response cannot be parsed
    pub async fn chat(
        &self,
        messages: Vec<Message>,
        system: Option<String>,
        config: &ApiConfig,
    ) -> Result<AnthropicResponse> {
        let headers = self.build_headers(Some(&config.headers))?;
        let request = self.build_request(messages, system, false, config);

        let response = self
            .client
            .post(ANTHROPIC_API_URL)
            .headers(headers)
            .json(&request)
            .send()
            .await
            .map_err(|e| ApiError::AnthropicError {
                message: format!("Request failed: {}", e),
                type_: "request_failed".to_string(),
                param: None,
                code: None
            })?;

        if !response.status().is_success() {
            let error = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(ApiError::AnthropicError {
                message: error,
                type_: "api_error".to_string(),
                param: None,
                code: None
            });
        }

        response
            .json::<AnthropicResponse>()
            .await
            .map_err(|e| ApiError::AnthropicError {
                message: format!("Failed to parse response: {}", e),
                type_: "parse_error".to_string(),
                param: None,
                code: None
            })
    }

    /// Sends a streaming chat request to the Anthropic API.
    ///
    /// Returns a stream that yields events from the model's response as they arrive.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `system` - Optional system prompt to set context
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Pin<Box<dyn Stream<Item = Result<StreamEvent>> + Send>>` - A stream of response events
    ///
    /// # Errors
    ///
    /// The stream may yield `ApiError::AnthropicError` if:
    /// - The API request fails
    /// - Stream processing encounters an error
    /// - Response events cannot be parsed
    pub fn chat_stream(
        &self,
        messages: Vec<Message>,
        system: Option<String>,
        config: &ApiConfig,
    ) -> Pin<Box<dyn Stream<Item = Result<StreamEvent>> + Send>> {
        let headers = match self.build_headers(Some(&config.headers)) {
            Ok(h) => h,
            Err(e) => return Box::pin(futures::stream::once(async move { Err(e) })),
        };

        let request = self.build_request(messages, system, true, config);
        let client = self.client.clone();

        Box::pin(async_stream::try_stream! {
            let mut stream = client
                .post(ANTHROPIC_API_URL)
                .headers(headers)
                .json(&request)
                .send()
                .await
                .map_err(|e| ApiError::AnthropicError {
                    message: format!("Request failed: {}", e),
                    type_: "request_failed".to_string(),
                    param: None,
                    code: None
                })?
                .bytes_stream();

            let mut data = String::new();

            while let Some(chunk) = stream.next().await {
                let chunk = chunk.map_err(|e| ApiError::AnthropicError {
                    message: format!("Stream error: {}", e),
                    type_: "stream_error".to_string(),
                    param: None,
                    code: None
                })?;
                data.push_str(&String::from_utf8_lossy(&chunk));

                let mut start = 0;
                while let Some(end) = data[start..].find("\n\n") {
                    let end = start + end;
                    let event_data = &data[start..end];
                    start = end + 2;

                    if event_data.starts_with("event: ") {
                        let _event_line = &event_data["event: ".len()..];
                        if let Some(data_line) = event_data.lines().nth(1) {
                            if data_line.starts_with("data: ") {
                                let json_data = &data_line["data: ".len()..];
                                if let Ok(event) = serde_json::from_str::<StreamEvent>(json_data) {
                                    yield event;
                                }
                            }
                        }
                    }
                }

                if start > 0 {
                    data = data[start..].to_string();
                }
            }
        })
    }
}

/// Converts an Anthropic content block into the application's generic content block type.
impl From<ContentBlock> for crate::models::response::ContentBlock {
    fn from(block: ContentBlock) -> Self {
        Self {
            content_type: block.content_type,
            text: block.text,
        }
    }
}

//! DeepSeek API client implementation for interacting with DeepSeek's AI models.
//!
//! This module provides a client implementation for making requests to DeepSeek's chat completion API.
//! It supports both streaming and non-streaming interactions, handling authentication, request
//! construction, and response parsing.
//!
//! # Features
//!
//! - Supports chat completions with DeepSeek's AI models
//! - Handles both streaming and non-streaming responses
//! - Configurable request parameters (model, max tokens, temperature)
//! - Custom header support
//! - Comprehensive error handling
//!
//! # Examples
//!
//! ```no_run
//! use crate::{
//!     clients::DeepSeekClient,
//!     models::{ApiConfig, Message},
//! };
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! // Initialize the client
//! let client = DeepSeekClient::new("your-api-key".to_string());
//!
//! // Prepare messages and configuration
//! let messages = vec![Message {
//!     role: "user".to_string(),
//!     content: "Hello, how are you?".to_string(),
//! }];
//!
//! let config = ApiConfig::default();
//!
//! // Make a non-streaming request
//! let response = client.chat(messages.clone(), &config).await?;
//!
//! // Or use streaming for real-time responses
//! let mut stream = client.chat_stream(messages, &config);
//! while let Some(chunk) = stream.next().await {
//!     println!("Received chunk: {:?}", chunk?);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! # Error Handling
//!
//! The client uses a custom error type `ApiError` to handle various failure cases:
//! - Network errors
//! - API authentication errors
//! - Invalid response formats
//! - Stream processing errors
//!
//! All public methods return `Result` types with appropriate error variants.

use crate::{
    error::{ApiError, Result},
    models::{ApiConfig, Message},
};
use futures::Stream;
use reqwest::{header::HeaderMap, Client};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, pin::Pin};
use futures::StreamExt;
use serde_json;

pub(crate) const DEEPSEEK_API_URL: &str = "https://api.deepseek.com/chat/completions";
const DEFAULT_MODEL: &str = "deepseek-reasoner";

/// Client for interacting with DeepSeek's AI models.
///
/// This client handles authentication, request construction, and response parsing
/// for both streaming and non-streaming interactions with DeepSeek's API.
///
/// # Examples
///
/// ```no_run
/// use deepclaude::clients::DeepSeekClient;
///
/// let client = DeepSeekClient::new("api_token".to_string());
/// ```
#[derive(Debug)]
pub struct DeepSeekClient {
    pub(crate) client: Client,
    api_token: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct DeepSeekResponse {
    pub id: String,
    pub object: String,
    pub created: i64,
    pub model: String,
    pub choices: Vec<Choice>,
    pub usage: Usage,
    pub system_fingerprint: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Choice {
    pub index: i32,
    pub message: AssistantMessage,
    pub logprobs: Option<serde_json::Value>,
    pub finish_reason: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AssistantMessage {
    pub role: String,
    pub content: Option<String>,
    pub reasoning_content: Option<String>,
}

// Streaming response types
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamChoice {
    pub index: i32,
    pub delta: StreamDelta,
    pub logprobs: Option<serde_json::Value>,
    pub finish_reason: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamDelta {
    pub role: Option<String>,
    pub content: Option<String>,
    pub reasoning_content: Option<String>,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct StreamResponse {
    pub id: String,
    pub object: String,
    pub created: i64,
    pub model: String,
    pub choices: Vec<StreamChoice>,
    pub usage: Option<Usage>,
    pub system_fingerprint: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Usage {
    pub prompt_tokens: u32,
    pub completion_tokens: u32,
    pub total_tokens: u32,
    pub prompt_tokens_details: PromptTokensDetails,
    pub completion_tokens_details: CompletionTokensDetails,
    pub prompt_cache_hit_tokens: u32,
    pub prompt_cache_miss_tokens: u32,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PromptTokensDetails {
    pub cached_tokens: u32,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct CompletionTokensDetails {
    pub reasoning_tokens: u32,
}

#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct DeepSeekRequest {
    messages: Vec<Message>,
    stream: bool,
    #[serde(flatten)]
    additional_params: serde_json::Value,
}

impl DeepSeekClient {
    pub fn new(api_token: String) -> Self {
        Self {
            client: Client::new(),
            api_token,
        }
    }

    /// Builds the HTTP headers required for DeepSeek API requests.
    ///
    /// # Arguments
    ///
    /// * `custom_headers` - Optional additional headers to include in requests
    ///
    /// # Returns
    ///
    /// * `Result<HeaderMap>` - The constructed headers on success, or an error if header construction fails
    ///
    /// # Errors
    ///
    /// Returns `ApiError::Internal` if:
    /// - The API token is invalid
    /// - Content-Type or Accept headers cannot be constructed
    pub(crate) fn build_headers(&self, custom_headers: Option<&HashMap<String, String>>) -> Result<HeaderMap> {
        let mut headers = HeaderMap::new();
        headers.insert(
            "Authorization",
            format!("Bearer {}", self.api_token)
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid API token: {}", e)
                })?,
        );
        headers.insert(
            "Content-Type",
            "application/json"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid content type: {}", e)
                })?,
        );
        headers.insert(
            "Accept",
            "application/json"
                .parse()
                .map_err(|e| ApiError::Internal {
                    message: format!("Invalid accept header: {}", e)
                })?,
        );

        if let Some(custom) = custom_headers {
            headers.extend(super::build_headers(custom)?);
        }

        Ok(headers)
    }

    /// Constructs a request object for the DeepSeek API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages to send to the model
    /// * `stream` - Whether to enable streaming mode
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// A `DeepSeekRequest` object configured with the provided parameters and defaults
    pub(crate) fn build_request(&self, messages: Vec<Message>, stream: bool, config: &ApiConfig) -> DeepSeekRequest {
        // Create a base request with required fields
        let mut request_value = serde_json::json!({
            "messages": messages,
            "stream": stream,
            // Set defaults only if not provided in config
            "model": config.body.get("model").unwrap_or(&serde_json::json!(DEFAULT_MODEL)),
            "max_tokens": config.body.get("max_tokens").unwrap_or(&serde_json::json!(8192)),
            "temperature": config.body.get("temperature").unwrap_or(&serde_json::json!(1.0)),
            "response_format": {
                "type": "text"
            }
        });

        // Merge additional configuration from config.body while protecting critical fields
        if let serde_json::Value::Object(mut map) = request_value {
            if let serde_json::Value::Object(mut body) = serde_json::to_value(&config.body).unwrap_or_default() {
                // Remove protected fields from config body
                body.remove("stream");
                body.remove("messages");

                // Merge remaining fields from config.body
                for (key, value) in body {
                    map.insert(key, value);
                }
            }
            request_value = serde_json::Value::Object(map);
        }

        // Convert the merged JSON value into our request structure
        serde_json::from_value(request_value).unwrap_or_else(|_| DeepSeekRequest {
            messages,
            stream,
            additional_params: config.body.clone(),
        })
    }

    /// Sends a non-streaming chat request to the DeepSeek API.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Result<DeepSeekResponse>` - The model's response on success
    ///
    /// # Errors
    ///
    /// Returns `ApiError::DeepSeekError` if:
    /// - The API request fails
    /// - The response status is not successful
    /// - The response cannot be parsed
    pub async fn chat(
        &self,
        messages: Vec<Message>,
        config: &ApiConfig,
    ) -> Result<DeepSeekResponse> {
        let headers = self.build_headers(Some(&config.headers))?;
        let request = self.build_request(messages, false, config);

        let response = self
            .client
            .post(DEEPSEEK_API_URL)
            .headers(headers)
            .json(&request)
            .send()
            .await
            .map_err(|e| ApiError::DeepSeekError {
                message: format!("Request failed: {}", e),
                type_: "request_failed".to_string(),
                param: None,
                code: None
            })?;

        if !response.status().is_success() {
            let error = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(ApiError::DeepSeekError {
                message: error,
                type_: "api_error".to_string(),
                param: None,
                code: None
            });
        }

        response
            .json::<DeepSeekResponse>()
            .await
            .map_err(|e| ApiError::DeepSeekError {
                message: format!("Failed to parse response: {}", e),
                type_: "parse_error".to_string(),
                param: None,
                code: None
            })
    }

    /// Sends a streaming chat request to the DeepSeek API.
    ///
    /// Returns a stream that yields chunks of the model's response as they arrive.
    ///
    /// # Arguments
    ///
    /// * `messages` - Vector of messages for the conversation
    /// * `config` - Configuration options for the request
    ///
    /// # Returns
    ///
    /// * `Pin<Box<dyn Stream<Item = Result<StreamResponse>> + Send>>` - A stream of response chunks
    ///
    /// # Errors
    ///
    /// The stream may yield `ApiError::DeepSeekError` if:
    /// - The API request fails
    /// - Stream processing encounters an error
    /// - Response chunks cannot be parsed
    pub fn chat_stream(
        &self,
        messages: Vec<Message>,
        config: &ApiConfig,
    ) -> Pin<Box<dyn Stream<Item = Result<StreamResponse>> + Send>> {
        let headers = match self.build_headers(Some(&config.headers)) {
            Ok(h) => h,
            Err(e) => return Box::pin(futures::stream::once(async move { Err(e) })),
        };

        let request = self.build_request(messages, true, config);
        let client = self.client.clone();

        Box::pin(async_stream::try_stream! {
            let mut stream = client
                .post(DEEPSEEK_API_URL)
                .headers(headers)
                .json(&request)
                .send()
                .await
                .map_err(|e| ApiError::DeepSeekError {
                    message: format!("Request failed: {}", e),
                    type_: "request_failed".to_string(),
                    param: None,
                    code: None
                })?
                .bytes_stream();

            let mut data = String::new();

            while let Some(chunk) = stream.next().await {
                let chunk = chunk.map_err(|e| ApiError::DeepSeekError {
                    message: format!("Stream error: {}", e),
                    type_: "stream_error".to_string(),
                    param: None,
                    code: None
                })?;
                data.push_str(&String::from_utf8_lossy(&chunk));

                let mut start = 0;
                while let Some(end) = data[start..].find("\n\n") {
                    let end = start + end;
                    let line = &data[start..end].trim();
                    start = end + 2;

                    if line.starts_with("data: ") {
                        let json_data = &line["data: ".len()..];
                        if let Ok(response) = serde_json::from_str::<StreamResponse>(json_data) {
                            yield response;
                        }
                    }
                }

                if start > 0 {
                    data = data[start..].to_string();
                }
            }
        })
    }
}

//! Response models for the API endpoints.
//!
//! This module defines the structures used to represent API responses,
//! including chat completions, usage statistics, and streaming events.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Primary response structure for chat API endpoints.
///
/// Contains the complete response from both AI models, including
/// content blocks, usage statistics, and optional raw API responses.
#[derive(Debug, Serialize, Clone)]
pub struct ApiResponse {
    pub created: DateTime<Utc>,
    pub content: Vec<ContentBlock>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub deepseek_response: Option<ExternalApiResponse>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub anthropic_response: Option<ExternalApiResponse>,

    pub combined_usage: CombinedUsage,
}

/// A block of content in a response.
///
/// Represents a single piece of content in the response,
/// with its type and actual text content.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ContentBlock {
    #[serde(rename = "type")]
    pub content_type: String,
    pub text: String,
}

/// Raw response from an external API.
///
/// Contains the complete response details from an external API
/// call, including status code, headers, and response body.
#[derive(Debug, Serialize, Clone)]
pub struct ExternalApiResponse {
    pub status: u16,
    pub headers: HashMap<String, String>,
    pub body: serde_json::Value,
}

/// Combined usage statistics from both AI models.
///
/// Aggregates token usage and cost information from both
/// DeepSeek and Anthropic API calls.
#[derive(Debug, Serialize, Clone)]
pub struct CombinedUsage {
    pub total_cost: String,
    pub deepseek_usage: DeepSeekUsage,
    pub anthropic_usage: AnthropicUsage,
}

/// Usage statistics for DeepSeek API calls.
///
/// Tracks token consumption and costs specific to
/// DeepSeek model usage.
#[derive(Debug, Serialize, Clone)]
pub struct DeepSeekUsage {
    pub input_tokens: u32,
    pub output_tokens: u32,
    pub reasoning_tokens: u32,
    pub cached_input_tokens: u32,
    pub total_tokens: u32,
    pub total_cost: String,
}

/// Usage statistics for Anthropic API calls.
///
/// Tracks token consumption and costs specific to
/// Anthropic model usage.
#[derive(Debug, Serialize, Clone)]
pub struct AnthropicUsage {
    pub input_tokens: u32,
    pub output_tokens: u32,
    pub cached_write_tokens: u32,
    pub cached_read_tokens: u32,
    pub total_tokens: u32,
    pub total_cost: String,
}

// Streaming event types
/// Events emitted during streaming responses.
///
/// Represents different types of events that can occur
/// during a streaming response, including content updates
/// and usage statistics.
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
pub enum StreamEvent {
    #[serde(rename = "start")]
    Start {
        created: DateTime<Utc>,
    },

    #[serde(rename = "content")]
    Content {
        content: Vec<ContentBlock>,
    },

    #[serde(rename = "usage")]
    Usage {
        usage: CombinedUsage,
    },

    #[serde(rename = "done")]
    Done,

    #[serde(rename = "error")]
    Error {
        message: String,
        code: u16,
    },
}

impl ContentBlock {
    /// Creates a new text content block.
    ///
    /// # Arguments
    ///
    /// * `text` - The text content to include in the block
    ///
    /// # Returns
    ///
    /// A new `ContentBlock` with the type set to "text"
    pub fn text(text: impl Into<String>) -> Self {
        Self {
            content_type: "text".to_string(),
            text: text.into(),
        }
    }

    /// Converts an Anthropic content block to a generic content block.
    ///
    /// # Arguments
    ///
    /// * `block` - The Anthropic-specific content block to convert
    ///
    /// # Returns
    ///
    /// A new `ContentBlock` with the same content type and text
    pub fn from_anthropic(block: crate::clients::anthropic::ContentBlock) -> Self {
        Self {
            content_type: block.content_type,
            text: block.text,
        }
    }
}

impl ApiResponse {
    /// Creates a new API response with simple text content.
    ///
    /// # Arguments
    ///
    /// * `content` - The text content for the response
    ///
    /// # Returns
    ///
    /// A new `ApiResponse` with default values and the provided content
    #[allow(dead_code)]
    pub fn new(content: impl Into<String>) -> Self {
        Self {
            created: Utc::now(),
            content: vec![ContentBlock::text(content)],
            deepseek_response: None,
            anthropic_response: None,
            combined_usage: CombinedUsage {
                total_cost: "$0.00".to_string(),
                deepseek_usage: DeepSeekUsage {
                    input_tokens: 0,
                    output_tokens: 0,
                    reasoning_tokens: 0,
                    cached_input_tokens: 0,
                    total_tokens: 0,
                    total_cost: "$0.00".to_string(),
                },
                anthropic_usage: AnthropicUsage {
                    input_tokens: 0,
                    output_tokens: 0,
                    cached_write_tokens: 0,
                    cached_read_tokens: 0,
                    total_tokens: 0,
                    total_cost: "$0.00".to_string(),
                },
            },
        }
    }
}

impl AnthropicUsage {
    /// Converts Anthropic usage statistics to the generic usage format.
    ///
    /// # Arguments
    ///
    /// * `usage` - The Anthropic-specific usage statistics to convert
    ///
    /// # Returns
    ///
    /// A new `AnthropicUsage` with values copied from the Anthropic usage
    pub fn from_anthropic(usage: crate::clients::anthropic::Usage) -> Self {
        Self {
            input_tokens: usage.input_tokens,
            output_tokens: usage.output_tokens,
            cached_write_tokens: usage.cache_creation_input_tokens,
            cached_read_tokens: usage.cache_read_input_tokens,
            total_tokens: usage.input_tokens + usage.output_tokens,
            total_cost: "$0.00".to_string(), // Cost will be calculated later
        }
    }
}

//! Request handlers for the API endpoints.
//!
//! This module contains the main request handlers and supporting functions
//! for processing chat requests, including both streaming and non-streaming
//! responses. It coordinates between different AI models and handles
//! usage tracking and cost calculations.

use crate::{
    clients::{AnthropicClient, DeepSeekClient},
    config::Config,
    error::{ApiError, Result, SseResponse},
    models::{
        ApiRequest, ApiResponse, ContentBlock, CombinedUsage, DeepSeekUsage, AnthropicUsage,
        ExternalApiResponse, Message, Role, StreamEvent,
    },
};
use axum::{
    extract::State,
    response::{sse::Event, IntoResponse},
    Json,
};
use chrono::Utc;
use futures::StreamExt;
use std::{sync::Arc, collections::HashMap};
use tokio_stream::wrappers::ReceiverStream;

/// Application state shared across request handlers.
///
/// Contains configuration that needs to be accessible
/// to all request handlers.
pub struct AppState {
    pub config: Config,
}

/// Extracts API tokens from request headers.
///
/// # Arguments
///
/// * `headers` - The HTTP headers containing the API tokens
///
/// # Returns
///
/// * `Result<(String, String)>` - A tuple of (DeepSeek token, Anthropic token)
///
/// # Errors
///
/// Returns `ApiError::MissingHeader` if either token is missing
/// Returns `ApiError::BadRequest` if tokens are malformed
fn extract_api_tokens(
    headers: &axum::http::HeaderMap,
) -> Result<(String, String)> {
    let deepseek_token = headers
        .get("X-DeepSeek-API-Token")
        .ok_or_else(|| ApiError::MissingHeader {
            header: "X-DeepSeek-API-Token".to_string()
        })?
        .to_str()
        .map_err(|_| ApiError::BadRequest {
            message: "Invalid DeepSeek API token".to_string()
        })?
        .to_string();

    let anthropic_token = headers
        .get("X-Anthropic-API-Token")
        .ok_or_else(|| ApiError::MissingHeader {
            header: "X-Anthropic-API-Token".to_string()
        })?
        .to_str()
        .map_err(|_| ApiError::BadRequest {
            message: "Invalid Anthropic API token".to_string()
        })?
        .to_string();

    Ok((deepseek_token, anthropic_token))
}

/// Calculates the cost of DeepSeek API usage.
///
/// # Arguments
///
/// * `input_tokens` - Number of input tokens processed
/// * `output_tokens` - Number of output tokens generated
/// * `_reasoning_tokens` - Number of tokens used for reasoning
/// * `cached_tokens` - Number of tokens retrieved from cache
/// * `config` - Configuration containing pricing information
///
/// # Returns
///
/// The total cost in dollars for the API usage
fn calculate_deepseek_cost(
    input_tokens: u32,
    output_tokens: u32,
    _reasoning_tokens: u32,
    cached_tokens: u32,
    config: &Config,
) -> f64 {
    let cache_hit_cost = (cached_tokens as f64 / 1_000_000.0) * config.pricing.deepseek.input_cache_hit_price;
    let cache_miss_cost = ((input_tokens - cached_tokens) as f64 / 1_000_000.0) * config.pricing.deepseek.input_cache_miss_price;
    let output_cost = (output_tokens as f64 / 1_000_000.0) * config.pricing.deepseek.output_price;

    cache_hit_cost + cache_miss_cost + output_cost
}

/// Calculates the cost of Anthropic API usage.
///
/// # Arguments
///
/// * `model` - The specific Claude model used
/// * `input_tokens` - Number of input tokens processed
/// * `output_tokens` - Number of output tokens generated
/// * `cache_write_tokens` - Number of tokens written to cache
/// * `cache_read_tokens` - Number of tokens read from cache
/// * `config` - Configuration containing pricing information
///
/// # Returns
///
/// The total cost in dollars for the API usage
fn calculate_anthropic_cost(
    model: &str,
    input_tokens: u32,
    output_tokens: u32,
    cache_write_tokens: u32,
    cache_read_tokens: u32,
    config: &Config,
) -> f64 {
    let pricing = if model.contains("claude-3-5-sonnet") {
        &config.pricing.anthropic.claude_3_sonnet
    } else if model.contains("claude-3-5-haiku") {
        &config.pricing.anthropic.claude_3_haiku
    } else if model.contains("claude-3-opus") {
        &config.pricing.anthropic.claude_3_opus
    } else {
        &config.pricing.anthropic.claude_3_sonnet // default to sonnet pricing
    };

    let input_cost = (input_tokens as f64 / 1_000_000.0) * pricing.input_price;
    let output_cost = (output_tokens as f64 / 1_000_000.0) * pricing.output_price;
    let cache_write_cost = (cache_write_tokens as f64 / 1_000_000.0) * pricing.cache_write_price;
    let cache_read_cost = (cache_read_tokens as f64 / 1_000_000.0) * pricing.cache_read_price;

    input_cost + output_cost + cache_write_cost + cache_read_cost
}

/// Formats a cost value as a dollar amount string.
///
/// # Arguments
///
/// * `cost` - The cost value to format
///
/// # Returns
///
/// A string representing the cost with 3 decimal places and $ prefix
fn format_cost(cost: f64) -> String {
    format!("${:.3}", cost)
}

/// Main handler for chat requests.
///
/// Routes requests to either streaming or non-streaming handlers
/// based on the request configuration.
///
/// # Arguments
///
/// * `state` - Application state containing configuration
/// * `headers` - HTTP request headers
/// * `request` - The parsed chat request
///
/// # Returns
///
/// * `Result<Response>` - The API response or an error
pub async fn handle_chat(
    state: State<Arc<AppState>>,
    headers: axum::http::HeaderMap,
    Json(request): Json<ApiRequest>,
) -> Result<axum::response::Response> {
    if request.stream {
        let stream_response = chat_stream(state, headers, Json(request)).await?;
        Ok(stream_response.into_response())
    } else {
        let json_response = chat(state, headers, Json(request)).await?;
        Ok(json_response.into_response())
    }
}

/// Handler for non-streaming chat requests.
///
/// Processes the request through both AI models sequentially,
/// combining their responses and tracking usage.
///
/// # Arguments
///
/// * `state` - Application state containing configuration
/// * `headers` - HTTP request headers
/// * `request` - The parsed chat request
///
/// # Returns
///
/// * `Result<Json<ApiResponse>>` - The combined API response or an error
pub(crate) async fn chat(
    State(state): State<Arc<AppState>>,
    headers: axum::http::HeaderMap,
    Json(request): Json<ApiRequest>,
) -> Result<Json<ApiResponse>> {
    // Validate system prompt
    if !request.validate_system_prompt() {
        return Err(ApiError::InvalidSystemPrompt);
    }

    // Extract API tokens
    let (deepseek_token, anthropic_token) = extract_api_tokens(&headers)?;

    // Initialize clients
    let deepseek_client = DeepSeekClient::new(deepseek_token);
    let anthropic_client = AnthropicClient::new(anthropic_token);

    // Get messages with system prompt
    let messages = request.get_messages_with_system();

    // Call DeepSeek API
    let deepseek_response = deepseek_client.chat(messages.clone(), &request.deepseek_config).await?;

    // Store response metadata
    let deepseek_status: u16 = 200;
    let deepseek_headers = HashMap::new(); // Headers not available when using high-level chat method

    // Extract reasoning content and wrap in thinking tags
    let reasoning_content = deepseek_response
        .choices
        .first()
        .and_then(|c| c.message.reasoning_content.as_ref())
        .ok_or_else(|| ApiError::DeepSeekError {
            message: "No reasoning content in response".to_string(),
            type_: "missing_content".to_string(),
            param: None,
            code: None
        })?;

    let thinking_content = format!("<thinking>\n{}\n</thinking>", reasoning_content);

    // Add thinking content to messages for Anthropic
    let mut anthropic_messages = messages;
    anthropic_messages.push(Message {
        role: Role::Assistant,
        content: thinking_content.clone(),
    });

    // Call Anthropic API
    let anthropic_response = anthropic_client.chat(
        anthropic_messages,
        request.get_system_prompt().map(String::from),
        &request.anthropic_config
    ).await?;

    // Store response metadata
    let anthropic_status: u16 = 200;
    let anthropic_headers = HashMap::new(); // Headers not available when using high-level chat method

    // Calculate usage costs
    let deepseek_cost = calculate_deepseek_cost(
        deepseek_response.usage.prompt_tokens,
        deepseek_response.usage.completion_tokens,
        deepseek_response.usage.completion_tokens_details.reasoning_tokens,
        deepseek_response.usage.prompt_tokens_details.cached_tokens,
        &state.config,
    );

    let anthropic_cost = calculate_anthropic_cost(
        &anthropic_response.model,
        anthropic_response.usage.input_tokens,
        anthropic_response.usage.output_tokens,
        anthropic_response.usage.cache_creation_input_tokens,
        anthropic_response.usage.cache_read_input_tokens,
        &state.config,
    );

    // Combine thinking content with Anthropic's response
    let mut content = Vec::new();

    // Add thinking block first
    content.push(ContentBlock::text(thinking_content));

    // Add Anthropic's response blocks
    content.extend(anthropic_response.content.clone().into_iter()
        .map(ContentBlock::from_anthropic));

    // Build response with captured headers
    let response = ApiResponse {
        created: Utc::now(),
        content,
        deepseek_response: request.verbose.then(|| ExternalApiResponse {
            status: deepseek_status,
            headers: deepseek_headers,
            body: serde_json::to_value(&deepseek_response).unwrap_or_default(),
        }),
        anthropic_response: request.verbose.then(|| ExternalApiResponse {
            status: anthropic_status,
            headers: anthropic_headers,
            body: serde_json::to_value(&anthropic_response).unwrap_or_default(),
        }),
        combined_usage: CombinedUsage {
            total_cost: format_cost(deepseek_cost + anthropic_cost),
            deepseek_usage: DeepSeekUsage {
                input_tokens: deepseek_response.usage.prompt_tokens,
                output_tokens: deepseek_response.usage.completion_tokens,
                reasoning_tokens: deepseek_response.usage.completion_tokens_details.reasoning_tokens,
                cached_input_tokens: deepseek_response.usage.prompt_tokens_details.cached_tokens,
                total_tokens: deepseek_response.usage.total_tokens,
                total_cost: format_cost(deepseek_cost),
            },
            anthropic_usage: AnthropicUsage {
                input_tokens: anthropic_response.usage.input_tokens,
                output_tokens: anthropic_response.usage.output_tokens,
                cached_write_tokens: anthropic_response.usage.cache_creation_input_tokens,
                cached_read_tokens: anthropic_response.usage.cache_read_input_tokens,
                total_tokens: anthropic_response.usage.input_tokens + anthropic_response.usage.output_tokens,
                total_cost: format_cost(anthropic_cost),
            },
        },
    };

    Ok(Json(response))
}

/// Handler for streaming chat requests.
///
/// Processes the request through both AI models sequentially,
/// streaming their responses as Server-Sent Events.
///
/// # Arguments
///
/// * `state` - Application state containing configuration
/// * `headers` - HTTP request headers
/// * `request` - The parsed chat request
///
/// # Returns
///
/// * `Result<SseResponse>` - A stream of Server-Sent Events or an error
pub(crate) async fn chat_stream(
    State(state): State<Arc<AppState>>,
    headers: axum::http::HeaderMap,
    Json(request): Json<ApiRequest>,
) -> Result<SseResponse> {
    // Validate system prompt
    if !request.validate_system_prompt() {
        return Err(ApiError::InvalidSystemPrompt);
    }

    // Extract API tokens
    let (deepseek_token, anthropic_token) = extract_api_tokens(&headers)?;

    // Initialize clients
    let deepseek_client = DeepSeekClient::new(deepseek_token);
    let anthropic_client = AnthropicClient::new(anthropic_token);

    // Get messages with system prompt
    let messages = request.get_messages_with_system();

    // Create channel for stream events
    let (tx, rx) = tokio::sync::mpsc::channel(100);
    let tx = Arc::new(tx);

    // Spawn task to handle streaming
    let config = state.config.clone();
    let request_clone = request.clone();
    tokio::spawn(async move {
        let tx = tx.clone();

        // Start event
        let _ = tx
            .send(Ok(Event::default().event("start").data(
                serde_json::to_string(&StreamEvent::Start {
                    created: Utc::now(),
                })
                .unwrap_or_default(),
            )))
            .await;

        // Send initial thinking tag
        let _ = tx
            .send(Ok(Event::default().event("content").data(
                serde_json::to_string(&StreamEvent::Content {
                    content: vec![ContentBlock {
                        content_type: "text".to_string(),
                        text: "<thinking>\n".to_string(),
                    }],
                })
                .unwrap_or_default(),
            )))
            .await;

        // Stream from DeepSeek
        let mut deepseek_usage = None;
        let mut complete_reasoning = String::new();
        let mut deepseek_stream = deepseek_client.chat_stream(messages.clone(), &request_clone.deepseek_config);

        while let Some(chunk) = deepseek_stream.next().await {
            match chunk {
                Ok(response) => {
                    if let Some(choice) = response.choices.first() {
                        // Check if reasoning_content is null and break if it is
                        if choice.delta.reasoning_content.is_none() {
                            break;
                        }

                        // Handle delta reasoning_content for streaming
                        if let Some(reasoning) = &choice.delta.reasoning_content {
                            if !reasoning.is_empty() {
                                // Stream the reasoning content as a delta
                                let _ = tx
                                    .send(Ok(Event::default().event("content").data(
                                        serde_json::to_string(&StreamEvent::Content {
                                            content: vec![ContentBlock {
                                                content_type: "text_delta".to_string(),
                                                text: reasoning.to_string(),
                                            }],
                                        })
                                        .unwrap_or_default(),
                                    )))
                                    .await;

                                // Accumulate complete reasoning for later use
                                complete_reasoning.push_str(reasoning);
                            }
                        }
                    }

                    // Store usage information if present
                    if let Some(usage) = response.usage {
                        deepseek_usage = Some(usage);
                    }
                }
                Err(e) => {
                    let _ = tx
                        .send(Ok(Event::default().event("error").data(
                            serde_json::to_string(&StreamEvent::Error {
                                message: e.to_string(),
                                code: 500,
                            })
                            .unwrap_or_default(),
                        )))
                        .await;
                    return;
                }
            }
        }

        // Send closing thinking tag
        let _ = tx
            .send(Ok(Event::default().event("content").data(
                serde_json::to_string(&StreamEvent::Content {
                    content: vec![ContentBlock {
                        content_type: "text".to_string(),
                        text: "\n</thinking>".to_string(),
                    }],
                })
                .unwrap_or_default(),
            )))
            .await;

        // Add complete thinking content to messages for Anthropic
        let mut anthropic_messages = messages;
        anthropic_messages.push(Message {
            role: Role::Assistant,
            content: format!("<thinking>\n{}\n</thinking>", complete_reasoning),
        });

        // Stream from Anthropic
        let mut anthropic_stream = anthropic_client.chat_stream(
            anthropic_messages,
            request_clone.get_system_prompt().map(String::from),
            &request_clone.anthropic_config,
        );

        while let Some(chunk) = anthropic_stream.next().await {
            match chunk {
                Ok(event) => match event {
                    crate::clients::anthropic::StreamEvent::MessageStart { message } => {
                        // Only send content event if there's actual content to send
                        if !message.content.is_empty() {
                            let _ = tx
                                .send(Ok(Event::default().event("content").data(
                                    serde_json::to_string(&StreamEvent::Content {
                                        content: message.content.into_iter()
                                            .map(ContentBlock::from_anthropic)
                                            .collect()
                                    })
                                    .unwrap_or_default(),
                                )))
                                .await;
                        }
                    }
                    crate::clients::anthropic::StreamEvent::ContentBlockDelta { delta, .. } => {
                        // Send content update
                        let _ = tx
                            .send(Ok(Event::default().event("content").data(
                                serde_json::to_string(&StreamEvent::Content {
                                    content: vec![ContentBlock {
                                        content_type: delta.delta_type,
                                        text: delta.text,
                                    }],
                                })
                                .unwrap_or_default(),
                            )))
                            .await;
                    }
                    crate::clients::anthropic::StreamEvent::MessageDelta { usage, .. } => {
                        // Send final usage stats if available
                        if let Some(usage) = usage {
                            let anthropic_usage = AnthropicUsage::from_anthropic(usage);
                            let anthropic_cost = calculate_anthropic_cost(
                                "claude-3-5-sonnet-20241022", // Default model
                                anthropic_usage.input_tokens,
                                anthropic_usage.output_tokens,
                                anthropic_usage.cached_write_tokens,
                                anthropic_usage.cached_read_tokens,
                                &config,
                            );

                            // Calculate DeepSeek costs if usage is available
                            let (deepseek_usage, deepseek_cost) = if let Some(usage) = deepseek_usage.as_ref() {
                                let cost = calculate_deepseek_cost(
                                    usage.prompt_tokens,
                                    usage.completion_tokens,
                                    usage.completion_tokens_details.reasoning_tokens,
                                    usage.prompt_tokens_details.cached_tokens,
                                    &config,
                                );

                                (DeepSeekUsage {
                                    input_tokens: usage.prompt_tokens,
                                    output_tokens: usage.completion_tokens,
                                    reasoning_tokens: usage.completion_tokens_details.reasoning_tokens,
                                    cached_input_tokens: usage.prompt_tokens_details.cached_tokens,
                                    total_tokens: usage.total_tokens,
                                    total_cost: format_cost(cost),
                                }, cost)
                            } else {
                                (DeepSeekUsage {
                                    input_tokens: 0,
                                    output_tokens: 0,
                                    reasoning_tokens: 0,
                                    cached_input_tokens: 0,
                                    total_tokens: 0,
                                    total_cost: "$0.00".to_string(),
                                }, 0.0)
                            };

                            let _ = tx
                                .send(Ok(Event::default().event("usage").data(
                                    serde_json::to_string(&StreamEvent::Usage {
                                        usage: CombinedUsage {
                                            total_cost: format_cost(deepseek_cost + anthropic_cost),
                                            deepseek_usage,
                                            anthropic_usage: AnthropicUsage {
                                                input_tokens: anthropic_usage.input_tokens,
                                                output_tokens: anthropic_usage.output_tokens,
                                                cached_write_tokens: anthropic_usage.cached_write_tokens,
                                                cached_read_tokens: anthropic_usage.cached_read_tokens,
                                                total_tokens: anthropic_usage.total_tokens,
                                                total_cost: format_cost(anthropic_cost),
                                            },
                                        },
                                    })
                                    .unwrap_or_default(),
                                )))
                                .await;
                        }
                    }
                    _ => {} // Handle other events if needed
                },
                Err(e) => {
                    let _ = tx
                        .send(Ok(Event::default().event("error").data(
                            serde_json::to_string(&StreamEvent::Error {
                                message: e.to_string(),
                                code: 500,
                            })
                            .unwrap_or_default(),
                        )))
                        .await;
                    return;
                }
            }
        }

        // Send done event
        let _ = tx
            .send(Ok(Event::default().event("done").data(
                serde_json::to_string(&StreamEvent::Done)
                    .unwrap_or_default(),
            )))
            .await;
    });

    // Convert receiver into stream
    let stream = ReceiverStream::new(rx);
    Ok(SseResponse::new(stream))
}

//! Error handling types and implementations for the application.
//!
//! This module provides a comprehensive error handling system including:
//! - Custom error types for various failure scenarios
//! - Conversion implementations for common error types
//! - Response formatting for API errors
//! - Type aliases for common Result types

use axum::{
    http::StatusCode,
    response::{IntoResponse, Response, sse::Event},
    Json,
};
use serde::{Deserialize, Serialize};
use std::convert::Infallible;
use thiserror::Error;
use tokio_stream::wrappers::ReceiverStream;

/// Response structure for API errors.
///
/// This structure provides a consistent format for error responses
/// returned by the API endpoints.
#[derive(Debug, Serialize, Deserialize)]
pub struct ErrorResponse {
    pub error: ErrorDetails,
}

/// Detailed error information included in error responses.
///
/// Contains specific information about what went wrong, including:
/// - A human-readable error message
/// - The type of error that occurred
/// - Optional parameter that caused the error
/// - Optional error code for more specific error handling
#[derive(Debug, Serialize, Deserialize)]
pub struct ErrorDetails {
    pub message: String,
    #[serde(rename = "type")]
    pub type_: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub param: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<String>,
}

/// Enumeration of all possible API errors.
///
/// This enum represents all the different types of errors that can occur
/// during API operations, including validation errors, external API errors,
/// and internal server errors.
#[derive(Error, Debug, Clone)]
pub enum ApiError {
    #[error("Invalid request: {message}")]
    BadRequest {
        message: String,
    },

    #[error("Missing required header: {header}")]
    MissingHeader {
        header: String,
    },

    #[error("Invalid system prompt configuration")]
    InvalidSystemPrompt,

    #[error("DeepSeek API error: {message}")]
    DeepSeekError {
        message: String,
        type_: String,
        param: Option<String>,
        code: Option<String>,
    },

    #[error("Anthropic API error: {message}")]
    AnthropicError {
        message: String,
        type_: String,
        param: Option<String>,
        code: Option<String>,
    },

    #[error("Internal server error: {message}")]
    Internal {
        message: String,
    },

    #[error("Other error: {message}")]
    Other {
        message: String,
    },
}

/// Implements conversion of API errors into HTTP responses.
///
/// Maps each error variant to an appropriate HTTP status code and
/// formats the error details into a consistent JSON response structure.
impl IntoResponse for ApiError {
    fn into_response(self) -> Response {
        let (status, error_response) = match &self {
            ApiError::BadRequest { message } => (
                StatusCode::BAD_REQUEST,
                ErrorResponse {
                    error: ErrorDetails {
                        message: message.clone(),
                        type_: "bad_request".to_string(),
                        param: None,
                        code: None,
                    },
                },
            ),
            ApiError::MissingHeader { header } => (
                StatusCode::BAD_REQUEST,
                ErrorResponse {
                    error: ErrorDetails {
                        message: format!("Missing required header: {}", header),
                        type_: "missing_header".to_string(),
                        param: Some(header.clone()),
                        code: None,
                    },
                },
            ),
            ApiError::InvalidSystemPrompt => (
                StatusCode::BAD_REQUEST,
                ErrorResponse {
                    error: ErrorDetails {
                        message: "System prompt can only be provided once, either in root or messages array".to_string(),
                        type_: "invalid_system_prompt".to_string(),
                        param: None,
                        code: None,
                    },
                },
            ),
            ApiError::DeepSeekError { message, type_, param, code } => (
                StatusCode::BAD_REQUEST,
                ErrorResponse {
                    error: ErrorDetails {
                        message: format!("DeepSeek API Error: {}", message),
                        type_: format!("deepseek_{}", type_),
                        param: param.clone(),
                        code: code.clone(),
                    },
                },
            ),
            ApiError::AnthropicError { message, type_, param, code } => (
                StatusCode::BAD_REQUEST,
                ErrorResponse {
                    error: ErrorDetails {
                        message: format!("Anthropic API Error: {}", message),
                        type_: format!("anthropic_{}", type_),
                        param: param.clone(),
                        code: code.clone(),
                    },
                },
            ),
            ApiError::Internal { message } => (
                StatusCode::INTERNAL_SERVER_ERROR,
                ErrorResponse {
                    error: ErrorDetails {
                        message: message.clone(),
                        type_: "internal_error".to_string(),
                        param: None,
                        code: None,
                    },
                },
            ),
            ApiError::Other { message } => (
                StatusCode::INTERNAL_SERVER_ERROR,
                ErrorResponse {
                    error: ErrorDetails {
                        message: format!("Internal server error: {}", message),
                        type_: "internal_error".to_string(),
                        param: None,
                        code: None,
                    },
                },
            ),
        };

        (status, Json(error_response)).into_response()
    }
}

/// Converts generic errors into API errors.
///
/// This implementation allows using the `?` operator with functions that
/// return `anyhow::Error`, converting them into our custom `ApiError` type.
impl From<anyhow::Error> for ApiError {
    fn from(err: anyhow::Error) -> Self {
        ApiError::Other {
            message: err.to_string()
        }
    }
}

/// Type alias for Results using our custom ApiError type.
///
/// This provides a convenient way to use Result with our ApiError
/// throughout the application.
pub type Result<T> = std::result::Result<T, ApiError>;

/// Type alias for Server-Sent Events (SSE) results.
///
/// Used for streaming responses where errors are converted to Infallible
/// since they are handled within the stream.
pub type SseResult = std::result::Result<Event, Infallible>;

/// Type alias for SSE streams.
///
/// Represents a stream of SSE results that can be sent to clients.
pub type SseStream = ReceiverStream<SseResult>;

/// Type alias for SSE responses.
///
/// Represents the complete SSE response type used by the API endpoints.
pub type SseResponse = axum::response::sse::Sse<SseStream>;

//! Configuration management for the application.
//!
//! This module handles loading and managing configuration settings from files
//! and environment variables. It includes pricing configurations for different
//! AI model providers and server settings.

use serde::{Deserialize, Serialize};
use std::path::Path;

/// Root configuration structure containing all application settings.
///
/// This structure is typically loaded from a TOML configuration file
/// and provides access to all configurable aspects of the application.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct Config {
    pub server: ServerConfig,
    pub pricing: PricingConfig,
}

/// Server-specific configuration settings.
///
/// Contains settings related to the HTTP server, such as the
/// host address and port number to bind to.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ServerConfig {
    pub host: String,
    pub port: u16,
}

/// Pricing configuration for all supported AI models.
///
/// Contains pricing information for different AI model providers
/// and their various models, used for usage cost calculation.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PricingConfig {
    pub deepseek: DeepSeekPricing,
    pub anthropic: AnthropicPricing,
}

/// DeepSeek-specific pricing configuration.
///
/// Contains pricing rates for different aspects of DeepSeek API usage,
/// including cached and non-cached requests.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct DeepSeekPricing {
    pub input_cache_hit_price: f64,   // per million tokens
    pub input_cache_miss_price: f64,  // per million tokens
    pub output_price: f64,            // per million tokens
}

/// Anthropic-specific pricing configuration.
///
/// Contains pricing information for different Claude model variants
/// and their associated costs.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AnthropicPricing {
    pub claude_3_sonnet: ModelPricing,
    pub claude_3_haiku: ModelPricing,
    pub claude_3_opus: ModelPricing,
}

/// Generic model pricing configuration.
///
/// Contains detailed pricing information for a specific model,
/// including input, output, and caching costs.
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ModelPricing {
    pub input_price: f64,             // per million tokens
    pub output_price: f64,            // per million tokens
    pub cache_write_price: f64,       // per million tokens
    pub cache_read_price: f64,        // per million tokens
}

impl Config {
    /// Loads configuration from the default config file.
    ///
    /// Attempts to load and parse the configuration from 'config.toml'.
    /// Falls back to default values if the file cannot be loaded or parsed.
    ///
    /// # Returns
    ///
    /// * `anyhow::Result<Self>` - The loaded configuration or an error if loading fails
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The config file cannot be read
    /// - The TOML content cannot be parsed
    /// - The parsed content doesn't match the expected structure
    pub fn load() -> anyhow::Result<Self> {
        let config_path = Path::new("config.toml");
        let config = config::Config::builder()
            .add_source(config::File::from(config_path))
            .build()?;

        Ok(config.try_deserialize()?)
    }
}

/// Provides default configuration values.
///
/// These defaults are used when a configuration file is not present
/// or when specific values are not provided in the config file.
impl Default for Config {
    fn default() -> Self {
        Self {
            server: ServerConfig {
                host: "127.0.0.1".to_string(),
                port: 3000,
            },
            pricing: PricingConfig {
                deepseek: DeepSeekPricing {
                    input_cache_hit_price: 0.14,
                    input_cache_miss_price: 0.55,
                    output_price: 2.19,
                },
                anthropic: AnthropicPricing {
                    claude_3_sonnet: ModelPricing {
                        input_price: 3.0,
                        output_price: 15.0,
                        cache_write_price: 3.75,
                        cache_read_price: 0.30,
                    },
                    claude_3_haiku: ModelPricing {
                        input_price: 0.80,
                        output_price: 4.0,
                        cache_write_price: 1.0,
                        cache_read_price: 0.08,
                    },
                    claude_3_opus: ModelPricing {
                        input_price: 15.0,
                        output_price: 75.0,
                        cache_write_price: 18.75,
                        cache_read_price: 1.50,
                    },
                },
            },
        }
    }
}

//! Client implementations for external AI model providers.
//!
//! This module contains client implementations for different AI model providers:
//! - `anthropic`: Client for Anthropic's Claude models
//! - `deepseek`: Client for DeepSeek's reasoning models
//!
//! Each client handles authentication, request building, and response parsing
//! specific to its provider's API.

pub mod anthropic;
pub mod deepseek;

pub use anthropic::AnthropicClient;
pub use deepseek::DeepSeekClient;

use crate::error::Result;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use std::collections::HashMap;

/// Converts a HashMap of string headers to a reqwest HeaderMap.
///
/// This function is used internally by clients to convert user-provided
/// header maps into the format required by reqwest.
///
/// # Arguments
///
/// * `headers` - A HashMap containing header names and values as strings
///
/// # Returns
///
/// * `Result<HeaderMap>` - The converted HeaderMap on success, or an error if
///   any header name or value is invalid
///
/// # Errors
///
/// Returns `ApiError::BadRequest` if:
/// - A header name contains invalid characters
/// - A header value contains invalid characters
pub(crate) fn build_headers(headers: &HashMap<String, String>) -> Result<HeaderMap> {
    let mut header_map = HeaderMap::new();

    for (key, value) in headers {
        let header_name = HeaderName::from_bytes(key.as_bytes())
            .map_err(|e| crate::error::ApiError::BadRequest {
                message: format!("Invalid header name: {}", e)
            })?;

        let header_value = HeaderValue::from_str(value)
            .map_err(|e| crate::error::ApiError::BadRequest {
                message: format!("Invalid header value: {}", e)
            })?;

        header_map.insert(header_name, header_value);
    }

    Ok(header_map)
}

pub mod request;
pub mod response;

pub use request::*;
pub use response::*;

pub fn get_messages_with_system (&self) -> Vec<Message> {}

This code segment functions to: Consolidate and structure conversation messages by prioritizing the system prompt at the beginning while excluding duplicate system role entries from subsequent messages.

```rust
[TASK_BEGIN]
    pub fn get_messages_with_system(&self) -> Vec<Message> {
        if let Some(system_content) = &self.system {
            // Prepend system prompt from root configuration
            let mut messages = vec![Message {
                role: Role::System,
                content: system_content.clone(),
            }];
            messages.extend(self.messages.clone());
            messages
        } else {
            // Find first system message if exists in messages
            let system_message = self.messages.iter().find(|msg| msg.role == Role::System);

            match system_message {
                Some(sys_msg) => {
                    // Prepend system message and filter out other system messages
                    let mut messages = vec![sys_msg.clone()];
                    messages.extend(
                        self.messages
                            .iter()
                            .filter(|msg| msg.role != Role::System)
                            .cloned()
                    );
                    messages
                }
                None => self.messages.clone(),
            }
        }
    }
[TASK_END]
```

pub fn get_messages_with_system(&self) -> Vec<Message> {
        if let Some(system_content) = &self.system {
            let mut messages = vec![Message {
                role: Role::System,
                content: system_content.clone(),
            }];
            messages.extend(self.messages.clone());
            messages
        } else {
            let system_message = self.messages.iter().find(|msg| msg.role == Role::System);
            match system_message {
                Some(sys_msg) => {
                    let mut messages = vec![sys_msg.clone()];
                    messages.extend(
                        self.messages
                            .iter()
                            .filter(|msg| msg.role != Role::System)
                            .cloned()
                    );
                    messages
                }
                None => self.messages.clone(),
            }
        }
    }