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};
use crate::gui_builder::runtime::ComponentContext;

pub struct ExecuteQueryNode;

impl NodeImpl for ExecuteQueryNode {
    fn execute(&self, graph: &NodeGraph, ctx: &mut RuntimeContext, node: &Node) -> Result<Option<usize>, String> {
        // Try getting query from input pin first, then fallback to params
        let query = match eval_input_string(graph, ctx, node.id, "query") {
            Ok(s) if !s.is_empty() => s,
            _ => {
                // Check params
                match &node.params {
                    crate::gui_builder::nodes::NodeParams::SqlQuery(s) => s.clone(),
                    _ => String::new(), // Or fail?
                }
            }
        };

        let params = eval_input_string(graph, ctx, node.id, "params").unwrap_or_default();

        match ctx.execute_query(&query, &params) {
            Ok(rows_affected) => {
                 // ctx.store_temp_value ...
                 // Maybe store rows affected?
                 get_default_exec_out(node)
            }
            Err(e) => {
                 ctx.log(&format!("DB Error: {}", e));
                 Err(e)
            }
        }
    }
}

impl super::super::framework::NodeDescription for ExecuteQueryNode {
    fn description(&self) -> &str {
        "Executes a SQL query (INSERT, UPDATE, DELETE) that modifies the database."
    }
}

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, ""));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "query"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "params"));
    *next_pin_id += 1;
    pins
}

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

crate::register_node!(NodeSpec {
    id: "ExecuteQuery",
    display_name: "Execute Query",
    documentation: "Executes a SQL query (INSERT, UPDATE, DELETE) that modifies the database.",
    category: NodeCategory::Database,
    library: NodeLibrary::Sql,
    param_kind: ParamKind::None,
    default_params,
    pins,
    execute: Some(execute),
    evaluate: None,
});

crate::register_node!(NodeSpec {
    id: "SqlRawQuery",
    display_name: "SQL Raw Query",
    documentation: "Executes a SQL query (INSERT, UPDATE, DELETE) that modifies the database.",
    category: NodeCategory::Database,
    library: NodeLibrary::Sql,
    param_kind: ParamKind::None,
    default_params,
    pins,
    execute: Some(execute),
    evaluate: None,
});
