use super::super::framework::{NodeImpl, 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::{ComponentContext, RuntimeContext, RuntimeValue};

pub struct HttpPostNode;

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

        match ctx.http_post(&url, &headers, &body) {
            Ok((status, response)) => {
                 ctx.store_temp_value(node.id, "response", RuntimeValue::String(response));
                 ctx.store_temp_value(node.id, "status", RuntimeValue::Float(status as f32));

                 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) => {
                 ctx.log(&format!("HTTP POST Error: {}", e));
                 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 HttpPostNode {
    fn description(&self) -> &str {
        "Performs an HTTP POST request."
    }
}

fn default_params() -> NodeParams {
    NodeParams::HttpHeaders(String::new())
}

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::String, true, "url"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "headers"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::String, true, "body"));
    *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, false, "response"));
    *next_pin_id += 1;
    pins.push(Pin::new(*next_pin_id, PinType::Float, false, "status"));
    *next_pin_id += 1;
    pins
}

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

crate::register_node!(NodeSpec {
    id: "HttpPost",
    display_name: "HTTP POST",
    documentation: "Performs an HTTP POST request.",
    category: NodeCategory::Network,
    library: NodeLibrary::Http,
    param_kind: ParamKind::HttpHeaders,
    default_params,
    pins,
    execute: Some(exec),
    evaluate: None,
});
