//
// Created by sebastian on 02.08.26.
//

#ifndef COLORRACE_PICKINGSYSTEM_H
#define COLORRACE_PICKINGSYSTEM_H
#include <optional>

#include "imgui.h"
#include "core/inputsOutputs/inputs/Mouse.h"
#include "core/inputsOutputs/inputs/MouseButton.h"
#include "ecs/EntityRegistry.h"
#include "ecs/standardComponents/PickableComponent.h"
#include "ecs/standardComponents/TransformComponent.h"
#define GLM_ENABLE_EXPERIMENTAL
#include <iostream>

#include "ecs/standardComponents/MeshComponent.h"

#include "renderer/entities/Camera.h"
#include "spdlog/spdlog.h"


namespace engine {
    class Mouse;

    class PickingSystem {
    public:
        explicit PickingSystem(Camera& camera) : m_camera(camera) {}

        std::optional<Entity> update(const Mouse& mouse, EntityRegistry& registry) {

            //if (ImGui::GetIO().WantCaptureMouse) return std::nullopt;
            if (!mouse.isClickEvent(MouseButton::LEFT)) return std::nullopt;
            auto [origin, dir] = screenToRay(mouse.getXY(/*ndc=*/true), m_camera);

            float closestT = std::numeric_limits<float>::max();
            std::optional<Entity> hit;

            for (const auto& [entity, pickable] : registry.getPool<PickableComponent>()) {
                const auto transform = registry.getComponent<TransformComponent>(entity);
                const auto mesh = registry.getComponent<MeshComponent>(entity);

                AABB transformedAABB = mesh.model->getAABB().transformed(transform.computeModelMatrix());
                Ray ray = Ray(origin, dir);
                std::optional<RayHit> ray_hit = transformedAABB.intersects(ray, closestT);
                if (ray_hit.has_value()) {
                    spdlog::info(std::format("Hit: {} {}", entity.value(), std::to_string(ray_hit.value().distance)));
                    closestT = ray_hit.value().distance;
                    hit = entity;
                }
            }

            return hit;
        }

        static std::pair<glm::vec3, glm::vec3> screenToRay(const glm::vec2& screenPos, const Camera& camera);

        static bool raySphereIntersect(const glm::vec3& origin, const glm::vec3& dir, const glm::vec3& center, float radius, float& t);
    private:
        Camera& m_camera;
    };
}


#endif //COLORRACE_PICKINGSYSTEM_H
