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

#include "ExampleLayer.h"

#include <imgui.h>
#include <Hazel/Renderer/Renderer.h>
#include <Hazel/Renderer/RendererCommand.h>
#include <Platform/OpenGL/OpenGLShader.h>

#include "glm/gtc/type_ptr.hpp"

#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/transform.hpp"

ExampleLayer::ExampleLayer() : Layer("ExampleLayer"), m_CameraController(1280.0f / 720.0f), m_SquarePosition(glm::vec3(0.0f))
{
		// ------------------------------------------------------------test------------------------------------------------------------
		// Vertex Array
		m_VertexArray = Hazel::VertexArray::Create();

		// Vertex Buffer
		float vertices[3 * 7] = {
			-0.5f, -0.5f, 0.0f, 0.8f, 0.2f, 0.8f, 1.0f,
			0.5f, -0.5f, 0.0f, 0.2f, 0.3f, 0.8f, 1.0f,
			0.0f, 0.5f, 0.0f, 0.8f, 0.8f, 0.2f, 1.0f
		};
		std::shared_ptr<Hazel::VertexBuffer> m_VertexBuffer;
		m_VertexBuffer = Hazel::VertexBuffer::Create(vertices, sizeof(vertices));
		Hazel::BufferLayout layout = {
			{Hazel::ShaderDataType::Float3, "a_Postion"},
			{Hazel::ShaderDataType::Float4, "a_Color"},
		};
		m_VertexBuffer->SetLayout(layout);
		m_VertexArray->AddVertexBuffer(m_VertexBuffer);


		uint32_t                            indices[6] = {0, 1, 2};
		std::shared_ptr<Hazel::IndexBuffer> m_IndexBuffer;
		m_IndexBuffer = Hazel::IndexBuffer::Create(indices, sizeof(indices) / sizeof(indices[0]));
		m_VertexArray->SetIndexBuffer(m_IndexBuffer);

		// Shader
		std::string vertexSrc   = R"(
			#version 460 core

			layout(location = 0) in vec3 a_Position;
			layout(location = 1) in vec3 a_Color;

			uniform mat4 u_ViewProjection;
			uniform mat4 u_Transform;

			out vec3 v_Position;
			out vec3 v_Color;

			void main() {
				v_Position = a_Position;
				v_Color = a_Color;
				gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0f);
			}

		)";
		std::string fragmentSrc = R"(
			#version 460 core

			layout(location = 0) out vec4 color;

			in vec3 v_Position;
			in vec3 v_Color;

			void main() {
				color = vec4(v_Color, 1.0f);
			}
		)";
		m_Shader = Hazel::Shader::Create("demoShader", vertexSrc, fragmentSrc);


		m_SquareVA = Hazel::VertexArray::Create();

		float squareVertices[5 * 4] = {
			-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
			0.5f, -0.5f, 0.0f,1.0f, 0.0f,
			0.5f, 0.5f, 0.0f,1.0f, 1.0f,
			-0.5f, 0.5f, 0.0f,0.0f, 1.0f
		};
		std::shared_ptr<Hazel::VertexBuffer> squareVB; //= VertexBuffer::Create(squareVertices, sizeof(squareVertices));
		squareVB = Hazel::VertexBuffer::Create(squareVertices, sizeof(squareVertices));
		squareVB->SetLayout(
			{
				{Hazel::ShaderDataType::Float3, "a_Postion"},
				{Hazel::ShaderDataType::Float2, "a_TexCoord"}
			});
		m_SquareVA->AddVertexBuffer(squareVB);


		uint32_t                            squareIndice[6] = {0, 1, 2, 2, 3, 0};
		std::shared_ptr<Hazel::IndexBuffer> squareIB;
		// = std::make_shared<IndexBuffer>(IndexBuffer::Create(squareIndice, sizeof(squareIndice) / sizeof(uint32_t)));
		squareIB = Hazel::IndexBuffer::Create(squareIndice, sizeof(squareIndice) / sizeof(uint32_t));
		m_SquareVA->SetIndexBuffer(squareIB);

		std::string coloeVertexSrc      = R"(
			#version 460 core

			layout(location = 0) in vec3 a_Position;
			layout(location = 1) in vec2 a_TexCoord;

			uniform mat4 u_ViewProjection;
			uniform mat4 u_Transform;

			out vec2 v_TexCoord;

			void main() {
				v_TexCoord = a_TexCoord;
				gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0f);
			}
		)";
		std::string colorFragmentSrc = R"(
			#version 460 core

			layout(location = 0) out vec4 color;

			in vec3 v_Position;
			uniform vec4 u_Color;

			void main() {
				color = u_Color;
			}
		)";
		m_colorShader = Hazel::Shader::Create("ColorShader", coloeVertexSrc, colorFragmentSrc);


		// Texture.Shader
		// m_TextureShader = Hazel::Shader::Create("assets/shaders/Texture.glsl");
		auto textureShader = m_ShaderLibrary.Load("assets/shaders/Texture.glsl");


		// Texture
		m_Texture = Hazel::Texture2D::Create("assets/textures/Checkerboard.png");
		m_logoTexture = Hazel::Texture2D::Create("assets/textures/iceLogo.png");

		std::dynamic_pointer_cast<Hazel::OpenGLShader>(textureShader)->Bind();
		std::dynamic_pointer_cast<Hazel::OpenGLShader>(textureShader)->UploadUniformInt("u_Texture", 0);
	}


