//! Claude API client wrapper

use serde::{Deserialize, Serialize};

use crate::error::ClaudeError;

/// Default API base URL
const DEFAULT_API_BASE: &str = "https://api.anthropic.com";

/// Default model to use
const DEFAULT_MODEL: &str = "claude-sonnet-4-20250514";

/// Client for interacting with Claude API
pub struct ClaudeClient {
    api_key: String,
    model: String,
    api_base: String,
    max_tokens: u32,
}

impl ClaudeClient {
    /// Create a new Claude client
    #[must_use]
    pub fn new(api_key: impl Into<String>) -> Self {
        Self {
            api_key: api_key.into(),
            model: DEFAULT_MODEL.to_string(),
            api_base: DEFAULT_API_BASE.to_string(),
            max_tokens: 4096,
        }
    }

    /// Set the model to use
    #[must_use]
    pub fn with_model(mut self, model: impl Into<String>) -> Self {
        self.model = model.into();
        self
    }

    /// Set a custom API base URL
    #[must_use]
    pub fn with_api_base(mut self, api_base: impl Into<String>) -> Self {
        self.api_base = api_base.into();
        self
    }

    /// Set the maximum tokens for responses
    #[must_use]
    pub fn with_max_tokens(mut self, max_tokens: u32) -> Self {
        self.max_tokens = max_tokens;
        self
    }

    /// Get the model being used
    #[must_use]
    pub fn model(&self) -> &str {
        &self.model
    }

    /// Get the API key
    #[must_use]
    pub fn api_key(&self) -> &str {
        &self.api_key
    }

    /// Get the API base URL
    #[must_use]
    pub fn api_base(&self) -> &str {
        &self.api_base
    }

    /// Send a message to Claude and get a response
    ///
    /// # Errors
    /// Returns an error if the API request fails
    pub async fn send_message(&self, message: &str) -> Result<String, ClaudeError> {
        let request = MessageRequest {
            model: self.model.clone(),
            max_tokens: self.max_tokens,
            messages: vec![Message {
                role: Role::User,
                content: message.to_string(),
            }],
            system: None,
        };

        self.send_request(request).await
    }

    /// Send a message with a system prompt
    ///
    /// # Errors
    /// Returns an error if the API request fails
    pub async fn send_message_with_system(
        &self,
        system: &str,
        message: &str,
    ) -> Result<String, ClaudeError> {
        let request = MessageRequest {
            model: self.model.clone(),
            max_tokens: self.max_tokens,
            messages: vec![Message {
                role: Role::User,
                content: message.to_string(),
            }],
            system: Some(system.to_string()),
        };

        self.send_request(request).await
    }

    /// Send a conversation with multiple messages
    ///
    /// # Errors
    /// Returns an error if the API request fails
    pub async fn send_conversation(
        &self,
        messages: Vec<Message>,
        system: Option<String>,
    ) -> Result<String, ClaudeError> {
        let request = MessageRequest {
            model: self.model.clone(),
            max_tokens: self.max_tokens,
            messages,
            system,
        };

        self.send_request(request).await
    }

    async fn send_request(&self, request: MessageRequest) -> Result<String, ClaudeError> {
        tracing::debug!(
            "Sending request to Claude using model: {} with {} messages",
            self.model,
            request.messages.len()
        );

        // TODO: Implement actual HTTP request to Claude API
        // For now, return a placeholder response
        let _ = request; // Suppress unused warning

        Ok("Claude response placeholder".to_string())
    }
}

/// A message in a conversation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
    /// Role of the message sender
    pub role: Role,
    /// Content of the message
    pub content: String,
}

impl Message {
    /// Create a user message
    #[must_use]
    pub fn user(content: impl Into<String>) -> Self {
        Self {
            role: Role::User,
            content: content.into(),
        }
    }

    /// Create an assistant message
    #[must_use]
    pub fn assistant(content: impl Into<String>) -> Self {
        Self {
            role: Role::Assistant,
            content: content.into(),
        }
    }
}

/// Role in a conversation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
    /// User message
    User,
    /// Assistant (Claude) message
    Assistant,
}

/// Request to the Claude messages API
#[derive(Debug, Clone, Serialize)]
struct MessageRequest {
    model: String,
    max_tokens: u32,
    messages: Vec<Message>,
    #[serde(skip_serializing_if = "Option::is_none")]
    system: Option<String>,
}

/// Response from the Claude messages API
#[derive(Debug, Clone, Deserialize)]
#[allow(dead_code)]
pub struct MessageResponse {
    /// Response ID
    pub id: String,
    /// Model used
    pub model: String,
    /// Stop reason
    pub stop_reason: Option<String>,
    /// Content blocks
    pub content: Vec<ContentBlock>,
    /// Usage information
    pub usage: Usage,
}

/// A content block in a response
#[derive(Debug, Clone, Deserialize)]
#[serde(tag = "type")]
pub enum ContentBlock {
    /// Text content
    #[serde(rename = "text")]
    Text {
        /// The text content
        text: String,
    },
}

/// Token usage information
#[derive(Debug, Clone, Deserialize)]
pub struct Usage {
    /// Input tokens used
    pub input_tokens: u32,
    /// Output tokens used
    pub output_tokens: u32,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_client_creation() {
        let client = ClaudeClient::new("test-api-key");
        assert_eq!(client.api_key(), "test-api-key");
        assert_eq!(client.model(), DEFAULT_MODEL);
    }

    #[test]
    fn test_client_with_model() {
        let client = ClaudeClient::new("test-api-key").with_model("claude-3-opus-20240229");
        assert_eq!(client.model(), "claude-3-opus-20240229");
    }

    #[test]
    fn test_client_with_custom_base() {
        let client = ClaudeClient::new("test-api-key").with_api_base("https://custom.api.com");
        assert_eq!(client.api_base(), "https://custom.api.com");
    }

    #[test]
    fn test_message_creation() {
        let user_msg = Message::user("Hello");
        assert_eq!(user_msg.role, Role::User);
        assert_eq!(user_msg.content, "Hello");

        let assistant_msg = Message::assistant("Hi there!");
        assert_eq!(assistant_msg.role, Role::Assistant);
    }

    #[tokio::test]
    async fn test_send_message() {
        let client = ClaudeClient::new("test-api-key");
        let response = client.send_message("Hello").await.unwrap();
        assert!(!response.is_empty());
    }
}
