use super::super::framework::{EvalImpl, eval_input};
use crate::gui_builder::node_registry::{NodeSpec, ParamKind};
use crate::gui_builder::nodes::{Node, NodeCategory, NodeGraph, NodeLibrary, NodeParams, Pin, PinType};
use crate::gui_builder::runtime::{RuntimeContext, RuntimeValue};

pub struct ToStringNode;

impl EvalImpl for ToStringNode {
    fn evaluate(&self, graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node, _pin_id: usize) -> Result<RuntimeValue, String> {
        // Try all potential inputs
        // "float", "bool", "color"
        
        // This logic mirrors interpreter.rs which checks which input is connected.
        // But `eval_input` does connection check.
        
        let float_val = eval_input(graph, ctx, node.id, "float");
        if let Ok(val) = float_val {
            if !matches!(val, RuntimeValue::None) {
                 return Ok(RuntimeValue::String(val.as_string()));
            }
        }
        
        let bool_val = eval_input(graph, ctx, node.id, "bool");
        if let Ok(val) = bool_val {
            if !matches!(val, RuntimeValue::None) {
                 return Ok(RuntimeValue::String(val.as_string()));
            }
        }
        
        let color_val = eval_input(graph, ctx, node.id, "color");
        if let Ok(val) = color_val {
            if !matches!(val, RuntimeValue::None) {
                 return Ok(RuntimeValue::String(val.as_string()));
            }
        }
        
        Ok(RuntimeValue::String(String::new()))
    }
}

impl super::super::framework::NodeDescription for ToStringNode {
    fn description(&self) -> &str {
        "Converts any value to its string representation."
    }
}

fn default_params() -> NodeParams {
    NodeParams::None
}

fn pins(next_pin_id: &mut usize) -> Vec<Pin> {
    let mut pins = Vec::new();
    pins.push(Pin::new(*next_pin_id, PinType::String, false, "string"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Float, true, "float"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Bool, true, "bool"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Color, true, "color"));
    *next_pin_id += 1;
    pins
}

fn evaluate(graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node, pin_id: usize) -> Result<RuntimeValue, String> {
    ToStringNode.evaluate(graph, ctx, node, pin_id)
}

crate::register_node!(NodeSpec {
    id: "ToString",
    display_name: "To String",
    documentation: "Converts any value to its string representation.",
    category: NodeCategory::Data,
    library: NodeLibrary::Core,
    param_kind: ParamKind::None,
    default_params,
    pins,
    execute: None,
    evaluate: Some(evaluate),
});
