-- =============================================================================
-- Behavior Tree Lua API Examples
-- =============================================================================
-- This file demonstrates how to create custom behavior tree nodes using
-- Lua functions via the ecs.behavior_tree API, and how to use the
-- built-in C++ node types via ecs.behavior_tree.create_node().
--
-- The API allows you to:
--   1. Register Lua functions as behavior tree node handlers
--   2. Create behavior tree nodes (both Lua and built-in C++ types)
--   3. Return "success", "failure", or "running" to control tree flow
--   4. Pass parameters from the behavior tree editor to your Lua function
-- =============================================================================

-- =============================================================================
-- Registering Lua Node Handlers
-- =============================================================================
-- Use ecs.behavior_tree.register_node(name, function) to register a Lua
-- function as a behavior tree node handler.
--
-- The function receives two arguments:
--   entity_id  - The entity ID executing this behavior tree node
--   params     - A table of parameters parsed from the node's params string
--
-- The function must return one of:
--   "success"  - Node completed successfully (tree continues)
--   "failure"  - Node failed (tree stops with failure)
--   "running"  - Node is still running (will be called again next frame)
-- =============================================================================

-- =============================================================================
-- Example 1: Simple greeting node
-- =============================================================================
-- Prints a message and succeeds immediately.

ecs.behavior_tree.register_node("say_hello", function(entity_id, params)
    local message = params.message or "Hello!"
    print("Entity " .. entity_id .. " says: " .. message)
    return "success"
end)

-- =============================================================================
-- Example 2: Node that checks a blackboard value
-- =============================================================================
-- Checks if a blackboard integer value meets a minimum threshold.
-- Succeeds if value >= min, fails otherwise.

ecs.behavior_tree.register_node("check_blackboard_value", function(entity_id, params)
    local key = params.key
    local min_val = tonumber(params.min) or 0

    if not key then
        return "failure"
    end

    local bb = ecs.get_component(entity_id, "GoapBlackboard")
    if not bb then
        return "failure"
    end

    local value = bb.values[key]
    if value == nil then
        return "failure"
    end

    if value >= min_val then
        return "success"
    else
        return "failure"
    end
end)

-- =============================================================================
-- Example 3: Node that runs over multiple frames (running state)
-- =============================================================================
-- Waits for a specified duration, storing progress in the blackboard's
-- floatValues. Returns "running" each frame until the duration elapses.

ecs.behavior_tree.register_node("wait_for_duration", function(entity_id, params)
    local duration = tonumber(params.duration) or 1.0
    local timer_key = params.timer_key or "wait_timer"

    local bb = ecs.get_component(entity_id, "GoapBlackboard")
    if not bb then
        return "failure"
    end

    local elapsed = bb.floatValues[timer_key] or 0.0
    local dt = ecs.get_delta_time() or 0.016

    elapsed = elapsed + dt
    bb.floatValues[timer_key] = elapsed
    ecs.set_component(entity_id, "GoapBlackboard", bb)

    if elapsed >= duration then
        bb.floatValues[timer_key] = nil
        ecs.set_component(entity_id, "GoapBlackboard", bb)
        return "success"
    end

    return "running"
end)

-- =============================================================================
-- Example 4: Node that modifies blackboard values
-- =============================================================================
-- Adds a configurable amount to a blackboard integer value.

ecs.behavior_tree.register_node("add_blackboard_value", function(entity_id, params)
    local key = params.key
    local amount = tonumber(params.amount) or 1

    if not key then
        return "failure"
    end

    local bb = ecs.get_component(entity_id, "GoapBlackboard")
    if not bb then
        return "failure"
    end

    bb.values[key] = (bb.values[key] or 0) + amount
    ecs.set_component(entity_id, "GoapBlackboard", bb)
    return "success"
end)

-- =============================================================================
-- Example 5: Node that sets a blackboard bit
-- =============================================================================
-- Sets or clears a named bit in the blackboard.

ecs.behavior_tree.register_node("set_blackboard_bit", function(entity_id, params)
    local bit_name = params.bit
    local value = params.value == "1" or params.value == "true"

    if not bit_name then
        return "failure"
    end

    local bb = ecs.get_component(entity_id, "GoapBlackboard")
    if not bb then
        return "failure"
    end

    bb.bits[bit_name] = value
    ecs.set_component(entity_id, "GoapBlackboard", bb)
    return "success"
end)

-- =============================================================================
-- Example 6: Node that checks a blackboard bit
-- =============================================================================
-- Checks if a named bit is set to a specific value.

ecs.behavior_tree.register_node("check_blackboard_bit", function(entity_id, params)
    local bit_name = params.bit
    local expected = params.value ~= "0" and params.value ~= "false"

    if not bit_name then
        return "failure"
    end

    local bb = ecs.get_component(entity_id, "GoapBlackboard")
    if not bb then
        return "failure"
    end

    local actual = bb.bits[bit_name] == true
    if actual == expected then
        return "success"
    else
        return "failure"
    end
end)

