//
// Created by sfd on 25-5-25.
//

#include "EditorLayer.h"

#include <imgui.h>
#include <ImGuizmo.h>
#include <glm/gtc/type_ptr.hpp>
#include <Hazel/Core/Input.h>
#include <Hazel/Math/Math.h>
#include <Hazel/Scene/SceneSerializer.h>
#include <Hazel/Utils/PlatformUtils.h>

#include "glm/gtx/matrix_decompose.hpp"

namespace Hazel
{

    extern const std::filesystem::path g_AssetPath;

    EditorLayer::EditorLayer()
        : Layer("HazelEditor"), m_CameraController((float)Application::Get().GetWindow().GetWidth() / (float)Application::Get().GetWindow().GetHeight())
    {

    }

    void EditorLayer::OnAttach()
    {
    	FrameBufferSpecification spec;
    	spec.Width = Application::Get().GetWindow().GetWidth();
    	spec.Height = Application::Get().GetWindow().GetHeight();
    	spec.Attachments = { FrameBufferTextureFormat::RGBA8, FrameBufferTextureFormat::RED_INTEGER,FrameBufferTextureFormat::DEPTH };
        m_FrameBuffer = FrameBuffer::Create(spec);

    	m_ViewPortSize = { spec.Width, spec.Height };

    	m_LogoTexture = Texture2D::Create("assets/textures/iceLogo.png");
    	m_CheckerBoardTexture = Texture2D::Create("assets/textures/Checkerboard.png");

    	m_IconPlay = Texture2D::Create("Resources/Icons/PlayButton.png");
    	m_IconStop = Texture2D::Create("Resources/Icons/PauseButton.png");
    	m_IconSimulate = Texture2D::Create("Resources/Icons/SimulateButton.png");

    	m_EditorScene = CreateRef<Scene>();
    	m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
    	m_ActiveScene = m_EditorScene;

    	m_EditorCamera = EditorCamera(45.0f, 1.667f, 0.1f, 1000.0f);

    	m_SceneHierachyPanel.SetContext(m_ActiveScene);

    	m_GizmoType = ImGuizmo::OPERATION::TRANSLATE;

    }

    void EditorLayer::OnDetech()
    {
    }

    void EditorLayer::OnUpdate(TimeStep& ts)
    {
    	// reset Renderer Draw Stats
    	Renderer2D::ResetStats();

    	if (const auto& spec = m_FrameBuffer->GetSpecification();
    		spec.Width != m_ViewPortSize.x || spec.Height != m_ViewPortSize.y)
    	{
		    m_FrameBuffer->Resize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
		    m_CameraController.OnResize(m_ViewPortSize.x, m_ViewPortSize.y);

    		m_EditorCamera.SetViewPortSize(m_ViewPortSize.x, m_ViewPortSize.y);
    		m_ActiveScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);

	    }

	    // update camera

	    // update Renderer
	    m_FrameBuffer->Bind();
	    RendererCommand::SetClearColor(m_BackgroundColor);
	    RendererCommand::Clear();

    	m_FrameBuffer->ClearAttachment(1, -1);

    	switch (m_SceneState)
    	{
    	case SceneState::Play:
			m_ActiveScene->OnUpdateRuntime(ts);
    		break;
    	case SceneState::Edit:
		    if (m_ViewportFocused)
			    m_CameraController.OnUpdate(ts);

		    m_EditorCamera.OnUpdate(ts);
		    m_ActiveScene->OnUpdateEditor(ts, m_EditorCamera);
    		break;
    	case SceneState::Simulate:
		    m_EditorCamera.OnUpdate(ts);
		    m_ActiveScene->OnUpdateSimulation(ts, m_EditorCamera);
    		break;
    	}


    	auto [mx, my] = ImGui::GetMousePos();
    	mx -= m_ViewPortBounds[0].x;
    	my -= m_ViewPortBounds[0].y;
    	const glm::vec2 viewPortSize = m_ViewPortBounds[1] - m_ViewPortBounds[0];
    	my = viewPortSize.y - my;

    	const int mouseX = (int)mx;
    	const int mouseY = (int)my;

    	if (mouseX >= 0 && mouseY >= 0 && mouseX < m_ViewPortSize.x && mouseY < m_ViewPortSize.y)
    	{
    		int pixelData = m_FrameBuffer->ReadPixel(1, mouseX, mouseY);
    		m_HoveredEntity = pixelData == -1 ? Entity{} : Entity{ (entt::entity)pixelData, m_ActiveScene.get()};
	    }

