/// Runtime context for event handler execution

use super::components::{Component, ComponentProps};
use std::collections::HashMap;
use std::io::Read;
use num_bigint::BigInt;
use num_traits::{Zero, One, ToPrimitive};
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};

/// Trait that event handlers use to interact with components
pub trait ComponentContext {
    /// Get text from a component (Text/InputText/Button labels)
    fn get_text(&self, name: &str) -> Option<String>;
    
    /// Set text on a component
    fn set_text(&mut self, name: &str, text: String) -> bool;
    
    /// Get checked state (Checkbox)
    fn get_checked(&self, name: &str) -> Option<bool>;
    
    /// Set checked state
    fn set_checked(&mut self, name: &str, checked: bool) -> bool;
    
    /// Get numeric value (Slider/ProgressBar)
    fn get_value(&self, name: &str) -> Option<f32>;
    
    /// Set numeric value
    fn set_value(&mut self, name: &str, value: f32) -> bool;
    
    /// Get color value (ColorPicker/Text color)
    fn get_color(&self, name: &str) -> Option<[f32; 4]>;
    
    /// Set color value
    fn set_color(&mut self, name: &str, color: [f32; 4]) -> bool;

    /// Set ComboBox items
    fn set_combobox_items(&mut self, name: &str, items: Vec<String>) -> Result<(), String>;

    /// Get the currently selected value from a ComboBox
    fn get_combobox_value(&self, name: &str) -> Option<String>;

    /// Show a message popup
    fn show_message(&mut self, msg: &str);

    /// Log a message to console
    fn log(&mut self, msg: &str);

    /// HTTP GET request
    fn http_get(&mut self, url: &str, headers: &str) -> Result<(u16, String), String>;

    /// HTTP POST request
    fn http_post(&mut self, url: &str, headers: &str, body: &str) -> Result<(u16, String), String>;

    /// HTTP PUT request
    fn http_put(&mut self, url: &str, headers: &str, body: &str) -> Result<(u16, String), String>;

    /// HTTP DELETE request
    fn http_delete(&mut self, url: &str, headers: &str) -> Result<(u16, String), String>;

    /// Parse JSON and extract value at path
    fn parse_json(&self, json: &str, path: &str) -> Result<String, String>;

    /// Build JSON from key-value pairs
    fn build_json(&self, pairs: &[(&str, &str)]) -> Result<String, String>;

    /// Execute a SQL query (returns rows affected)
    fn execute_query(&mut self, query: &str, params: &str) -> Result<u64, String>;

    /// Execute a SQL query (returns JSON rows)
    fn query_rows(&self, query: &str, params: &str) -> Result<String, String>;
}

/// Runtime value type
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum RuntimeValue {
    String(String),
    Float(f32),
    Bool(bool),
    Color([f32; 4]),
    BigInt(BigInt),
    Array(Vec<RuntimeValue>),           // NEW - Collection of values
    Map(HashMap<String, RuntimeValue>),  // NEW - Key-value pairs
    Tuple(Vec<RuntimeValue>),            // NEW - Fixed-size (2-4 elements)
    None,
}

impl RuntimeValue {
    pub fn as_string(&self) -> String {
        match self {
            RuntimeValue::String(s) => s.clone(),
            RuntimeValue::Float(f) => f.to_string(),
            RuntimeValue::Bool(b) => b.to_string(),
            RuntimeValue::Color(c) => format!("[{}, {}, {}, {}]", c[0], c[1], c[2], c[3]),
            RuntimeValue::BigInt(n) => n.to_string(),
            RuntimeValue::Array(arr) => {
                let elements: Vec<String> = arr.iter().map(|v| v.as_string()).collect();
                format!("[{}]", elements.join(", "))
            }
            RuntimeValue::Map(map) => {
                let pairs: Vec<String> = map.iter()
                    .map(|(k, v)| format!("{}: {}", k, v.as_string()))
                    .collect();
                format!("{{{}}}", pairs.join(", "))
            }
            RuntimeValue::Tuple(tuple) => {
                let elements: Vec<String> = tuple.iter().map(|v| v.as_string()).collect();
                format!("({})", elements.join(", "))
            }
            RuntimeValue::None => String::new(),
        }
    }

