#pragma once
#ifndef RTRMATERIALSANDLIGHTING_H
#define RTRMATERIALSANDLIGHTING_H
//////////////
// Includes //
//////////////
// C++ general includes
#include<string>
#include<iostream>

// OpenGL Includes
#include <glad/glad.h>
#include <GLFW/glfw3.h> // GLFW must be included after GLAD!

#include "rtrShader.h" //rtrShader::

/////////////
// Classes //
/////////////

namespace rtrMaterialsAndLighting
{
	struct Material
	{
		unsigned int textureMap = 1; // texture unit for diffuse texture map
		unsigned int specularMap = 2; //texture unit for specular Map
		unsigned int normalMap = 3; // texture unit for Normal map
		glm::vec3 specularColor = glm::vec3(1.0f, 1.0f, 1.0f);
		float diffuseStrength = 0.5;
		float shininess = 32.0f;
		float specularStrength = 0.5;

		void sendDataToShader(rtrShader::Shader& shader)
		{
			shader.setVec3F("material.specularColor", specularColor);
			shader.setFloat("material.diffuseStrength", diffuseStrength);
			shader.setFloat("material.shininess", shininess);
			shader.setFloat("material.specularStrength", specularStrength);
		}
	};

	struct Light
	{
		glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);
		glm::vec3 direction = glm::vec3(0.0f, -1.0f, 0.0f);
		glm::vec3 color = glm::vec3(1.0f, 1.0f, 1.0f);
		float strength = 1.0f;
		float linAttenFact = 0.09f;
		float quadrAttenFact = 0.032f;
		float cutOff = glm::cos(glm::radians(10.0f));
		float outerCutOff = glm::cos(glm::radians(25.0f));
		bool activated = true;
		int type = -1; // 0 = ambient, 1 = point, 2 = directional, 3 = spot
		bool activateBlinn = true;
		bool keyAlreadyPressed;

		void sendDataToShader(rtrShader::Shader& shader, std::string nameOfUniform)
		{
			shader.use();
			// All light types
			if (type >= 0 && type <= 3)
			{
				shader.setFloat(nameOfUniform + ".strength", strength);//
				shader.setVec3F(nameOfUniform + ".color", color); //
				shader.setBool(nameOfUniform + ".activated", activated); //	
				shader.setInt(nameOfUniform + ".type", type);
				shader.setBool(nameOfUniform + ".activateBlinn", activateBlinn);
			}

			// Point Light OR Spotlight
			if (type == 1 || type == 3)
			{
				shader.setVec3F(nameOfUniform + ".position", position);
				shader.setFloat(nameOfUniform + ".linAttenFact", linAttenFact);
				shader.setFloat(nameOfUniform + ".quadrAttenFact", quadrAttenFact);
			}

			// Directional Light OR Spotlight
			if (type == 2 || type == 3)
			{
				shader.setVec3F(nameOfUniform + ".direction", direction);
			}

			// Spotlight
			if (type == 3)
			{
				shader.setFloat(nameOfUniform + ".cutOff", cutOff);
				shader.setFloat(nameOfUniform + ".outerCutOff", outerCutOff);
			}
		}

		void sendPosAndDirToShader(rtrShader::Shader& shader, std::string nameOfUniform)
		{
			shader.use();
			shader.setVec3F(nameOfUniform + ".position", position);
			shader.setVec3F(nameOfUniform + ".direction", direction);
		}

		void sendStrengthToShader(rtrShader::Shader& shader, std::string nameOfUniform)
		{
			shader.use();
			shader.setFloat(nameOfUniform + ".strength", strength);
		}

		void sendActivationStatusToShader(rtrShader::Shader& shader, std::string nameOfUniform)
		{
			shader.use();
			shader.setBool(nameOfUniform + ".activated", activated);
		}
		
		void processKeyboardInput(GLFWwindow* Window)
		{
			int key;
			switch (type)
			{
			case 0:
				key = GLFW_KEY_A;
				break;
			case 1:
				key = GLFW_KEY_P;
				break;
			case 2:
				key = GLFW_KEY_D;
				break;
			case 3:
				key = GLFW_KEY_S; // atm used for shadows
				break;
			}

			// Toggle light if a, s, d, or p was pressed according to light type
			if ( type != 3 && glfwGetKey(Window, key) == GLFW_PRESS)
			{
				if(!keyAlreadyPressed)
				{
					activated = !activated;
					keyAlreadyPressed = true;
				}
			}
			else
			{
				keyAlreadyPressed = false;
			}
		}
	};

	//Hier könnten noch eigenes ChildStructs hin für AMbient Light, Point Light etc
}
#endif
