#ifndef EDITSCENE_BUOYANCYSYSTEM_HPP
#define EDITSCENE_BUOYANCYSYSTEM_HPP
#pragma once

#include <flecs.h>
#include <Ogre.h>
#include <memory>
#include <unordered_map>
#include "../physics/physics.h"
#include "../components/BuoyancyInfo.hpp"
#include "../components/InWater.hpp"
#include "../components/WaterPhysics.hpp"
#include "../components/Transform.hpp"

/**
 * Buoyancy system for water physics
 * Applies buoyancy forces to entities submerged in water
 * Uses broadphase queries to detect submerged bodies
 *
 * The system handles all dynamic physics bodies (rigid bodies, characters, etc.)
 * by mapping JPH::BodyID to flecs::entity via scene node lookup.
 * If an entity has a BuoyancyInfo component, its settings are used.
 * Otherwise, default settings from WaterPhysics component are applied.
 */
class BuoyancySystem {
public:
	BuoyancySystem(flecs::world &world, JoltPhysicsWrapper *physics);
	~BuoyancySystem() = default;

	// Initialize buoyancy system
	void initialize();

	// Update buoyancy forces
	void update(float deltaTime);

	// Enable/disable buoyancy system
	void setEnabled(bool enabled)
	{
		m_enabled = enabled;
	}
	bool isEnabled() const
	{
		return m_enabled;
	}

	// Enable/disable debug mode
	void setDebugEnabled(bool enabled)
	{
		m_debugEnabled = enabled;
	}
	bool isDebugEnabled() const
	{
		return m_debugEnabled;
	}

	// Set camera position for water detection area
	void setCameraPosition(const Ogre::Vector3 &cameraPos)
	{
		m_cameraPosition = cameraPos;
	}

private:
	// Apply buoyancy to a specific body
	void applyBuoyancyToBody(JPH::BodyID bodyID, float deltaTime,
				 const BuoyancyInfo *buoyancyInfo,
				 const WaterPhysics *waterPhysics);

	// Check if a body is submerged based on its position
	bool isBodySubmerged(JPH::BodyID bodyID, float waterSurfaceY) const;

	// Find entity from scene node (cached lookup)
	flecs::entity findEntityFromSceneNode(Ogre::SceneNode *node);

	// Debug logging
	void debugLogWaterDetection(const Ogre::Vector3 &waterSurfacePos);

	flecs::world &m_world;
	JoltPhysicsWrapper *m_physics;

	// System enabled state
	bool m_enabled = true;

	// Debug mode
	bool m_debugEnabled = false;

	// Camera position for water detection area
	Ogre::Vector3 m_cameraPosition = Ogre::Vector3::ZERO;

	// Bodies currently in water (cached from broadphase query)
	std::set<JPH::BodyID> m_bodiesInWater;

	// Cache for scene node -> entity mapping
	std::unordered_map<Ogre::SceneNode *, flecs::entity_t> m_nodeToEntity;

	// Entities that were in water last frame (for InWater tag management)
	std::set<flecs::entity_t> m_entitiesInWater;

	// Query for entities with BuoyancyInfo component
	flecs::query<BuoyancyInfo> m_buoyancyInfoQuery;
};

#endif // EDITSCENE_BUOYANCYSYSTEM_HPP
