#pragma once
// #include "TexturePool.h"

// #include "WAlloc.h"
// #include "util/WArray.h"

struct Drawer;
class LUT;
class DrawerMDI;
class StartMenu;
class TextDrawer;
class Font;
class AudioFile;
class ModelNode;
class ShaderProgram;
class Light;
class Shader;
class Camera;
struct ShaderManager;
class Editor;
class Framebuffer;
class Texture;
class Buffer;
class TexturePool;
class WGL;

class Model;

class AudioMixer;
class Physics;




class WEntity;
struct WCollision;
struct DebugDrawer;
struct Drawer2D;
class Drawer3D;
class IO;


struct Scene {
	virtual void init() = 0;
	virtual void loop() = 0;
};

#include "gl/Texture.h"
#include "engine/Physics.h"
#include "WEntity.h"
#include "scenes/_SceneVars.h"

struct MidiFile;
class Engine {
private:
	void update_time();
	void update_shared_uniforms();
	void handle_winapi_start_frame();

public:
	std::vector<Framebuffer*> framebuffers;
	Framebuffer* curr_bound_framebuffer = nullptr;
	TexturePool* texture_pool;
	// WArray<Texture*>* textures;

	bool fullscreen = false;
	bool borderless = false;

	Camera* camera;

	uint32_t msaa_samples = 16;
	
	uint32_t RESX;
	uint32_t RESY;
	
	uint32_t desktop_fullscreen_res_x;
	uint32_t desktop_fullscreen_res_y;
	
	uint32_t refresh_rate = 60;

	AudioMixer* audio_mixer;
	Physics physics;

	float ambient_light_intensity = 1.0;

	WGL* wgl;
  Framebuffer* default_fb;
	ShaderManager* shader_manager;
	DebugDrawer* debug_drawer;
	ShaderProgram* prog_clean_dbg;
	ShaderProgram* prog_blit_texture;
	ShaderProgram* prog_gif;

	// TextDrawer* text_drawer = nullptr;
	Drawer3D* drawer_3d = nullptr;
	Drawer2D* drawer_2d = nullptr;
	DrawerMDI* drawer_mdi = nullptr;
	Drawer* drawer_new = nullptr;

	WAlloc<Model, 10>& alloc_scenes = WAlloc<Model, 10>::get_instance();
	WAlloc<Texture, 500>& alloc_textures = WAlloc<Texture, 500>::get_instance();
	WAlloc<Light, 10000>& alloc_lights = WAlloc<Light, 10000>::get_instance();
	WAlloc<WEntity, 10000>& alloc_game_object = WAlloc<WEntity, 10000>::get_instance();

	std::vector<Buffer*> buffers;

	Model* scene_model = nullptr;


	IO* io = nullptr;
	Editor* editor = nullptr;

	Shader* passthrough_frag_shader;
	Shader* shadowmap_geom_shader;
	Shader* vert_sh_fullscreen_quad;
	Buffer* shared_ssbo;
	Buffer* lights_ssbo;


	bool to_reset_whole_engine = false;

	std::unordered_map<JPH::BodyID, WEntity*> body_to_game_object;
	std::unordered_map<long, WEntity*> entitties;
	std::vector<WEntity*> objects_to_destroy;
	// std::vector<Framebuffer*> framebuffers_to_resize;
	std::vector<Framebuffer*> shadow_map_textures;
	// WArray<GameObject*> collided_game_objects;
	std::vector<WCollision> collisions;
	std::vector<Light> lights;
	std::vector<MidiFile*> midi_files;

	std::atomic<bool> scene_reloaded;

	int bytes_upload_this_frame = 0;
	std::mutex collisions_mutex;

	long gam_obj_id_cnt = 0;

	bool initializing = true;

	long timer;
	long timerStart;
	double time = 0.0;
	double delta_time = 0.0;
	double delta_time_internal = 0.0;
	long frame = 0;
	
  HMODULE giflib_instance = nullptr;
  HMODULE libvlc_instance = nullptr;

	Engine();
	void end_frame();

	// void initialize();
	void start_frame();
	void start_timer_query(const char* name);

	Texture* get_tex(TextureDesc target_desc);

	Framebuffer* get_framebuffer(TextureDesc target_desc);

	void init_tracer(VarsCloudTracer& v);
	void run();



	void reset();
	void destroy_entity(WEntity* entity);

};
