/// Python tool wrapper for Rust tool system
use pyo3::prelude::*;
use pyo3::types::PyDict;
use lumina_tools::Tool;
use lumina_engine::Event;
use async_trait::async_trait;
use serde_json::Value;

/// Python tool implementation that wraps a Python callable
#[derive(Debug)]
pub struct PythonTool {
    name: &'static str,
    name_string: String,
    description: &'static str,
    description_string: String,
    parameters: Value,
    py_func: PyObject,
}

impl PythonTool {
    pub fn new(
        name: String,
        description: String,
        parameters: Value,
        py_func: PyObject,
    ) -> Self {
        let name_static = Box::leak(name.clone().into_boxed_str());
        let desc_static = Box::leak(description.clone().into_boxed_str());
        Self {
            name: name_static,
            name_string: name,
            description: desc_static,
            description_string: description,
            parameters,
            py_func,
        }
    }
}

#[async_trait]
impl Tool for PythonTool {
    fn name(&self) -> &'static str {
        self.name
    }
    
    fn description(&self) -> &'static str {
        self.description
    }
    
    fn schema(&self) -> Option<Value> {
        Some(serde_json::json!({
            "name": self.name_string,
            "description": self.description_string,
            "parameters": self.parameters,
        }))
    }
    
    async fn execute(
        &self,
        input: Value,
        _event: &Event,
    ) -> Result<Value, String> {
        Python::with_gil(|py| {
            // Convert JSON parameters to Python dict
            let py_dict = PyDict::new(py);
            
            if let Value::Object(map) = input {
                for (key, value) in map {
                    let py_value: PyObject = match value {
                        Value::String(s) => s.to_object(py),
                        Value::Number(n) => {
                            if n.is_i64() {
                                n.as_i64().unwrap().to_object(py)
                            } else if n.is_u64() {
                                n.as_u64().unwrap().to_object(py)
                            } else {
                                n.as_f64().unwrap().to_object(py)
                            }
                        }
                        Value::Bool(b) => b.to_object(py),
                        Value::Null => py.None(),
                        Value::Array(_) | Value::Object(_) => {
                            // For complex types, convert to JSON string
                            serde_json::to_string(&value)
                                .unwrap_or_default()
                                .to_object(py)
                        }
                    };
                    py_dict.set_item(key, py_value)?;
                }
            }
            
            // Call Python function with kwargs
            let result = self.py_func.call(py, (), Some(py_dict))?;
            
            // Convert result back to JSON
            // Try to extract as dict first, then string
            let json_value = if let Ok(dict) = result.downcast::<PyDict>(py) {
                // Convert Python dict to JSON
                let mut json_map = serde_json::Map::new();
                for (key, value) in dict.iter() {
                    let key_str = key.to_string();
                    let value_str = value.to_string();
                    json_map.insert(key_str, Value::String(value_str));
                }
                Value::Object(json_map)
            } else {
                // Convert to string and try to parse as JSON
                let result_str = result.to_string();
                serde_json::from_str(&result_str)
                    .unwrap_or_else(|_| Value::String(result_str))
            };
            
            Ok(json_value)
        })
        .map_err(|e: PyErr| format!("Python tool error: {}", e))
    }
}

