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

pub struct ExpandEnvVarsNode;

fn expand_env_vars(path: &str) -> String {
    let mut result = path.to_string();
    while let Some(start) = result.find('%') {
        if let Some(end) = result[start + 1..].find('%') {
            let var_name = &result[start + 1..start + 1 + end];
            let replacement = std::env::var(var_name).unwrap_or_default();
            result = format!(
                "{}{}{}",
                &result[..start],
                replacement,
                &result[start + 2 + end..]
            );
        } else {
            break;
        }
    }
    result
}

impl EvalImpl for ExpandEnvVarsNode {
    fn evaluate(
        &self,
        graph: &NodeGraph,
        ctx: &mut RuntimeContext,
        node: &Node,
        _pin_id: usize,
    ) -> Result<RuntimeValue, String> {
        let input = eval_input(graph, ctx, node.id, "in")?;
        if matches!(input, RuntimeValue::None) {
            return Ok(RuntimeValue::String(String::new()));
        }
        Ok(RuntimeValue::String(expand_env_vars(&input.as_string())))
    }
}

impl super::super::framework::NodeDescription for ExpandEnvVarsNode {
    fn description(&self) -> &str {
        "Expands Windows-style environment variables in a string (e.g. %LOCALAPPDATA%)."
    }
}

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

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

crate::register_node!(NodeSpec {
    id: "ExpandEnvVars",
    display_name: "Expand Env Vars",
    documentation: "Expands Windows-style environment variables in a string (e.g. %LOCALAPPDATA%).",
    category: NodeCategory::Data,
    library: NodeLibrary::Core,
    param_kind: ParamKind::None,
    default_params,
    pins,
    execute: None,
    evaluate: Some(evaluate),
});
