#include "LightSystem.hpp"
#include "../components/Light.hpp"
#include "../components/Transform.hpp"
#include <OgreLogManager.h>

EditorLightSystem::EditorLightSystem(flecs::world& world, Ogre::SceneManager* sceneMgr)
	: m_world(world)
	, m_sceneMgr(sceneMgr)
	, m_lightQuery(world.query<LightComponent, TransformComponent>())
{
}

EditorLightSystem::~EditorLightSystem() = default;

void EditorLightSystem::update()
{
	m_lightQuery.each([&](flecs::entity entity, LightComponent& light, TransformComponent& transform) {
		if (light.needsRebuild || !light.light) {
			updateLight(entity, light, transform);
		}
	});
}

void EditorLightSystem::processAllLights()
{
	m_lightQuery.each([&](flecs::entity entity, LightComponent& light, TransformComponent& transform) {
		updateLight(entity, light, transform);
	});
}

void EditorLightSystem::updateLight(flecs::entity entity, LightComponent& light, 
                                    TransformComponent& transform)
{
	// Remove existing light if any
	if (light.light) {
		removeLight(light);
	}

	// Need a valid scene node to attach the light
	if (!transform.node) {
		Ogre::LogManager::getSingleton().logMessage(
			"LightSystem: Cannot create light - entity has no SceneNode");
		return;
	}

	// Create unique name for the light
	std::string lightName = "Light_" + std::to_string(entity.id());

	// Create the Ogre light
	light.light = m_sceneMgr->createLight(lightName);
	
	// Attach to the entity's scene node
	transform.node->attachObject(light.light);

	// Set light type
	switch (light.lightType) {
		case LightComponent::LightType::Point:
			light.light->setType(Ogre::Light::LT_POINT);
			break;
		case LightComponent::LightType::Directional:
			light.light->setType(Ogre::Light::LT_DIRECTIONAL);
			break;
		case LightComponent::LightType::Spotlight:
			light.light->setType(Ogre::Light::LT_SPOTLIGHT);
			break;
	}

	// Set colors (apply intensity)
	light.light->setDiffuseColour(light.diffuseColor * light.intensity);
	light.light->setSpecularColour(light.specularColor * light.intensity);

	// Set attenuation for point/spot lights
	if (light.lightType == LightComponent::LightType::Point ||
	    light.lightType == LightComponent::LightType::Spotlight) {
		light.light->setAttenuation(light.range,
		                            light.constantAttenuation,
		                            light.linearAttenuation,
		                            light.quadraticAttenuation);
	}

	// Set direction for directional/spot lights by rotating the node
	if (light.lightType == LightComponent::LightType::Directional ||
	    light.lightType == LightComponent::LightType::Spotlight) {
		// Convert direction to orientation - the light's default direction is typically (0,0,-1) or (0,-1,0)
		// We need to orient the node to point in the desired direction
		Ogre::Vector3 defaultDir(0, -1, 0); // Ogre lights typically point down by default
		Ogre::Quaternion rot = defaultDir.getRotationTo(light.direction);
		transform.node->setOrientation(rot);
	}

	// Set spotlight parameters
	if (light.lightType == LightComponent::LightType::Spotlight) {
		light.light->setSpotlightRange(
			Ogre::Degree(light.spotlightInnerAngle),
			Ogre::Degree(light.spotlightOuterAngle),
			light.spotlightFalloff);
	}

	// Set shadow casting
	light.light->setCastShadows(light.castShadows);

	light.needsRebuild = false;
	
	Ogre::LogManager::getSingleton().logMessage(
		"LightSystem: Created " + 
		std::string(light.lightType == LightComponent::LightType::Point ? "point" :
		            light.lightType == LightComponent::LightType::Directional ? "directional" : "spot") +
		" light '" + lightName + "'");
}

void EditorLightSystem::removeLight(LightComponent& light)
{
	if (light.light) {
		// Detach from parent node first
		Ogre::SceneNode* parent = light.light->getParentSceneNode();
		if (parent) {
			parent->detachObject(light.light);
		}
		
		m_sceneMgr->destroyLight(light.light);
		light.light = nullptr;
	}
}