	    // Renderer2D::DrawQuad({0, 0.5f}, {1.0f, 1.0f}, {0.2f, 0.3f, 0.8f, 1.0f});
	    // Renderer2D::DrawQuad({0, -0.5f}, {1.0f, 1.0f}, {0.8f, 0.2f, 0.2f, 1.0f});
	    // Renderer2D::DrawQuad({-1, 0}, {1, 1}, m_LogoTexture);
	    // Renderer2D::DrawQuad({1, 0}, {1, 1}, m_CheckerBoardTexture);
		OnOverLayRender();

	    // Renderer2D::EndScene();
	    m_FrameBuffer->UnBind();
    }

	void EditorLayer::OnOverLayRender()
    {

    	if (m_SceneState == SceneState::Play)
    	{

    		Entity camera = m_ActiveScene->GetPrimaryCameraEntity();
    		if (camera)
    			Renderer2D::BeginScene(camera.GetComponent<CameraComponent>().Camera, camera.GetComponent<TransformComponent>().GetTransform());
    		else
				Renderer2D::BeginScene(m_EditorCamera);
    	}else
	    {
		    Renderer2D::BeginScene(m_EditorCamera);
	    }

    	if (m_ShowPhysicsColliders)
	    {
		    // box collider
    		auto bcview = m_ActiveScene->GetAllEntitiesWith<TransformComponent, BoxCollider2DComponent>();
    		for (auto entity : bcview)
    		{
    			auto [tc, bc2D] = bcview.get<TransformComponent, BoxCollider2DComponent>(entity);


    			glm::mat4 model = glm::translate(glm::mat4(1.0f), tc.Translation)
								* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
								* glm::scale(glm::mat4(1.0f), tc.Scale);

    			glm::vec4 worldOffset = model * glm::vec4(bc2D.Offset.x, bc2D.Offset.y, 0.0f, 1.0f);
    			// glm::vec3 translation = glm::vec3(worldOffset) + glm::vec3(0.0f, 0.0f, 0.001f);
    			glm::vec3 scale = tc.Scale * glm::vec3(bc2D.Size * 2.0f, 1.0f);

    			glm::mat4 transform =
					glm::translate(glm::mat4(1.0f), glm::vec3(worldOffset))
					* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
					* glm::scale(glm::mat4(1.0f), scale);

    			Renderer2D::DrawRect(transform, glm::vec4(0.2f, 1.0f, 0.2f, 1.0f));
    		}

			// circle collider
		    auto ccview = m_ActiveScene->GetAllEntitiesWith<TransformComponent, CircleCollider2DComponent>();
		    for (auto entity : ccview)
		    {
			    auto      [tc, cc2D]  = ccview.get<TransformComponent, CircleCollider2DComponent>(entity);
    			glm::mat4 model = glm::translate(glm::mat4(1.0f), tc.Translation)
								* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
								* glm::scale(glm::mat4(1.0f), tc.Scale);

    			glm::vec4 worldOffset = model * glm::vec4(cc2D.Offset.x, cc2D.Offset.y, 0.0f, 1.0f);
    			// glm::vec3 translation = glm::vec3(worldOffset) + glm::vec3(0.0f, 0.0f, 0.001f);
    			glm::vec3 scale = tc.Scale * glm::vec3(cc2D.Radius * 2.05f);

    			glm::mat4 transform =
					glm::translate(glm::mat4(1.0f), glm::vec3(worldOffset))
					* glm::rotate(glm::mat4(1.0f), tc.Rotation.z, glm::vec3(0.0f, 0.0f, 1.0f))
					* glm::scale(glm::mat4(1.0f), scale);

			    Renderer2D::DrawCircle(transform, glm::vec4(0.2, 1.0f, 0.2f, 1.0f), Renderer2D::GetLineWidth() * 0.015f);
		    }
	    }
    	Renderer2D::EndScene();
    }

    void EditorLayer::OnImGuiRender()
    {
	    static bool showDockspace = true;
	    if (showDockspace)
	    {
		    static bool               dockspaceOpen   = true;
		    static bool               opt_fullscreen  = true;
		    static bool               opt_padding     = false;
		    static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;

		    // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
		    // because it would be confusing to have two docking targets within each others.
		    ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
		    if (opt_fullscreen)
		    {
			    const ImGuiViewport* viewport = ImGui::GetMainViewport();
			    ImGui::SetNextWindowPos(viewport->WorkPos);
			    ImGui::SetNextWindowSize(viewport->WorkSize);
			    ImGui::SetNextWindowViewport(viewport->ID);
			    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
			    ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
			    window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
				    ImGuiWindowFlags_NoMove;
			    window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
		    }
		    else
		    {
			    dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
		    }

		    // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
		    // and handle the pass-thru hole, so we ask Begin() to not render a background.
		    if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
			    window_flags |= ImGuiWindowFlags_NoBackground;

		    // Important: note that we proceed even if Begin() returns false (aka window is collapsed).
		    // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
		    // all active windows docked into it will lose their parent and become undocked.
		    // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
		    // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
		    if (!opt_padding)
			    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
		    ImGui::Begin("DockSpace", &dockspaceOpen, window_flags);
		    if (!opt_padding)
			    ImGui::PopStyleVar();

		    if (opt_fullscreen)
			    ImGui::PopStyleVar(2);

		    // Submit the DockSpace
		    ImGuiIO&    io        = ImGui::GetIO();
		    ImGuiStyle& style     = ImGui::GetStyle();
		    style.WindowMinSize.x = 364.0f;
		    if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
		    {
			    ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
			    ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
		    }

		    if (ImGui::BeginMenuBar())
		    {
			    if (ImGui::BeginMenu("Options"))
			    {
				    // Disabling fullscreen would allow the window to be moved to the front of other windows,
				    // which we can't undo at the moment without finer window depth/z control.
				    // ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
				    // ImGui::MenuItem("Padding", NULL, &opt_padding);
				    // ImGui::Separator();
				    if (ImGui::MenuItem("New", "Ctrl+N"))
					    NewScene();
				    if (ImGui::MenuItem("Open...", "Ctrl+O"))
					    OpenScene();
				    if (ImGui::MenuItem("Save", "Ctrl+S", false, m_ActiveScene ? true : false))
					    SaveScene();
				    if (ImGui::MenuItem("Save As...", "Ctrl+Shift+S"))
					    SaveSceneAs();

				    ImGui::Separator();
				    if (ImGui::MenuItem("Exit")) { Hazel::Application::Get().Close(); }

				    ImGui::EndMenu();
			    }

			    ImGui::EndMenuBar();
		    }

		    // Scene Hierachy Panel
		    m_SceneHierachyPanel.OnImGuiRender();
	    	m_ContentBroswerPanel.OnImGuiRender();

		    // Render Status
		    {
			    ImGui::Begin("Render Status");

			    auto stats = Renderer2D::GetStats();
			    ImGui::Text("Renderer BatchInfo: ");
			    ImGui::Text("Draw Calls: %d", stats.DrawCalls);
			    ImGui::Text("Quads: %d", stats.QuadCount);
			    ImGui::Text("Vertices: %d", stats.GetTotalVertexCount());
			    ImGui::Text("Indices: %d", stats.GetTotalIndexCount());

			    ImGui::Separator();

			    ImGui::Text("viewPortSize: (%.2f, %.2f)", m_ViewPortSize.x, m_ViewPortSize.y);

			    ImGui::Separator();

				auto editorCameraPos = m_EditorCamera.GetPosition();
		    	ImGui::Text("Editor Camera(%.3f, %.3f, %.3f)", editorCameraPos.x, editorCameraPos.y, editorCameraPos.z);
		    	ImGui::Text("Editor Camera Distance: %f", m_EditorCamera.GetDistance());

		    	float lineWidth = Renderer2D::GetLineWidth();
		    	if (ImGui::DragFloat("LineWidth", &lineWidth, 0.01f, 0.0f, 10.0f))
		    	{
		    		Renderer2D::SetLineWidth(lineWidth);
		    	}
		    	// std::string name = "none";
		    	// if (m_HoveredEntity)
		    		// name = m_HoveredEntity.GetComponent<TagComponent>().Tag;

		    	// ImGui::Text("Hovered Entity: %s", name.c_str());

		    	ImGui::Separator();

		    	ImGui::Checkbox("Show Colliders", &m_ShowPhysicsColliders);

			    ImGui::End();
		    }

		    // ViewPort
		    {
			    ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f});
			    ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoCollapse);
			    auto viewportOffet = ImGui::GetCursorPos();
			    m_ViewportFocused  = ImGui::IsWindowFocused();
			    m_ViewportHovered  = ImGui::IsWindowHovered();


			    ImVec2 viewPortPanelSize = ImGui::GetContentRegionAvail();
			    if (m_ViewPortSize != *reinterpret_cast<glm::vec2*>(&viewPortPanelSize))
			    {
				    m_ViewPortSize = {viewPortPanelSize.x, viewPortPanelSize.y};
			    }
			    // ImGui::Text("Viewport: (%.2f, %.2f)", viewPortPanelSize.x, viewPortPanelSize.y);
			    ImGui::Image(m_FrameBuffer->GetColorAttachmentID(), {m_ViewPortSize.x, m_ViewPortSize.y}, {0, 1},
			                 {1, 0});
		    	const ImVec2 &viewPortMin = ImGui::GetItemRectMin();  // left-top pos
		    	const ImVec2 &viewPortMax = ImGui::GetItemRectMax();  // right-buttom pos

		    	if (ImGui::BeginDragDropTarget())
		    	{
		    		if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROSWER_ITEM"))
				    {
					    const wchar_t* path = (const wchar_t*)payload->Data;
					    OpenScene(std::filesystem::path(g_AssetPath) / path);
				    }
		    		ImGui::EndDragDropTarget();
		    	}

			    auto   windowsSize = ImGui::GetWindowSize();
			    ImVec2 minBound    = ImGui::GetWindowPos();


			    minBound.x += viewportOffet.x;
			    minBound.y += viewportOffet.y + m_ViewPortSize.y - windowsSize.y;

			    ImVec2 maxBound     = {minBound.x + windowsSize.x, minBound.y + windowsSize.y};
			    m_ViewPortBounds[0] = {minBound.x, minBound.y};
			    m_ViewPortBounds[1] = {maxBound.x, maxBound.y};

			    // ImGuizmo
			    Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity();
			    if (selectedEntity)
			    {
				    ImGuizmo::SetOrthographic(false);
				    ImGuizmo::SetDrawlist();


				    ImGuizmo::SetRect(viewPortMin.x, viewPortMin.y, viewPortMax.x - viewPortMin.x, viewPortMax.y - viewPortMin.y);

				    if (m_GizmoType != -1)
				    {

						glm::mat4 cameraProjection;
						glm::mat4 cameraView;

				    	if (m_SceneState == SceneState::Play)
					    {
						    auto cameraEntity = m_ActiveScene->GetPrimaryCameraEntity();
						    const auto& camera = cameraEntity.GetComponent<CameraComponent>().Camera;

							cameraProjection = camera.GetProjection();
							cameraView = glm::inverse(cameraEntity.GetComponent<TransformComponent>().GetTransform());
					    }else
					    {
						    cameraProjection = m_EditorCamera.GetProjection();
						    cameraView       = m_EditorCamera.GetViewMatrix();
					    }

					    auto& tc = selectedEntity.GetComponent<TransformComponent>();

					    glm::mat4 transform        = tc.GetTransform();
					    bool      snap             = SDL_GetModState() & SDL_KMOD_CTRL;
					    float     snapValue        = 0.5f;
					    if (m_GizmoType == ImGuizmo::OPERATION::TRANSLATE)
						    snapValue = 0.25f;
					    else if (m_GizmoType == ImGuizmo::OPERATION::ROTATE)
						    snapValue = 15.0f;
					    else if (m_GizmoType == ImGuizmo::OPERATION::SCALE)
						    snapValue = 0.25f;

					    float snapValues[3] = {snapValue, snapValue, snapValue};
					    if (ImGuizmo::Manipulate(glm::value_ptr(cameraView), glm::value_ptr(cameraProjection),
					                             static_cast<ImGuizmo::OPERATION>(m_GizmoType), ImGuizmo::WORLD,
					                             glm::value_ptr(transform), nullptr, snap ? snapValues : nullptr) && !Input::IsKeyPressed(SDL_SCANCODE_LALT))
					    {
						    if (ImGuizmo::IsUsing())
						    {
							    glm::vec3 translation, rotation, scale;

							    Hazel::Math::DecomposeTransform(transform, translation, rotation, scale);

							    glm::vec3 deltaRotation = rotation - tc.Rotation;

							    tc.Translation = translation;
							    tc.Rotation += deltaRotation;
							    tc.Scale = scale;
						    }
					    }
				    }
			    }


			    ImGui::End();
			    ImGui::PopStyleVar();
		    }

	    	UI_ToolBar();

		    ImGui::End();
	    }
    }

    void EditorLayer::SaveSceneAs() const
    {
	    std::string filepath = FileDiaglogs::SaveFile("Hazel Scene (*.scene,*.yaml)\0*.scene;*.yaml\0*\0*.*\0\0");
	    if (!filepath.empty())
	    {
			SerializeScene(m_ActiveScene, filepath);
	    }
    }

    void EditorLayer::OpenScene()
    {
	    std::string filepath = FileDiaglogs::OpenFile("Scene(*.scene, *.yaml)\0*.scene;*.yaml\0All files\0*.*\0\0");
	    if (!filepath.empty())
	    	OpenScene(filepath);
    }

    void EditorLayer::OpenScene(const std::filesystem::path& scenePath)
    {
    	if (m_SceneState != SceneState::Edit)
    		OnSceneStop();

	    Ref<Scene> newScene = CreateRef<Scene>();
	    SceneSerializer serializer(newScene);
	    if (serializer.Deserialize(scenePath.string()))
	    {
	    	m_EditorScene = newScene;
		    m_EditorScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);

	    	m_ActiveScene = m_EditorScene;

		    m_SceneHierachyPanel.SetContext(m_ActiveScene);

	    	m_EditorScenePath = scenePath;
	    }
    }

    void EditorLayer::NewScene()
    {
	    m_ActiveScene = CreateRef<Scene>();
	    m_ActiveScene->OnViewportResize((uint32_t)m_ViewPortSize.x, (uint32_t)m_ViewPortSize.y);
	    m_SceneHierachyPanel.SetContext(m_ActiveScene);

    	m_EditorScenePath = std::filesystem::path();
    }

    void EditorLayer::SaveScene() const
    {
    	if (!m_EditorScenePath.empty())
    	{
    		SerializeScene(m_ActiveScene, m_EditorScenePath);
    	}
    }

    void EditorLayer::SerializeScene(Ref<Scene> scene, const std::filesystem::path& scenePath) const
    {
    		const SceneSerializer serializer(scene);
    		serializer.Serialize(scenePath.string());
    }

    void EditorLayer::OnDuplicateEntity()
    {
    	if (m_SceneState != SceneState::Edit)
    		return;
		Entity selectedEntity = m_SceneHierachyPanel.GetSelectedEntity();
		if (selectedEntity)
			m_EditorScene->DuplicateEntity(selectedEntity);
    }

    void EditorLayer::OnScenePlay()
    {
    	if (m_SceneState == SceneState::Simulate)
    		OnSceneStop();

    	// SaveScene();
    	m_SceneState = SceneState::Play;

    	m_ActiveScene = Scene::Copy(m_EditorScene);
    	m_ActiveScene->OnRuntimeStart();

    	m_SceneHierachyPanel.SetContext(m_ActiveScene);
    }

    void EditorLayer::OnSceneStop()
    {
    	if (m_SceneState != SceneState::Play && m_SceneState != SceneState::Simulate)
    	{
    		HZ_CORE_WARN("Scene is not playing or simulating!");
    		return;
    	}

    	if (m_SceneState == SceneState::Play)
		    m_ActiveScene->OnRuntimeStop();
    	else if (m_SceneState == SceneState::Simulate)
    		m_ActiveScene->OnSimulationStop();

    	m_SceneState = SceneState::Edit;
    	m_ActiveScene = m_EditorScene;
    	m_SceneHierachyPanel.SetContext(m_ActiveScene);
    }

    void EditorLayer::OnSceneSimulation()
    {
    	if (m_SceneState == SceneState::Simulate)
    		OnSceneStop();
    	// SaveScene();
    	m_SceneState = SceneState::Simulate;

    	m_ActiveScene = Scene::Copy(m_EditorScene);
    	m_ActiveScene->OnSimulationStart();

    	m_SceneHierachyPanel.SetContext(m_ActiveScene);
    }

    void EditorLayer::ChangeOptMode(unsigned int mode)
    {
	    if (m_ViewportHovered)
		    m_GizmoType = mode;
    }

    void EditorLayer::OnEvent(SDL_Event& e)
    {
	    if (m_ViewportFocused)
	    {
		    m_CameraController.OnEvent(e);
		    m_EditorCamera.OnEvent(e);
	    }
    	if (e.button.clicks && m_ViewportHovered && !ImGuizmo::IsOver() && Input::IsMouseButtonPressed(BUTTON_LEFT) && !Input::IsKeyPressed(SDL_SCANCODE_LALT))
	    	m_SceneHierachyPanel.SetSelectedEntity(m_HoveredEntity);

#define SHORTCUT_EXIT		(SDL_KMOD_CTRL + SDLK_W)
#define SHORTCUT_NEW		(SDL_KMOD_CTRL + SDLK_N)
#define SHORTCUT_OPEN		(SDL_KMOD_CTRL + SDLK_O)
#define SHORTCUT_SAVE		(SDL_KMOD_CTRL + SDLK_S)
#define SHORTCUT_SAVE_AS	(SDL_KMOD_CTRL + SDL_KMOD_SHIFT + SDLK_S)
#define SHORTCUT_CTRL_D		(SDL_KMOD_CTRL + SDLK_D)


		if (e.key.down && e.key.repeat == 0)
		{
			const auto mod   = SDL_GetModState();
			const auto ctrl  = (mod & SDL_KMOD_CTRL) ? SDL_KMOD_CTRL : 0;
			const auto shift = (mod & SDL_KMOD_SHIFT) ? SDL_KMOD_SHIFT : 0;

			switch (ctrl + shift + e.key.key)
			{
			case SHORTCUT_EXIT:
				Application::Get().Close();
				break;
			case SHORTCUT_NEW:
				NewScene();
				break;
			case SHORTCUT_OPEN:
				OpenScene();
				break;
			case SHORTCUT_SAVE:
				SaveScene();
				break;
			case SHORTCUT_SAVE_AS:
				SaveSceneAs();
				break;
			case SHORTCUT_CTRL_D:
				OnDuplicateEntity();
				break;

			// GIZMO
			case SDLK_Q:
				ChangeOptMode(-1);
				break;
			case SDLK_W:
				ChangeOptMode(ImGuizmo::OPERATION::TRANSLATE);
				break;
			case SDLK_E:
				ChangeOptMode(ImGuizmo::OPERATION::SCALE);
				break;
			case SDLK_R:
				ChangeOptMode(ImGuizmo::OPERATION::ROTATE);
				break;

			default:
				break;
			}
		}
    }

    void EditorLayer::UI_ToolBar()
    {
    	ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2));
    	ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0));

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
    	auto& colors = ImGui::GetStyle().Colors;
    	auto& buttonHovered = colors[ImGuiCol_ButtonHovered];
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(buttonHovered.x, buttonHovered.y, buttonHovered.z, 0.5f));
    	auto& buttonActive = colors[ImGuiCol_ButtonActive];
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(buttonActive.x, buttonActive.y, buttonActive.z, 0.5f));


    	ImGui::Begin("##ToolBar", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
    	// ImGui::Begin("##ToolBar", nullptr);

    	float size = ImGui::GetWindowHeight() - 10.0f;
    	ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - size * 0.5f);
    	ImGui::SetCursorPosX(ImGui::GetWindowContentRegionMax().x * 0.5f - (size * 0.5f));

    	Ref<Texture2D> icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate)? m_IconPlay : m_IconStop;
    	if (ImGui::ImageButton("toolbar-play-edit", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1}))
    	{
    		if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Simulate)
				OnScenePlay();
    		else if (m_SceneState == SceneState::Play)
    			OnSceneStop();
    	}

    	ImGui::SameLine();
	    {
		    Ref<Texture2D> icon = (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play)? m_IconSimulate : m_IconStop;
		    if (ImGui::ImageButton("toolbar-simulate", icon->GetRendererID(), ImVec2{size, size}, ImVec2{0, 0}, ImVec2{1, 1}))
		    {
			    if (m_SceneState == SceneState::Edit || m_SceneState == SceneState::Play)
				    OnSceneSimulation();
			    else if (m_SceneState == SceneState::Simulate)
				    OnSceneStop();
		    }
	    }

    	ImGui::PopStyleVar(2);
    	ImGui::PopStyleColor(3);
		ImGui::End();
    }

}
