#pragma once

#include <type_traits>

#include <psemek/bt/node.hpp>
#include <psemek/bt/assert.hpp>

namespace psemek::bt
{

	template <typename Tree, typename ActionFn>
	struct action_node;

	template <typename Time, typename Event, typename ... Args, typename ActionFn>
	struct action_node<tree<Time, Event, Args...>, ActionFn>
		: node<tree<Time, Event, Args...>>
	{
		using tree_type = tree<Time, Event, Args...>;
		using node_type = node<tree_type>;
		using typename node_type::finished;
		using typename node_type::status;

		static_assert(std::is_same_v<std::invoke_result_t<ActionFn, Time, Args...>, void>, "bt::action result type must be void");

		action_node(ActionFn && action_fn)
			: action_fn_(std::move(action_fn))
		{}

		status update(Time dt, Args ... args) override
		{
			try
			{
				action_fn_(dt, args...);
			}
			catch (assertion_failed_exception const &)
			{
				return finished{false};
			}

			return finished{true};
		}

	private:
		ActionFn action_fn_;
	};

	template <typename Tree, typename ActionFn>
	node_ptr<Tree> action(ActionFn && action_fn)
	{
		return std::make_unique<action_node<Tree, ActionFn>>(std::move(action_fn));
	}

}
