//! Generation options for LLM inference

use serde::{Deserialize, Serialize};

/// Options for LLM text generation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationOptions {
    /// Sampling temperature (0.0 = deterministic, 2.0 = creative)
    #[serde(default = "default_temperature")]
    pub temperature: f32,

    /// Maximum tokens to generate
    #[serde(default = "default_max_tokens")]
    pub max_tokens: Option<usize>,

    /// Sequences that stop generation
    #[serde(default)]
    pub stop_sequences: Vec<String>,

    /// Top-k sampling (keep top k tokens)
    #[serde(default)]
    pub top_k: Option<usize>,

    /// Nucleus sampling (cumulative probability threshold)
    #[serde(default)]
    pub top_p: Option<f32>,

    /// Presence penalty (-2.0 to 2.0)
    #[serde(default)]
    pub presence_penalty: Option<f32>,

    /// Frequency penalty (-2.0 to 2.0)
    #[serde(default)]
    pub frequency_penalty: Option<f32>,
}

fn default_temperature() -> f32 {
    0.7
}

fn default_max_tokens() -> Option<usize> {
    Some(2048)
}

impl Default for GenerationOptions {
    fn default() -> Self {
        GenerationOptions {
            temperature: default_temperature(),
            max_tokens: default_max_tokens(),
            stop_sequences: vec![],
            top_k: None,
            top_p: None,
            presence_penalty: None,
            frequency_penalty: None,
        }
    }
}

impl GenerationOptions {
    /// Create options optimized for reasoning/analysis
    pub fn analytical() -> Self {
        GenerationOptions {
            temperature: 0.3,
            max_tokens: Some(4096),
            ..Default::default()
        }
    }

    /// Create options optimized for creative generation
    pub fn creative() -> Self {
        GenerationOptions {
            temperature: 1.2,
            max_tokens: Some(2048),
            top_p: Some(0.95),
            ..Default::default()
        }
    }

    /// Create options for config generation (deterministic, concise)
    pub fn config_generation() -> Self {
        GenerationOptions {
            temperature: 0.1,
            max_tokens: Some(8192),
            stop_sequences: vec!["```".to_string()],
            ..Default::default()
        }
    }
}

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

    #[test]
    fn test_default_options() {
        let opts = GenerationOptions::default();
        assert_eq!(opts.temperature, 0.7);
        assert_eq!(opts.max_tokens, Some(2048));
        assert!(opts.stop_sequences.is_empty());
    }

    #[test]
    fn test_analytical_options() {
        let opts = GenerationOptions::analytical();
        assert_eq!(opts.temperature, 0.3);
        assert_eq!(opts.max_tokens, Some(4096));
    }

    #[test]
    fn test_creative_options() {
        let opts = GenerationOptions::creative();
        assert_eq!(opts.temperature, 1.2);
        assert_eq!(opts.top_p, Some(0.95));
    }

    #[test]
    fn test_config_options() {
        let opts = GenerationOptions::config_generation();
        assert_eq!(opts.temperature, 0.1);
        assert_eq!(opts.max_tokens, Some(8192));
        assert!(!opts.stop_sequences.is_empty());
    }
}
