/// Weather API Tool - Demonstrates external API integration
/// 
/// This tool calls an external weather API to get current weather data.
/// It demonstrates:
/// - Async HTTP requests with reqwest
/// - Error handling
/// - Event-driven execution

use crate::tool::Tool;
use async_trait::async_trait;
use lumina_engine::Event;
use serde_json::Value;
use tracing::debug;

/// Weather API Tool
/// 
/// Fetches weather data from OpenWeatherMap API (or similar).
/// 
/// Input format:
/// ```json
/// {
///   "city": "London",
///   "country": "UK",
///   "api_key": "your-api-key" // Optional, can use env var
/// }
/// ```
/// 
/// Output format:
/// ```json
/// {
///   "temperature": 15.5,
///   "humidity": 65,
///   "description": "Partly cloudy",
///   "city": "London"
/// }
/// ```
#[derive(Debug, Clone)]
pub struct WeatherApiTool {
    default_api_key: Option<String>,
}

impl WeatherApiTool {
    /// Create a new WeatherApiTool
    pub fn new(api_key: Option<String>) -> Self {
        Self {
            default_api_key: api_key,
        }
    }
    
    /// Fetch weather data from API
    async fn fetch_weather(&self, city: &str, country: Option<&str>, api_key: &str) -> Result<Value, String> {
        // Build API URL
        let location = if let Some(country) = country {
            format!("{},{}", city, country)
        } else {
            city.to_string()
        };
        
        let url = format!(
            "https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units=metric",
            location, api_key
        );
        
        debug!("Fetching weather for: {}", location);
        
        // Make HTTP request
        let client = reqwest::Client::new();
        let response = client
            .get(&url)
            .timeout(std::time::Duration::from_secs(10))
            .send()
            .await
            .map_err(|e| format!("HTTP request failed: {}", e))?;
        
        if !response.status().is_success() {
            return Err(format!("API returned error: {}", response.status()));
        }
        
        let json: Value = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse JSON: {}", e))?;
        
        // Extract relevant data
        let main = json.get("main").ok_or("Missing 'main' in response")?;
        let weather = json.get("weather")
            .and_then(|w| w.as_array())
            .and_then(|arr| arr.first())
            .ok_or("Missing 'weather' in response")?;
        
        let result = serde_json::json!({
            "temperature": main.get("temp"),
            "feels_like": main.get("feels_like"),
            "humidity": main.get("humidity"),
            "pressure": main.get("pressure"),
            "description": weather.get("description"),
            "city": city,
            "country": country,
        });
        
        Ok(result)
    }
}

#[async_trait]
impl Tool for WeatherApiTool {
    fn name(&self) -> &'static str {
        "weather_api"
    }
    
    fn description(&self) -> &'static str {
        "Fetches current weather data for a given city from OpenWeatherMap API"
    }
    
    fn schema(&self) -> Option<Value> {
        Some(serde_json::json!({
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name"
                },
                "country": {
                    "type": "string",
                    "description": "Country code (optional)"
                },
                "api_key": {
                    "type": "string",
                    "description": "OpenWeatherMap API key (optional, can use env var)"
                }
            },
            "required": ["city"]
        }))
    }
    
    async fn execute(&self, input: Value, _event: &Event) -> Result<Value, String> {
        // Extract parameters
        let city = input
            .get("city")
            .and_then(|v| v.as_str())
            .ok_or("Missing required parameter: 'city'")?;
        
        let country = input
            .get("country")
            .and_then(|v| v.as_str());
        
        // Get API key from input, default_api_key, or environment
        let env_api_key = std::env::var("OPENWEATHER_API_KEY").ok();
        let api_key = input
            .get("api_key")
            .and_then(|v| v.as_str())
            .or_else(|| self.default_api_key.as_deref())
            .or_else(|| env_api_key.as_deref())
            .ok_or("API key required. Provide 'api_key' in input, set default_api_key, or set OPENWEATHER_API_KEY env var")?;
        
        // Fetch weather
        self.fetch_weather(city, country, api_key).await
    }
}

impl Default for WeatherApiTool {
    fn default() -> Self {
        Self::new(None)
    }
}