void ExampleLayer::OnUpdate(Hazel::TimeStep& ts)
{
		m_CameraController.OnUpdate(ts);

		// key event
		{
			float time = ts;

			const bool* state = SDL_GetKeyboardState(NULL);

			if (state[SDL_SCANCODE_I])
			{
				m_SquarePosition.y += 5 * time;
			}
			else if (state[SDL_SCANCODE_K])
			{
				m_SquarePosition.y -= 5 * time;
			}
			if (state[SDL_SCANCODE_J])
			{
				m_SquarePosition.x -= 5 * time;
			}
			else if (state[SDL_SCANCODE_L])
			{
				m_SquarePosition.x += 5 * time;
			}
		}


		Hazel::RendererCommand::SetClearColor(m_ScreenClearColor);
		Hazel::RendererCommand::Clear();

		Hazel::Renderer::BeginScene(m_CameraController.GetCamera());

		auto transform = glm::translate(glm::mat4(1.0f), m_SquarePosition);

		auto textureShader = m_ShaderLibrary.Get("Texture");
		m_Texture->Bind();
		Hazel::Renderer::Submit(textureShader, m_SquareVA, transform);

		m_logoTexture->Bind();
		Hazel::Renderer::Submit(textureShader, m_SquareVA);

		Hazel::Renderer::EndScene();
}


void ExampleLayer::OnEvent(SDL_Event& e)
{
	m_CameraController.OnEvent(e);
}

void ExampleLayer::OnImGuiRender()
{
	ImGui::ShowDemoWindow();

	const auto cameraRotation = m_CameraController.GetCamera().GetRotation();
	const auto cameraPosition = m_CameraController.GetCamera().GetPosition();
	ImGui::Begin("Hazel Layer");
	ImGui::Text("Rotation: %f", cameraRotation);
	ImGui::Text("Position: ( %.2f, %.2f, %.2f)", cameraPosition.x, cameraPosition.y, cameraPosition.z);
	ImGui::Text("frame: %.3f", ImGui::GetIO().Framerate);
	ImGui::ColorEdit3("Square Color", glm::value_ptr(m_SquareColor));
	ImGui::NewLine();
	ImGui::ColorEdit4("Screen Clear Color", glm::value_ptr(m_ScreenClearColor));
	ImGui::End();
}
