use serde::{Deserialize, Serialize};

use super::{brave, tavily};

/// Which search backend the AI tool layer should call.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SearchProvider {
    Tavily,
    Brave,
}

impl SearchProvider {
    /// Parse the `SEARCH_PROVIDER` environment variable into a supported variant.
    pub fn from_env(value: Option<&str>) -> Result<Self, String> {
        match value
            .unwrap_or("tavily")
            .trim()
            .to_ascii_lowercase()
            .as_str()
        {
            "tavily" => Ok(Self::Tavily),
            "brave" => Ok(Self::Brave),
            other => Err(format!(
                "Unsupported SEARCH_PROVIDER '{}'. Expected 'tavily' or 'brave'.",
                other
            )),
        }
    }

    /// Return the environment variable name required by the selected provider.
    pub fn required_key_name(self) -> &'static str {
        match self {
            Self::Tavily => "TAVILY_API_KEY",
            Self::Brave => "BRAVE_API_KEY",
        }
    }
}

/// Normalized search result shape shared across providers.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
    pub title: String,
    pub url: String,
    pub description: String,
    pub age: Option<String>,
}

/// Dispatch a search request to whichever provider the server is configured to use.
pub async fn search(
    provider: SearchProvider,
    query: &str,
    tavily_api_key: Option<&str>,
    brave_api_key: Option<&str>,
    count: u8,
) -> Result<Vec<SearchResult>, String> {
    match provider {
        SearchProvider::Tavily => {
            let api_key = tavily_api_key
                .filter(|key| !key.is_empty())
                .ok_or_else(|| "TAVILY_API_KEY is not configured".to_string())?;
            tavily::search(query, api_key, count).await
        }
        SearchProvider::Brave => {
            let api_key = brave_api_key
                .filter(|key| !key.is_empty())
                .ok_or_else(|| "BRAVE_API_KEY is not configured".to_string())?;
            brave::search(query, api_key, count).await
        }
    }
}

/// Turn search results into plain text the AI model can read as tool output.
pub fn format_results(results: &[SearchResult]) -> String {
    if results.is_empty() {
        return "No search results found.".to_string();
    }

    let mut output = String::new();
    for (i, r) in results.iter().enumerate() {
        output.push_str(&format!("{}. {}\n", i + 1, r.title));
        if !r.url.is_empty() {
            output.push_str(&format!("   URL: {}\n", r.url));
        }
        if let Some(age) = &r.age {
            output.push_str(&format!("   Age: {}\n", age));
        }
        output.push_str(&format!("   {}\n\n", r.description));
    }
    output
}