    pub fn as_float(&self) -> f32 {
        match self {
            RuntimeValue::Float(f) => *f,
            RuntimeValue::String(s) => s.parse().unwrap_or(0.0),
            RuntimeValue::Bool(b) => if *b { 1.0 } else { 0.0 },
            RuntimeValue::BigInt(n) => n.to_f32().unwrap_or(0.0),
            RuntimeValue::Array(arr) => arr.len() as f32,  // Length as float
            RuntimeValue::Map(map) => map.len() as f32,    // Length as float
            RuntimeValue::Tuple(tuple) => tuple.len() as f32,
            _ => 0.0,
        }
    }

    pub fn as_bool(&self) -> bool {
        match self {
            RuntimeValue::Bool(b) => *b,
            RuntimeValue::String(s) => !s.is_empty(),
            RuntimeValue::Float(f) => *f != 0.0,
            RuntimeValue::BigInt(n) => !n.is_zero(),
            RuntimeValue::Array(arr) => !arr.is_empty(),   // Non-empty is true
            RuntimeValue::Map(map) => !map.is_empty(),
            RuntimeValue::Tuple(tuple) => !tuple.is_empty(),
            _ => false,
        }
    }

    pub fn as_color(&self) -> [f32; 4] {
        match self {
            RuntimeValue::Color(c) => *c,
            _ => [1.0, 1.0, 1.0, 1.0],
        }
    }

    pub fn as_bigint(&self) -> BigInt {
        match self {
            RuntimeValue::BigInt(n) => n.clone(),
            RuntimeValue::Float(f) => BigInt::from(*f as i64),
            RuntimeValue::String(s) => s.parse().unwrap_or_else(|_| BigInt::zero()),
            RuntimeValue::Bool(b) => if *b { BigInt::one() } else { BigInt::zero() },
            _ => BigInt::zero(),
        }
    }

    // NEW: Array accessor methods
    pub fn as_array(&self) -> Vec<RuntimeValue> {
        match self {
            RuntimeValue::Array(arr) => arr.clone(),
            _ => Vec::new(),
        }
    }

    pub fn as_array_ref(&self) -> Option<&Vec<RuntimeValue>> {
        match self {
            RuntimeValue::Array(arr) => Some(arr),
            _ => None,
        }
    }

    pub fn as_array_mut(&mut self) -> Option<&mut Vec<RuntimeValue>> {
        match self {
            RuntimeValue::Array(arr) => Some(arr),
            _ => None,
        }
    }

    pub fn array_get(&self, index: usize) -> Result<RuntimeValue, String> {
        match self {
            RuntimeValue::Array(arr) => {
                arr.get(index)
                    .cloned()
                    .ok_or_else(|| format!("Index {} out of bounds (array length: {})", index, arr.len()))
            }
            _ => Err("Value is not an array".to_string()),
        }
    }

    pub fn array_set(&mut self, index: usize, value: RuntimeValue) -> Result<(), String> {
        match self {
            RuntimeValue::Array(arr) => {
                if index < arr.len() {
                    arr[index] = value;
                    Ok(())
                } else {
                    Err(format!("Index {} out of bounds (array length: {})", index, arr.len()))
                }
            }
            _ => Err("Value is not an array".to_string()),
        }
    }

    pub fn array_push(&mut self, value: RuntimeValue) -> Result<(), String> {
        match self {
            RuntimeValue::Array(arr) => {
                arr.push(value);
                Ok(())
            }
            _ => Err("Value is not an array".to_string()),
        }
    }

    pub fn array_len(&self) -> Result<usize, String> {
        match self {
            RuntimeValue::Array(arr) => Ok(arr.len()),
            _ => Err("Value is not an array".to_string()),
        }
    }

    // NEW: Map accessor methods
    pub fn as_map(&self) -> HashMap<String, RuntimeValue> {
        match self {
            RuntimeValue::Map(map) => map.clone(),
            _ => HashMap::new(),
        }
    }