-- =============================================================================
-- Example 7: Random chance node
-- =============================================================================
-- Succeeds with a configurable probability (0.0 to 1.0).

ecs.behavior_tree.register_node("random_chance", function(entity_id, params)
    local probability = tonumber(params.probability) or 0.5
    local roll = math.random()
    if roll < probability then
        return "success"
    else
        return "failure"
    end
end)

-- =============================================================================
-- Using Built-in Node Types via create_node()
-- =============================================================================
-- ecs.behavior_tree.create_node(type, name, params) creates a node table
-- for any built-in C++ node type. If the first argument matches a registered
-- Lua handler name, it creates a luaTask node instead.
--
-- Built-in node types:
--   Control:     sequence, selector, invert
--   Animation:   setAnimationState, isAnimationEnded
--   Blackboard:  setBit, checkBit, setValue, checkValue, blackboardDump
--   Timing:      delay
--   Movement:    teleportToChild
--   Physics:     disablePhysics, enablePhysics
--   Events:      sendEvent
--   Inventory:   hasItem, hasItemByName, countItem, pickupItem, dropItem,
--                useItem, addItemToInventory
--   Debug:       debugPrint
--   Lua:         luaTask (auto-detected when name matches a registered handler)
-- =============================================================================

-- =============================================================================
-- Example 8: Action using built-in animation nodes
-- =============================================================================
-- Uses setAnimationState and isAnimationEnded to play an animation and
-- wait for it to finish.

ecs.action_db.add_action("play_walk_animation", 1,
    {},  -- preconditions
    {},  -- effects
    {    -- behavior tree
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("setAnimationState", "locomotion/walk"),
            ecs.behavior_tree.create_node("isAnimationEnded", "locomotion"),
            ecs.behavior_tree.create_node("setAnimationState", "locomotion/idle")
        }
    }
)

-- =============================================================================
-- Example 9: Action using built-in delay node
-- =============================================================================
-- Waits for a specified duration using the built-in delay node.

ecs.action_db.add_action("wait_and_greet", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("delay", "", "2.0"),
            ecs.behavior_tree.create_node("say_hello", "message=Waited 2 seconds!")
        }
    }
)

-- =============================================================================
-- Example 10: Action using built-in blackboard nodes
-- =============================================================================
-- Sets a blackboard bit, checks it, and sets a value.

ecs.action_db.add_action("blackboard_demo", 1,
    {},
    {
        bits = { has_sword = true },
        values = { gold = 100 }
    },
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("setBit", "has_sword", "1"),
            ecs.behavior_tree.create_node("checkBit", "has_sword"),
            ecs.behavior_tree.create_node("setValue", "gold", "100"),
            ecs.behavior_tree.create_node("checkValue", "gold", ">= 50"),
            ecs.behavior_tree.create_node("blackboardDump", "After setup")
        }
    }
)

-- =============================================================================
-- Example 11: Action using built-in sendEvent node
-- =============================================================================
-- Sends an event with parameters.

ecs.action_db.add_action("trigger_quest_event", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("sendEvent", "quest_started",
                "quest_id=the_ancient_sword,quest_giver=elder"),
            ecs.behavior_tree.create_node("debugPrint", "Quest event sent")
        }
    }
)

-- =============================================================================
-- Example 12: Action using built-in physics nodes
-- =============================================================================
-- Disables physics, waits, then re-enables.

ecs.action_db.add_action("physics_control", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("disablePhysics"),
            ecs.behavior_tree.create_node("delay", "", "1.0"),
            ecs.behavior_tree.create_node("enablePhysics")
        }
    }
)

-- =============================================================================
-- Example 13: Action using built-in inventory nodes
-- =============================================================================
-- Adds an item to inventory, checks for it, uses it, then drops it.

ecs.action_db.add_action("inventory_demo", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("addItemToInventory", "potion_01",
                "Health Potion,misc,1,0.5,10"),
            ecs.behavior_tree.create_node("hasItem", "potion_01"),
            ecs.behavior_tree.create_node("countItem", "potion_01", "1"),
            ecs.behavior_tree.create_node("useItem", "potion_01"),
            ecs.behavior_tree.create_node("dropItem", "potion_01", "1")
        }
    }
)

-- =============================================================================
-- Example 14: Action using built-in teleport node
-- =============================================================================
-- Teleports the entity to a named child transform.

ecs.action_db.add_action("teleport_to_entrance", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("teleportToChild", "entrance"),
            ecs.behavior_tree.create_node("debugPrint", "Teleported to entrance")
        }
    }
)

