use super::super::framework::{NodeImpl, get_default_exec_out, eval_input_string};
use crate::gui_builder::node_registry::{NodeSpec, ParamKind};
use crate::gui_builder::nodes::{Node, NodeCategory, NodeGraph, NodeLibrary, NodeParams, Pin, PinType};
use crate::gui_builder::interpreter::ExecutionStack;
use crate::gui_builder::runtime::{RuntimeContext, RuntimeValue};

pub struct FileReadNode;

impl NodeImpl for FileReadNode {
    fn execute(&self, graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node) -> Result<Option<usize>, String> {
        let path = eval_input_string(graph, ctx, node.id, "path")?;

        match std::fs::read_to_string(&path) {
            Ok(content) => {
                // Store content for output pin
                ctx.store_temp_value(node.id, "content", RuntimeValue::String(content));
                ctx.store_temp_value(node.id, "error_msg", RuntimeValue::String(String::new()));

                // Return 'success' pin
                let pin_id = node.pins.iter()
                    .find(|p| !p.is_input && p.name == "success" && p.pin_type == PinType::Exec)
                    .map(|p| p.id);
                Ok(pin_id)
            }
            Err(e) => {
                // Store error
                ctx.store_temp_value(node.id, "content", RuntimeValue::String(String::new()));
                ctx.store_temp_value(node.id, "error_msg", RuntimeValue::String(e.to_string()));

                // Return 'error' pin
                let pin_id = node.pins.iter()
                    .find(|p| !p.is_input && p.name == "error" && p.pin_type == PinType::Exec)
                    .map(|p| p.id);
                Ok(pin_id)
            }
        }
    }
}

impl super::super::framework::NodeDescription for FileReadNode {
    fn description(&self) -> &str {
        "Reads the contents of a file."
    }
}

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::Exec, true, ""));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Exec, false, "success"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Exec, false, "error"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "path"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, false, "content"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, false, "error_msg"));
    *next_pin_id += 1;
    pins
}

fn execute(graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node, _stack: &mut ExecutionStack) -> Result<Option<usize>, String> {
    FileReadNode.execute(graph, ctx, node)
}

crate::register_node!(NodeSpec {
    id: "FileRead",
    display_name: "File Read",
    documentation: "Reads the contents of a file.",
    category: NodeCategory::FileSystem,
    library: NodeLibrary::FileSystem,
    param_kind: ParamKind::None,
    default_params,
    pins,
    execute: Some(execute),
    evaluate: None,
});
