#ifndef EDITSCENE_HAIRPHYSICSSYSTEM_HPP
#define EDITSCENE_HAIRPHYSICSSYSTEM_HPP
#pragma once

#include <flecs.h>
#include <Ogre.h>
#include <unordered_map>
#include <vector>

#include "../physics/physics.h"

#include <Jolt/Physics/Ragdoll/Ragdoll.h>
#include <Jolt/Skeleton/Skeleton.h>

class CharacterSlotSystem;

/**
 * System that creates and updates Jolt Physics ragdolls for hair parts
 * with their own skeleton. Replaces the previous animation-tree-based
 * hair animation.
 */
class HairPhysicsSystem {
public:
	HairPhysicsSystem(flecs::world &world, Ogre::SceneManager *sceneMgr,
			   JoltPhysicsWrapper *physics,
			   CharacterSlotSystem *slotSystem);
	~HairPhysicsSystem();

	void initialize();

	/** Call before physics step to sync root bodies to head transforms. */
	void prePhysicsUpdate();

	/** Call after physics step to read poses back to Ogre skeletons. */
	void postPhysicsUpdate();

private:
	struct HairRagdollState {
		JPH::Ref<JPH::Ragdoll> ragdoll;
		flecs::entity_t entityId = 0;
		Ogre::Entity *hairEntity = nullptr;
		Ogre::Entity *masterEntity = nullptr;
		Ogre::String slotName;
		std::vector<Ogre::String> boneNames;
		std::vector<int> parentIndices;
		Ogre::Matrix4 rootBindTransform = Ogre::Matrix4::IDENTITY;
	};

	void createRagdoll(flecs::entity e, const Ogre::String &slot,
			   Ogre::Entity *hairEnt, Ogre::Entity *masterEnt);
	void destroyRagdoll(HairRagdollState &state);
	void syncRootToHead(HairRagdollState &state);
	void syncPhysicsToSkeleton(HairRagdollState &state);
	bool isStateValid(const HairRagdollState &state) const;

	/* Helpers */
	JPH::Mat44 ogreMatrixToJolt(const Ogre::Matrix4 &m) const;
	Ogre::Matrix4 joltMatrixToOgre(const JPH::Mat44 &m) const;

	flecs::world &m_world;
	Ogre::SceneManager *m_sceneMgr;
	JoltPhysicsWrapper *m_physics;
	CharacterSlotSystem *m_slotSystem;
	bool m_initialized = false;

	/* Per-entity per-slot ragdoll states */
	std::unordered_map<
		flecs::entity_t,
		std::unordered_map<Ogre::String, HairRagdollState> >
		m_states;

	static uint32_t s_nextCollisionGroup;
};

#endif // EDITSCENE_HAIRPHYSICSSYSTEM_HPP