    pub fn as_map_ref(&self) -> Option<&HashMap<String, RuntimeValue>> {
        match self {
            RuntimeValue::Map(map) => Some(map),
            _ => None,
        }
    }

    pub fn as_map_mut(&mut self) -> Option<&mut HashMap<String, RuntimeValue>> {
        match self {
            RuntimeValue::Map(map) => Some(map),
            _ => None,
        }
    }

    pub fn map_get(&self, key: &str) -> Result<RuntimeValue, String> {
        match self {
            RuntimeValue::Map(map) => {
                map.get(key)
                    .cloned()
                    .ok_or_else(|| format!("Key '{}' not found in map", key))
            }
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_set(&mut self, key: String, value: RuntimeValue) -> Result<(), String> {
        match self {
            RuntimeValue::Map(map) => {
                map.insert(key, value);
                Ok(())
            }
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_has(&self, key: &str) -> Result<bool, String> {
        match self {
            RuntimeValue::Map(map) => Ok(map.contains_key(key)),
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_remove(&mut self, key: &str) -> Result<Option<RuntimeValue>, String> {
        match self {
            RuntimeValue::Map(map) => Ok(map.remove(key)),
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_keys(&self) -> Result<Vec<String>, String> {
        match self {
            RuntimeValue::Map(map) => Ok(map.keys().cloned().collect()),
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_values(&self) -> Result<Vec<RuntimeValue>, String> {
        match self {
            RuntimeValue::Map(map) => Ok(map.values().cloned().collect()),
            _ => Err("Value is not a map".to_string()),
        }
    }

    pub fn map_len(&self) -> Result<usize, String> {
        match self {
            RuntimeValue::Map(map) => Ok(map.len()),
            _ => Err("Value is not a map".to_string()),
        }
    }

    // NEW: Tuple accessor methods
    pub fn as_tuple(&self) -> Vec<RuntimeValue> {
        match self {
            RuntimeValue::Tuple(tuple) => tuple.clone(),
            _ => Vec::new(),
        }
    }

    pub fn tuple_get(&self, index: usize) -> Result<RuntimeValue, String> {
        match self {
            RuntimeValue::Tuple(tuple) => {
                tuple.get(index)
                    .cloned()
                    .ok_or_else(|| format!("Index {} out of bounds (tuple size: {})", index, tuple.len()))
            }
            _ => Err("Value is not a tuple".to_string()),
        }
    }
}

/// Function call frame for managing local variables and return values
#[derive(Debug, Clone)]
pub struct FunctionFrame {
    pub function_id: usize,
    pub local_vars: HashMap<String, RuntimeValue>,
    pub return_value: Option<RuntimeValue>,
    pub return_address: Option<usize>,  // Pin ID to return to after function completes
}

/// Runtime context managing component state and handler execution
/// A log entry with source tracking
#[derive(Debug, Clone)]
pub struct LogEntry {
    pub timestamp: String,
    pub message: String,
    pub source_component_id: Option<usize>,
}

pub struct RuntimeContext {
    /// Component references by name
    components: Vec<Component>,
    /// Message queue for popups
    message_queue: Vec<String>,
    /// Log buffer with source tracking
    log_buffer: Vec<LogEntry>,
    /// Persistent variables
    variables: HashMap<String, RuntimeValue>,
    /// Temporary values for node execution (NodeId -> {PinName -> Value})
    temp_values: HashMap<(usize, String), RuntimeValue>,
    /// Function call stack for managing function execution
    function_stack: Vec<FunctionFrame>,
    /// Current executing component ID (for log source tracking)
    current_component_id: Option<usize>,
    /// Open modal form names
    open_modals: Vec<String>,
    /// Table data for DataTable components (component_name -> rows)
    table_data: HashMap<String, Vec<HashMap<String, String>>>,
}

impl RuntimeContext {
    pub fn new(components: Vec<Component>) -> Self {
        Self {
            components,
            message_queue: Vec::new(),
            log_buffer: Vec::new(),
            variables: HashMap::new(),
            temp_values: HashMap::new(),
            function_stack: Vec::new(),
            current_component_id: None,
            open_modals: Vec::new(),
            table_data: HashMap::new(),
        }
    }

    /// Create a new RuntimeContext with initialized variables
    pub fn with_variables(components: Vec<Component>, variables: &[super::nodes::Variable]) -> Self {
        let mut var_map = HashMap::new();

        // Initialize all variables with their default values
        for var in variables {
            let value = match &var.default_value {
                super::nodes::VariableValue::String(s) => RuntimeValue::String(s.clone()),
                super::nodes::VariableValue::Float(f) => RuntimeValue::Float(*f),
                super::nodes::VariableValue::Bool(b) => RuntimeValue::Bool(*b),
                super::nodes::VariableValue::Color(c) => RuntimeValue::Color(*c),
            };
            var_map.insert(var.name.clone(), value);
        }

        Self {
            components,
            message_queue: Vec::new(),
            log_buffer: Vec::new(),
            variables: var_map,
            temp_values: HashMap::new(),
            function_stack: Vec::new(),
            current_component_id: None,
            open_modals: Vec::new(),
            table_data: HashMap::new(),
        }
    }

    /// Update the component list (call this when components change)
    pub fn update_components(&mut self, components: Vec<Component>) {
        self.components = components;
    }

    /// Get the updated components back (after handlers have modified them)
    pub fn get_components(&self) -> &[Component] {
        &self.components
    }

    /// Get pending messages
    pub fn take_messages(&mut self) -> Vec<String> {
        std::mem::take(&mut self.message_queue)
    }

    /// Get log buffer
    pub fn get_logs(&self) -> &[LogEntry] {
        &self.log_buffer
    }

    /// Get logs filtered by component ID
    pub fn get_logs_for_component(&self, component_id: usize) -> Vec<LogEntry> {
        self.log_buffer.iter()
            .filter(|entry| entry.source_component_id == Some(component_id))
            .cloned()
            .collect()
    }

    /// Clear logs
    pub fn clear_logs(&mut self) {
        self.log_buffer.clear();
    }

    /// Set the current executing component (for log source tracking)
    pub fn set_current_component(&mut self, component_id: Option<usize>) {
        self.current_component_id = component_id;
    }

    /// Find component by name
    /// Handles both "ComponentName" and "FormName::ComponentName" formats
    fn find_component(&self, name: &str) -> Option<&Component> {
        // Extract just the component name if it's in "FormName::ComponentName" format
        let component_name = if name.contains("::") {
            name.split("::").last().unwrap_or(name)
        } else {
            name
        };
        self.components.iter().find(|c| c.name.as_deref() == Some(component_name))
    }

    /// Find mutable component by name
    /// Handles both "ComponentName" and "FormName::ComponentName" formats
    fn find_component_mut(&mut self, name: &str) -> Option<&mut Component> {
        // Extract just the component name if it's in "FormName::ComponentName" format
        let component_name = if name.contains("::") {
            name.split("::").last().unwrap_or(name)
        } else {
            name
        };
        self.components.iter_mut().find(|c| c.name.as_deref() == Some(component_name))
    }

    pub fn get_variable(&self, name: &str) -> Option<RuntimeValue> {
        self.variables.get(name).cloned()
    }

    pub fn set_variable(&mut self, name: String, value: RuntimeValue) {
        self.variables.insert(name, value);
    }

    pub fn get_temp_value(&self, node_id: usize, pin_name: &str) -> Option<RuntimeValue> {
        self.temp_values.get(&(node_id, pin_name.to_string())).cloned()
    }

    pub fn store_temp_value(&mut self, node_id: usize, pin_name: &str, value: RuntimeValue) {
        self.temp_values.insert((node_id, pin_name.to_string()), value);
    }
    
    pub fn clear_temp_values(&mut self) {
        self.temp_values.clear();
    }

    // ==================== Function Frame Management ====================

    /// Push a new function call frame onto the stack
    pub fn push_function_frame(&mut self, function_id: usize, params: HashMap<String, RuntimeValue>) {
        let frame = FunctionFrame {
            function_id,
            local_vars: params,
            return_value: None,
            return_address: None,
        };
        self.function_stack.push(frame);
    }

    /// Pop the current function frame and return its return value
    pub fn pop_function_frame(&mut self) -> Option<RuntimeValue> {
        self.function_stack.pop().and_then(|frame| frame.return_value)
    }

    /// Get the current function frame (top of stack)
    pub fn current_function_frame(&self) -> Option<&FunctionFrame> {
        self.function_stack.last()
    }

    /// Get the current function frame mutably
    pub fn current_function_frame_mut(&mut self) -> Option<&mut FunctionFrame> {
        self.function_stack.last_mut()
    }

    /// Get a local variable from the current function frame
    pub fn get_local_var(&self, name: &str) -> Option<RuntimeValue> {
        self.current_function_frame()
            .and_then(|frame| frame.local_vars.get(name).cloned())
    }

    /// Set a local variable in the current function frame
    pub fn set_local_var(&mut self, name: String, value: RuntimeValue) -> Result<(), String> {
        if let Some(frame) = self.current_function_frame_mut() {
            frame.local_vars.insert(name, value);
            Ok(())
        } else {
            Err("No active function frame".to_string())
        }
    }

    /// Set the return value for the current function
    pub fn set_function_return_value(&mut self, value: RuntimeValue) -> Result<(), String> {
        if let Some(frame) = self.current_function_frame_mut() {
            frame.return_value = Some(value);
            Ok(())
        } else {
            Err("No active function frame".to_string())
        }
    }

    /// Check if we're currently inside a function call
    pub fn in_function_context(&self) -> bool {
        !self.function_stack.is_empty()
    }

    /// Get the current function ID (if in a function)
    pub fn current_function_id(&self) -> Option<usize> {
        self.current_function_frame().map(|f| f.function_id)
    }

    // ==================== Modal Management ====================

    /// Open a modal by form name
    pub fn open_modal(&mut self, form_name: &str) {
        if !self.open_modals.contains(&form_name.to_string()) {
            self.open_modals.push(form_name.to_string());
        }
    }

    /// Close a modal by form name
    pub fn close_modal(&mut self, form_name: &str) {
        self.open_modals.retain(|n| n != form_name);
    }

    /// Check if a modal is open
    pub fn is_modal_open(&self, form_name: &str) -> bool {
        self.open_modals.contains(&form_name.to_string())
    }

    /// Get all open modals
    pub fn get_open_modals(&self) -> &[String] {
        &self.open_modals
    }

    /// Close all modals
    pub fn close_all_modals(&mut self) {
        self.open_modals.clear();
    }

    // ==================== Table Data Management ====================

    /// Set data for a DataTable component from a JSON array or RuntimeValue array
    pub fn set_table_data(&mut self, component_name: &str, data: Vec<HashMap<String, String>>) {
        self.table_data.insert(component_name.to_string(), data);
    }

    /// Set table data from a RuntimeValue::Array
    pub fn set_table_data_from_array(&mut self, component_name: &str, array: &RuntimeValue) {
        let rows = match array {
            RuntimeValue::Array(arr) => {
                arr.iter().map(|item| {
                    match item {
                        RuntimeValue::Map(map) => {
                            map.iter().map(|(k, v)| (k.clone(), v.as_string())).collect()
                        }
                        RuntimeValue::String(s) => {
                            let mut row = HashMap::new();
                            row.insert("value".to_string(), s.clone());
                            row
                        }
                        other => {
                            let mut row = HashMap::new();
                            row.insert("value".to_string(), other.as_string());
                            row
                        }
                    }
                }).collect()
            }
            _ => Vec::new(),
        };
        self.table_data.insert(component_name.to_string(), rows);
    }

    /// Set table data from a JSON string
    pub fn set_table_data_from_json(&mut self, component_name: &str, json: &str) -> Result<(), String> {
        let value: serde_json::Value = serde_json::from_str(json)
            .map_err(|e| format!("JSON parse error: {}", e))?;

        let rows = match value {
            serde_json::Value::Array(arr) => {
                arr.iter().map(|item| {
                    match item {
                        serde_json::Value::Object(obj) => {
                            obj.iter().map(|(k, v)| {
                                let val_str = match v {
                                    serde_json::Value::String(s) => s.clone(),
                                    other => other.to_string(),
                                };
                                (k.clone(), val_str)
                            }).collect()
                        }
                        serde_json::Value::String(s) => {
                            let mut row = HashMap::new();
                            row.insert("value".to_string(), s.clone());
                            row
                        }
                        other => {
                            let mut row = HashMap::new();
                            row.insert("value".to_string(), other.to_string());
                            row
                        }
                    }
                }).collect()
            }
            _ => return Err("Expected JSON array".to_string()),
        };

        self.table_data.insert(component_name.to_string(), rows);
        Ok(())
    }

    /// Get table data for a component
    pub fn get_table_data(&self, component_name: &str) -> Option<&Vec<HashMap<String, String>>> {
        self.table_data.get(component_name)
    }

    /// Get all table data
    pub fn get_all_table_data(&self) -> &HashMap<String, Vec<HashMap<String, String>>> {
        &self.table_data
    }

    /// Clear table data for a component
    pub fn clear_table_data(&mut self, component_name: &str) {
        self.table_data.remove(component_name);
    }
}

impl ComponentContext for RuntimeContext {
    fn get_text(&self, name: &str) -> Option<String> {
        self.find_component(name).and_then(|c| {
            match &c.props {
                ComponentProps::Text(props) => Some(props.text.clone()),
                ComponentProps::Button(props) => Some(props.label.clone()),
                ComponentProps::InputText(props) => Some(props.buffer.clone()),
                ComponentProps::Checkbox(props) => Some(props.label.clone()),
                ComponentProps::Slider(props) => Some(props.label.clone()),
                ComponentProps::ColorPicker(props) => Some(props.label.clone()),
                ComponentProps::ComboBox(props) => Some(props.label.clone()),
                ComponentProps::RadioButton(props) => Some(props.label.clone()),
                ComponentProps::ListBox(props) => Some(props.label.clone()),
                _ => None,
            }
        })
    }

    fn set_text(&mut self, name: &str, text: String) -> bool {
        if let Some(c) = self.find_component_mut(name) {
            match &mut c.props {
                ComponentProps::Text(props) => {
                    props.text = text;
                    true
                }
                ComponentProps::Button(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::InputText(props) => {
                    props.buffer = text;
                    true
                }
                ComponentProps::Checkbox(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::Slider(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::ColorPicker(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::ComboBox(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::RadioButton(props) => {
                    props.label = text;
                    true
                }
                ComponentProps::ListBox(props) => {
                    props.label = text;
                    true
                }
                _ => false,
            }
        } else {
            false
        }
    }

    fn get_checked(&self, name: &str) -> Option<bool> {
        self.find_component(name).and_then(|c| {
            match &c.props {
                ComponentProps::Checkbox(props) => Some(props.checked),
                ComponentProps::RadioButton(props) => Some(props.selected),
                _ => None,
            }
        })
    }

    fn set_checked(&mut self, name: &str, checked: bool) -> bool {
        if let Some(c) = self.find_component_mut(name) {
            match &mut c.props {
                ComponentProps::Checkbox(props) => {
                    props.checked = checked;
                    true
                }
                ComponentProps::RadioButton(props) => {
                    props.selected = checked;
                    true
                }
                _ => false,
            }
        } else {
            false
        }
    }

    fn get_value(&self, name: &str) -> Option<f32> {
        self.find_component(name).and_then(|c| {
            match &c.props {
                ComponentProps::Slider(props) => Some(props.value),
                ComponentProps::ProgressBar(props) => Some(props.fraction),
                _ => None,
            }
        })
    }

    fn set_value(&mut self, name: &str, value: f32) -> bool {
        if let Some(c) = self.find_component_mut(name) {
            match &mut c.props {
                ComponentProps::Slider(props) => {
                    props.value = value.max(props.min).min(props.max);
                    true
                }
                ComponentProps::ProgressBar(props) => {
                    props.fraction = value.max(0.0).min(1.0);
                    true
                }
                _ => false,
            }
        } else {
            false
        }
    }

    fn get_color(&self, name: &str) -> Option<[f32; 4]> {
        self.find_component(name).and_then(|c| {
            match &c.props {
                ComponentProps::ColorPicker(props) => Some(props.color),
                ComponentProps::Text(props) => Some(props.color),
                _ => None,
            }
        })
    }

    fn set_color(&mut self, name: &str, color: [f32; 4]) -> bool {
        if let Some(c) = self.find_component_mut(name) {
            match &mut c.props {
                ComponentProps::ColorPicker(props) => {
                    props.color = color;
                    true
                }
                ComponentProps::Text(props) => {
                    props.color = color;
                    true
                }
                _ => false,
            }
        } else {
            false
        }
    }

    fn set_combobox_items(&mut self, name: &str, items: Vec<String>) -> Result<(), String> {
        if let Some(c) = self.find_component_mut(name) {
            match &mut c.props {
                ComponentProps::ComboBox(props) => {
                    props.items = items;
                    // Reset current_item if it's out of bounds
                    if props.current_item >= props.items.len() && !props.items.is_empty() {
                        props.current_item = 0;
                    }
                    Ok(())
                }
                _ => Err(format!("Component '{}' is not a ComboBox", name)),
            }
        } else {
            Err(format!("Component '{}' not found", name))
        }
    }

    fn get_combobox_value(&self, name: &str) -> Option<String> {
        self.find_component(name).and_then(|component| {
            match &component.props {
                ComponentProps::ComboBox(props) => {
                    if props.current_item < props.items.len() {
                        Some(props.items[props.current_item].clone())
                    } else {
                        None
                    }
                }
                _ => None,
            }
        })
    }

    fn show_message(&mut self, msg: &str) {
        self.message_queue.push(msg.to_string());
    }

    fn log(&mut self, msg: &str) {
        // Simple timestamp without chrono dependency
        let timestamp = format!("{:?}", std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap_or_default());
        let entry = LogEntry {
            timestamp: timestamp.clone(),
            message: msg.to_string(),
            source_component_id: self.current_component_id,
        };
        self.log_buffer.push(entry);
        
        // Cap log buffer size to prevent unbounded memory growth
        const MAX_LOG_ENTRIES: usize = 500;
        if self.log_buffer.len() > MAX_LOG_ENTRIES {
            self.log_buffer.drain(0..self.log_buffer.len() - MAX_LOG_ENTRIES);
        }
        
        println!("[GUI Builder] [{}] {}", timestamp, msg);
    }

    fn http_get(&mut self, url: &str, headers: &str) -> Result<(u16, String), String> {
        self.log(&format!("HTTP GET: {}", url));

        let mut request = ureq::get(url);

        // Parse headers JSON if provided
        if !headers.is_empty() {
            if let Ok(headers_map) = serde_json::from_str::<serde_json::Value>(headers) {
                if let Some(obj) = headers_map.as_object() {
                    for (key, value) in obj {
                        if let Some(val_str) = value.as_str() {
                            request = request.set(key, val_str);
                        }
                    }
                }
            }
        }

        match request.call() {
            Ok(response) => {
                let status = response.status();
                // Read response as bytes first
                let mut bytes = Vec::new();
                response.into_reader().read_to_end(&mut bytes).map_err(|e| e.to_string())?;
                
                // Try to convert to UTF-8 string, if it fails, return as base64
                match String::from_utf8(bytes.clone()) {
                    Ok(text) => Ok((status, text)),
                    Err(_) => {
                        // Binary data - encode as base64 with prefix
                        let encoded = BASE64.encode(&bytes);
                        Ok((status, format!("base64:{}", encoded)))
                    }
                }
            }
            Err(ureq::Error::Status(code, response)) => {
                let mut bytes = Vec::new();
                let _ = response.into_reader().read_to_end(&mut bytes);
                match String::from_utf8(bytes.clone()) {
                    Ok(text) => Ok((code, text)),
                    Err(_) => {
                        let encoded = BASE64.encode(&bytes);
                        Ok((code, format!("base64:{}", encoded)))
                    }
                }
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn http_post(&mut self, url: &str, headers: &str, body: &str) -> Result<(u16, String), String> {
        self.log(&format!("HTTP POST: {}", url));

        let mut request = ureq::post(url);

        // Parse headers JSON if provided
        if !headers.is_empty() {
            if let Ok(headers_map) = serde_json::from_str::<serde_json::Value>(headers) {
                if let Some(obj) = headers_map.as_object() {
                    for (key, value) in obj {
                        if let Some(val_str) = value.as_str() {
                            request = request.set(key, val_str);
                        }
                    }
                }
            }
        }

        match request.send_string(body) {
            Ok(response) => {
                let status = response.status();
                let resp_body = response.into_string().map_err(|e| e.to_string())?;
                Ok((status, resp_body))
            }
            Err(ureq::Error::Status(code, response)) => {
                let resp_body = response.into_string().unwrap_or_default();
                Ok((code, resp_body))
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn http_put(&mut self, url: &str, headers: &str, body: &str) -> Result<(u16, String), String> {
        self.log(&format!("HTTP PUT: {}", url));

        let mut request = ureq::put(url);

        // Parse headers JSON if provided
        if !headers.is_empty() {
            if let Ok(headers_map) = serde_json::from_str::<serde_json::Value>(headers) {
                if let Some(obj) = headers_map.as_object() {
                    for (key, value) in obj {
                        if let Some(val_str) = value.as_str() {
                            request = request.set(key, val_str);
                        }
                    }
                }
            }
        }

        match request.send_string(body) {
            Ok(response) => {
                let status = response.status();
                let resp_body = response.into_string().map_err(|e| e.to_string())?;
                Ok((status, resp_body))
            }
            Err(ureq::Error::Status(code, response)) => {
                let resp_body = response.into_string().unwrap_or_default();
                Ok((code, resp_body))
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn http_delete(&mut self, url: &str, headers: &str) -> Result<(u16, String), String> {
        self.log(&format!("HTTP DELETE: {}", url));

        let mut request = ureq::delete(url);

        // Parse headers JSON if provided
        if !headers.is_empty() {
            if let Ok(headers_map) = serde_json::from_str::<serde_json::Value>(headers) {
                if let Some(obj) = headers_map.as_object() {
                    for (key, value) in obj {
                        if let Some(val_str) = value.as_str() {
                            request = request.set(key, val_str);
                        }
                    }
                }
            }
        }

        match request.call() {
            Ok(response) => {
                let status = response.status();
                let body = response.into_string().map_err(|e| e.to_string())?;
                Ok((status, body))
            }
            Err(ureq::Error::Status(code, response)) => {
                let body = response.into_string().unwrap_or_default();
                Ok((code, body))
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn parse_json(&self, json: &str, path: &str) -> Result<String, String> {
        let value: serde_json::Value = serde_json::from_str(json)
            .map_err(|e| format!("JSON parse error: {}", e))?;

        // Simple path traversal (supports "key" or "key.subkey.subsubkey")
        let mut current = &value;
        for part in path.split('.') {
            current = current.get(part)
                .ok_or_else(|| format!("Path '{}' not found", path))?;
        }

        // Convert result to string
        match current {
            serde_json::Value::String(s) => Ok(s.clone()),
            other => Ok(other.to_string()),
        }
    }

    fn build_json(&self, pairs: &[(&str, &str)]) -> Result<String, String> {
        let mut map = serde_json::Map::new();
        for (key, value) in pairs {
            // Try to parse value as JSON, otherwise treat as string
            let json_value = serde_json::from_str::<serde_json::Value>(value)
                .unwrap_or_else(|_| serde_json::Value::String(value.to_string()));
            map.insert(key.to_string(), json_value);
        }
        serde_json::to_string(&map)
            .map_err(|e| format!("JSON build error: {}", e))
    }

    fn execute_query(&mut self, query: &str, _params: &str) -> Result<u64, String> {
        self.log(&format!("SQL Execute (Simulator): {}", query));
        Ok(0) // Return 0 rows affected in simulation
    }

    fn query_rows(&self, query: &str, _params: &str) -> Result<String, String> {
         // In simulation we can't really query unless we mock data.
         // Return empty array.
         Ok("[]".to_string())
    }
}
