#pragma once

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

namespace psemek::bt
{

	template <typename Tree, typename NodeFactoryFn>
	struct lazy_node;

	template <typename Time, typename Event, typename ... Args, typename NodeFactoryFn>
	struct lazy_node<tree<Time, Event, Args...>, NodeFactoryFn>
		: 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;

		lazy_node(NodeFactoryFn && node_factory)
			: node_factory_(node_factory)
		{}

		void start(Args ... args) override
		{
			try
			{
				child_ = node_factory_(args...);
				child_->start(args...);
			}
			catch (assertion_failed_exception const &)
			{
				child_ = nullptr;
			}
		}

		status update(Time dt, Args ... args) override
		{
			if (!child_)
				return finished{false};

			auto result = child_->update(dt, args...);
			if (std::holds_alternative<finished>(result))
				child_ = nullptr;
			return result;
		}

		bool event(Event const & event, Args ... args) override
		{
			return child_->event(event, args...);
		}

	private:
		NodeFactoryFn node_factory_;
		node_ptr<tree_type> child_;
	};

	template <typename Tree, typename NodeFactoryFn>
	node_ptr<Tree> lazy(NodeFactoryFn && node_factory)
	{
		return std::make_unique<lazy_node<Tree, NodeFactoryFn>>(std::move(node_factory));
	}

}
