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

/// LLM request with deterministic parameters
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LLMRequest {
    pub prompt: String,
    pub system_prompt: Option<String>,
    pub temperature: f64,
    pub max_tokens: Option<u32>,
    pub seed: u64, // For deterministic sampling
    pub stop_sequences: Vec<String>,
    pub metadata: HashMap<String, String>,
}

/// LLM response
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LLMResponse {
    pub text: String,
    pub model: String,
    pub usage: TokenUsage,
    pub finish_reason: Option<String>,
    pub metadata: HashMap<String, String>,
}

/// Token usage statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenUsage {
    pub prompt_tokens: u32,
    pub completion_tokens: u32,
    pub total_tokens: u32,
}

/// LLM adapter trait
#[async_trait]
pub trait LLMAdapter: Send + Sync {
    /// Get adapter name
    fn name(&self) -> &str;
    
    /// Generate text from a request
    async fn generate(&self, request: &LLMRequest) -> Result<LLMResponse, LLMError>;
    
    /// Generate embeddings (if supported)
    async fn embed(&self, _text: &str) -> Result<Vec<f32>, LLMError> {
        Err(LLMError::NotSupported("Embeddings not supported".to_string()))
    }
    
    /// Check if adapter supports embeddings
    fn supports_embeddings(&self) -> bool {
        false
    }
}

/// LLM errors
#[derive(Debug, thiserror::Error)]
pub enum LLMError {
    #[error("LLM API error: {0}")]
    APIError(String),
    
    #[error("Invalid request: {0}")]
    InvalidRequest(String),
    
    #[error("Timeout")]
    Timeout,
    
    #[error("Not supported: {0}")]
    NotSupported(String),
    
    #[error("Serialization error: {0}")]
    SerializationError(#[from] serde_json::Error),
    
    #[error("HTTP error: {0}")]
    HttpError(#[from] reqwest::Error),
}

