#pragma once

#include "core/graphics/framebuffer.h"
#include "core/shader.h"
#include "input/input.h"
#include "scene/gltf_loader.h"

#include <entt/entt.hpp>
#include <flecs.h>
#include <glm/glm.hpp>
#include <memory>

class Camera;
class WindowDeprecated;

namespace FeverCore {

class Application
{
public:
    Application();

    virtual ~Application();
    Application(Application const&) = delete;
    Application(Application&&) = delete;
    auto operator=(Application const&) -> Application& = delete;
    auto operator=(Application&&) -> Application& = delete;

    auto registry() -> entt::registry& { return entt_registry; }
    auto registry() const -> entt::registry const& { return entt_registry; }

    auto world() -> flecs::world& { return _world; }
    auto world() const -> flecs::world const& { return _world; }

    void run();

    virtual void update() = 0;

protected:
    virtual void register_context_variables();
    void recreate_framebuffer();

    std::shared_ptr<WindowDeprecated> game_window;

    Shader post_processing_shader{"post_processing", "data/shaders"};
    Framebuffer post_processing_framebuffer;

    entt::registry entt_registry;
    flecs::world _world;

    entt::dispatcher event_dispatcher{};
    Input::KeyListener key_listener;
    Input::CursorListener cursor_listener;

    // Resource caches
    entt::resource_cache<Image> image_cache;
    entt::resource_cache<Material> material_cache;
    entt::resource_cache<Mesh> mesh_cache;
    entt::resource_cache<Shader, ShaderLoader> shader_cache;
    entt::resource_cache<GltfMesh> gltf_mesh_cache;
    entt::resource_cache<GltfNode> gltf_node_cache;

    GltfLoader gltf_loader;
    entt::resource_cache<Gltf, GltfLoader> gltf_cache;
};

} // namespace FeverCore