-- =============================================================================
-- Example 15: Complex action mixing Lua and built-in nodes
-- =============================================================================
-- A selector that first tries to use a sword, and if not available,
-- picks one up and equips it.

ecs.action_db.add_action("equip_sword", 2,
    {},
    {
        bits = { has_sword = true }
    },
    {
        type = "selector",
        children = {
            -- Try to use existing sword
            {
                type = "sequence",
                children = {
                    ecs.behavior_tree.create_node("checkBit", "has_sword"),
                    ecs.behavior_tree.create_node("debugPrint", "Already have a sword")
                }
            },
            -- Pick up and equip a sword
            {
                type = "sequence",
                children = {
                    ecs.behavior_tree.create_node("setAnimationState", "locomotion/walk"),
                    ecs.behavior_tree.create_node("delay", "", "3.0"),
                    ecs.behavior_tree.create_node("addItemToInventory", "sword_01",
                        "Iron Sword,weapon,1,2.5,50"),
                    ecs.behavior_tree.create_node("setBit", "has_sword", "1"),
                    ecs.behavior_tree.create_node("setAnimationState", "locomotion/idle"),
                    ecs.behavior_tree.create_node("debugPrint", "Picked up the sword!")
                }
            }
        }
    }
)

-- =============================================================================
-- Example 16: Action with conditional logic using Lua nodes
-- =============================================================================
-- Uses Lua-registered nodes for blackboard checks and modifications.

ecs.action_db.add_action("gain_experience", 2,
    {
        values = { experience = 0 }
    },
    {
        values = { experience = 15 }
    },
    {
        type = "selector",
        children = {
            {
                type = "sequence",
                children = {
                    ecs.behavior_tree.create_node("check_blackboard_value",
                        "key=experience,min=50"),
                    ecs.behavior_tree.create_node("say_hello",
                        "message=You are experienced!"),
                    ecs.behavior_tree.create_node("add_blackboard_value",
                        "key=experience,amount=10")
                }
            },
            {
                type = "sequence",
                children = {
                    ecs.behavior_tree.create_node("say_hello",
                        "message=You are still learning..."),
                    ecs.behavior_tree.create_node("add_blackboard_value",
                        "key=experience,amount=5")
                }
            }
        }
    }
)

-- =============================================================================
-- Example 17: Action with random outcomes
-- =============================================================================
-- Uses the Lua random_chance node for probabilistic behavior.

ecs.action_db.add_action("try_gamble", 3,
    {},
    {
        values = { gold = 10 }
    },
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("random_chance", "probability=0.3"),
            ecs.behavior_tree.create_node("say_hello", "message=You won the gamble!"),
            ecs.behavior_tree.create_node("add_blackboard_value", "key=gold,amount=10")
        }
    }
)

-- =============================================================================
-- Example 18: Action with running-state Lua node
-- =============================================================================
-- Uses the wait_for_duration Lua node which returns "running" each frame.

ecs.action_db.add_action("wait_and_continue", 1,
    {},
    {},
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("wait_for_duration",
                "duration=2.5,timer_key=my_timer"),
            ecs.behavior_tree.create_node("say_hello", "message=Done waiting!")
        }
    }
)

-- =============================================================================
-- Example 19: Action with blackboard bit operations via Lua nodes
-- =============================================================================

ecs.action_db.add_action("toggle_flag", 1,
    {},
    {
        bits = { quest_complete = true }
    },
    {
        type = "sequence",
        children = {
            ecs.behavior_tree.create_node("set_blackboard_bit",
                "bit=quest_complete,value=1"),
            ecs.behavior_tree.create_node("check_blackboard_bit",
                "bit=quest_complete,value=1"),
            ecs.behavior_tree.create_node("debugPrint", "Quest flag set and verified")
        }
    }
)

-- =============================================================================
-- Managing Registered Nodes
-- =============================================================================

-- List all registered node handlers:
local nodes = ecs.behavior_tree.list_nodes()
print("Registered behavior tree nodes:")
for i, name in ipairs(nodes) do
    print("  " .. i .. ". " .. name)
end

-- Unregister a node handler:
-- local removed = ecs.behavior_tree.unregister_node("say_hello")
-- if removed then
--     print("Unregistered node: say_hello")
-- end

-- =============================================================================
-- Parameter Format Reference
-- =============================================================================
--
-- The params string passed to create_node() supports:
--
--   Integer:    "count=42"          -> params.count = 42 (number)
--   Float:      "speed=3.5"         -> params.speed = 3.5 (number)
--   String:     "msg=hello"         -> params.msg = "hello" (string)
--   Quoted:     'msg="hello world"' -> params.msg = "hello world" (string)
--   Multiple:   "key=val,count=5"   -> params.key = "val", params.count = 5
--   Empty:      ""                  -> params = {} (empty table)
--
-- The params table is passed as the second argument to your registered
-- Lua function handler.
-- =============================================================================
