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 StringFormatNode;

impl EvalImpl for StringFormatNode {
    fn evaluate(&self, graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node, _pin_id: usize) -> Result<RuntimeValue, String> {
        let format_str = match &node.params {
            NodeParams::FormatString(s) => s,
            _ => return Err("Missing format string".to_string()),
        };

        // Simplified placeholder replacement like "{0}", "{1}" etc.
        // Assuming inputs are named "arg0", "arg1" or just relying on order?
        // Looking at nodes.rs creation logic for StringFormat...
        // Usually pins are generated dynamically or fixed.
        // Let's assume standard named inputs for now or check connected inputs.
        
        // This is a complex node to implement fully modularly without knowing exact pin layout.
        // The original interpreter might have logic for this.
        // Original interpreter:
        // node.node_type.as_str() == "StringFormat" => {
        //     let format_str = ...
        //     let mut result = format_str.clone();
        //     for (i, arg_pin) in input_pins.enumerate() {
        //          let val = eval_input...
        //          result = result.replace(&format!("{{{}}}", i), &val.to_string());
        //     }
        //     Ok(RuntimeValue::String(result))
        // }
        
        let mut result = format_str.clone();
        
        // Iterate over dynamic inputs
        // Assuming input pins are named "0", "1", "2" etc. or we just iterate executing inputs.
        // Let's iterate over pins that are inputs.
        
        let mut input_pins: Vec<_> = node
            .pins
            .iter()
            .filter(|p| p.is_input && !matches!(p.pin_type, PinType::Exec))
            .collect();

        // Keep arg ordering stable (arg0, arg1, ...), fallback to pin id.
        input_pins.sort_by_key(|p| {
            if let Some(rest) = p.name.strip_prefix("arg") {
                rest.parse::<usize>().unwrap_or(usize::MAX)
            } else {
                usize::MAX
            }
        });
            
        for (i, pin) in input_pins.iter().enumerate() {
            // Evaluates connection to this pin
           let connection = graph.connections.iter().find(|c| c.to_node == node.id && c.to_pin == pin.id);
           if let Some(conn) = connection {
               let val = crate::gui_builder::interpreter::eval_node_output(graph, ctx, conn.from_node, conn.from_pin)?;
               let replacement = val.as_string();

               // Support both "{}" (sequential) and "{0}" (indexed) styles.
               // Prefer consuming the next "{}" placeholder first.
               if let Some(pos) = result.find("{}") {
                   result.replace_range(pos..pos + 2, &replacement);
               } else {
                   result = result.replace(&format!("{{{}}}", i), &replacement);
               }
           }
        }
        
        Ok(RuntimeValue::String(result))
    }
}

impl super::super::framework::NodeDescription for StringFormatNode {
    fn description(&self) -> &str {
        "Formats a string by replacing placeholders {} with input values."
    }
}

fn default_params() -> NodeParams {
    NodeParams::FormatString("{}".to_string())
}

fn pins(next_pin_id: &mut usize) -> Vec<Pin> {
    let mut pins = Vec::new();
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "arg"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, false, "result"));
    *next_pin_id += 1;
    pins
}

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

crate::register_node!(NodeSpec {
    id: "StringFormat",
    display_name: "Format String",
    documentation: "Formats a string by replacing placeholders {} with input values.",
    category: NodeCategory::Data,
    library: NodeLibrary::Core,
    param_kind: ParamKind::StringFormat,
    default_params,
    pins,
    execute: None,
    evaluate: Some(evaluate),
});
