#include <iostream>
#include <Ogre.h>
#include <OgreFileSystemLayer.h>
#include <goap/goap.hpp>
#include "GameData.h"
#include "Components.h"
#include "LuaData.h"
#include "world-build.h"
struct Blackboard {
	enum {
		HIGH_LUST = 1,
		LOW_HEALTH = (1 << 1),
		HAS_TARGET = (1 << 2),
	};
	flecs::entity me;
	int health;
	int stamina;
	int lust;
	uint32_t flags;
	bool operator==(const Blackboard &other)
	{
		return flags != other.flags;
	}
};

struct CopulationGoal : goap::Goal<Blackboard> {
	int distance_to(const Blackboard &state) const override
	{
		if (state.flags & Blackboard::HIGH_LUST)
			return 1;
		else
			return 0;
	}
};

class BaseAction : public goap::Action<Blackboard> {
	std::string m_name;

public:
	BaseAction(const std::string &name)
		: goap::Action<Blackboard>()
		, m_name(name)
	{
	}
	BaseAction(const char *name)
		: goap::Action<Blackboard>()
		, m_name(name)
	{
	}
	const std::string &get_name() const
	{
		return m_name;
	}
	virtual bool can_run(const Blackboard &state) = 0;
	virtual void plan_effects(Blackboard &state) = 0;
	virtual bool execute(Blackboard &state) = 0;
};

class find_target : public BaseAction {
public:
	find_target(const std::string &name)
		: BaseAction(name)
	{
	}
	bool can_run(const Blackboard &state) override
	{
		bool can = !(state.flags & Blackboard::HAS_TARGET);
		std::cout << "find can run " << can << std::endl;
		return true;
	}
	void plan_effects(Blackboard &state) override
	{
		std::cout << "fuck: " << &state << " " << state.flags
			  << std::endl;
		//		std::cout << "find plan_effects\n";
		state.flags |= Blackboard::HAS_TARGET;
	}
	bool execute(Blackboard &state)
	{
		std::cout << "find_target" << std::endl;
		return false;
	}
};
class fuck_target : public BaseAction {
public:
	fuck_target(const std::string &name)
		: BaseAction(name)
	{
	}
	bool can_run(const Blackboard &state) override
	{
		std::cout << "fuck: " << &state << " " << state.flags
			  << std::endl;
		bool can = (state.flags & Blackboard::HAS_TARGET);
		std::cout << "fuck can run " << can << std::endl;
		return can;
	}
	void plan_effects(Blackboard &state) override
	{
		//		std::cout << "fuck plan_effects\n";
		state.lust = 0;
		state.flags &= ~Blackboard::HIGH_LUST;
	}
	bool execute(Blackboard &state)
	{
		std::cout << "fuck_target" << std::endl;
		return false;
	}
};
int main()
{
	//	new Ogre::LogManager;
	//	new Ogre::ArchiveManager;
	//	Ogre::FileSystemLayer fsLayer("Ogre3D");
	//	new Ogre::ResourceGroupManager;
	Ogre::Root *ogre = new Ogre::Root("", "");
	Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
		"Characters", true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"./characters", "FileSystem", "Characters", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"../characters", "FileSystem", "Characters", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"../../characters", "FileSystem", "Characters", true, true);

	Ogre::ResourceGroupManager::getSingleton().createResourceGroup(
		"LuaScripts", true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"./lua-scripts", "FileSystem", "LuaScripts", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"../lua-scripts", "FileSystem", "LuaScripts", true, true);
	Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
		"../../lua-scripts", "FileSystem", "LuaScripts", true, true);
	//	Ogre::ResourceGroupManager &mgr =
	//		Ogre::ResourceGroupManager::getSingleton();
	flecs::world ecs = ECS::get();
	ECS::setup_minimal();
	ecs.import <ECS::LuaModule>();
	ecs.import <ECS::GameWorldModule>();
	struct Male {};
	struct Female {};
	struct Position {
		Ogre::Vector2 position;
	};
	struct Target {
		flecs::entity target;
	};
	ecs.component<Blackboard>();
	ecs.component<Male>();
	ecs.component<Female>();
	ecs.component<Position>();
	ecs.component<Target>();
	ecs.set<ECS::EngineData>({ nullptr, 0.0f, 5.0f, 0, 0, false });

	flecs::entity e1 = ecs.entity("e1");
	e1.set<Blackboard>({ e1, 100, 100, 100, 0 });
	e1.add<Male>();
	e1.set<Position>({ { -100, -100 } });
	flecs::entity e2 = ecs.entity("e2");
	e2.set<Blackboard>({ e2, 100, 100, 100, 0 });
	e2.add<Female>();
	e2.set<Position>({ { 100, 100 } });

	std::vector<goap::Action<Blackboard> *> actions = {
		new find_target("find_target"), new fuck_target("fuck_target")
	};
	goap::Planner<Blackboard> planner;
	goap::Action<Blackboard> *path[100];
	CopulationGoal goal;
	bool stop_this = false;
	ecs.system<Blackboard>("UpdateCharacters")
		.kind(flecs::OnUpdate)
		.each([&](flecs::entity e, Blackboard &bb) {
			bb.flags = 0;
			bb.lust += 1;
			if (bb.health < 5)
				bb.flags |= Blackboard::LOW_HEALTH;
			if (bb.lust > 1)
				bb.flags |= Blackboard::HIGH_LUST;
		});
	ecs.system<Blackboard>("UpdateCharacters2")
		.kind(flecs::OnUpdate)
		.each([&](flecs::entity e, Blackboard &bb) {
			int i;
			int len = planner.plan(
				bb, goal,
				static_cast<goap::Action<Blackboard> **>(
					actions.data()),
				actions.size(), path, 100);
			std::cout << "plan length: " << len << std::endl;
			if (len > 0)
				stop_this = true;
			if (len < 0)
				stop_this = true;
			for (i = 0; i < len; i++)
				std::cout << i << " "
					  << static_cast<BaseAction *>(path[i])
						     ->get_name()
					  << std::endl;
			for (i = 0; i < len; i++) {
				if (!path[i]->execute(bb))
					break;
			}
		});

	while (true) {
#if 0
		if (ecs.get<ECS::LuaBase>().setup_called ||
		    ecs.get<ECS::LuaBase>().startup_called)
			break;
#endif
		ecs.progress(0.16f);
		if (stop_this)
			break;
	}

	return 0;
}
