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

pub struct MathOpNode;

impl EvalImpl for MathOpNode {
    fn evaluate(&self, graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node, _pin_id: usize) -> Result<RuntimeValue, String> {
        let a = eval_input(graph, ctx, node.id, "a")?.as_float();
        let b = eval_input(graph, ctx, node.id, "b")?.as_float();
        
        let op = match &node.params {
            NodeParams::MathOperation(op) => op,
            _ => &MathOp::Add,
        };
        
        let result = match op {
            MathOp::Add => a + b,
            MathOp::Subtract => a - b,
            MathOp::Multiply => a * b,
            MathOp::Divide => if b != 0.0 { a / b } else { 0.0 }, // Handle div zero?
            MathOp::LessThan => if a < b { 1.0 } else { 0.0 }, // MathOp usually returns float in this system? Or Bool?
            // Re-checking interpreter.rs logic for MathOp...
            // It seems MathOp in this system creates Numbers (Floats).
            // But LessThan/GreaterThan implies boolean.
            // If the output pin is float, then 1.0/0.0. If boolean, then Bool.
            // Let's assume Float for now as per common visual scripting, or check pin type.
            MathOp::GreaterThan => if a > b { 1.0 } else { 0.0 },
            MathOp::Equals => if (a - b).abs() < std::f32::EPSILON { 1.0 } else { 0.0 },
        };
        
        // Return based on operation type?
        // Actually, if it's comparison, maybe it should verify the output pin type.
        // But for simplicity/compat with interpreter.rs which seemed to treat them as values.
        Ok(RuntimeValue::Float(result))
    }
}

impl super::super::framework::NodeDescription for MathOpNode {
    fn description(&self) -> &str {
        "Performs basic mathematical or logical operations (Add, Subtract, Less Than, etc.)."
    }
}

fn default_params() -> NodeParams {
    NodeParams::MathOperation(MathOp::Add)
}

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

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

crate::register_node!(NodeSpec {
    id: "MathOp",
    display_name: "Math",
    documentation: "Performs basic mathematical or logical operations (Add, Subtract, Less Than, etc.).",
    category: NodeCategory::Data,
    library: NodeLibrary::Core,
    param_kind: ParamKind::MathOperation,
    default_params,
    pins,
    execute: None,
    evaluate: Some(evaluate),
});
