use async_trait::async_trait;
use reqwest::Client;
use serde::Deserialize;
use tracing::instrument;

use crate::types::Claim;

use super::{
    client::{LlmClient, LlmConfig},
    error::{LlmError, Result},
    prompt,
    response::handle_api_response,
};

pub struct GroqClient {
    client: Client,
    config: LlmConfig,
}

#[derive(Debug, Deserialize)]
struct GroqResponse {
    choices: Vec<GroqChoice>,
}

#[derive(Debug, Deserialize)]
struct GroqChoice {
    message: GroqMessage,
}

#[derive(Debug, Deserialize)]
struct GroqMessage {
    content: String,
}

impl GroqClient {
    pub fn new(config: LlmConfig) -> Self {
        let client = Client::builder()
            .timeout(std::time::Duration::from_secs(config.timeout_secs))
            .build()
            .unwrap_or_default();
        Self { client, config }
    }
}

#[async_trait]
impl LlmClient for GroqClient {
    #[instrument(skip(self), fields(text_len = text.len()))]
    async fn extract_claims(&self, text: &str) -> Result<Vec<Claim>> {
        let response = self
            .client
            .post("https://api.groq.com/openai/v1/chat/completions")
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .json(&serde_json::json!({
                "model": "llama-3.3-70b-versatile",
                "max_tokens": 4096,
                "messages": [
                    {"role": "system", "content": prompt::EXTRACTION_SYSTEM_PROMPT},
                    {"role": "user", "content": prompt::build_extraction_message(text)}
                ]
            }))
            .send()
            .await
            .map_err(|e| LlmError::from_reqwest(&e, self.config.timeout_secs))?;

        handle_api_response::<GroqResponse, _>(response, |body| {
            body.choices.first().map(|c| c.message.content.clone())
        })
        .await
    }

    async fn test_connection(&self) -> Result<()> {
        // Send minimal request to verify API key
        let response = self
            .client
            .post("https://api.groq.com/openai/v1/chat/completions")
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .json(&serde_json::json!({
                "model": "llama-3.3-70b-versatile",
                "max_tokens": 10,
                "messages": [{"role": "user", "content": "Hi"}]
            }))
            .send()
            .await
            .map_err(|e| LlmError::from_reqwest(&e, self.config.timeout_secs))?;

        match response.status().as_u16() {
            200 => Ok(()),
            401 => Err(LlmError::AuthenticationFailed),
            _ => Err(LlmError::ServiceUnavailable(response.status().to_string())),
        }
    }
}
