#version 330 core
struct DirLight
{
    vec3 direction;
    
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

struct PointLight
{
    vec3 position;  
  
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    
    float constant;
    float linear;
    float quadratic;
};

struct Material
{
    sampler2D texture_diffuse1;
    sampler2D texture_specular1;
    sampler2D texture_normal1;
    float shininess;
};

out vec4 FragColor;

in vec2 TexCoords;

in vec3 FragPos;
in vec3 Normal;
uniform vec3 viewPos;

uniform Material material;

#define NR_POINT_LIGHTS 8

in vec3 TangentLightPos[NR_POINT_LIGHTS];
in vec3 TangentViewPos;
in vec3 TangentFragPos;

uniform bool useNormalMapping;

//uniform DirLight dirLight;
uniform PointLight pointLights[NR_POINT_LIGHTS];

vec3 CalcDirLight(DirLight light, vec3 normal, Material material, vec3 viewDir);
vec3 CalcPointLight(PointLight light, vec3 normal, Material material, vec3 fragPos, vec3 viewDir);
vec3 CalcPointLightTangent(PointLight light, vec3 tangentLightPos, vec3 normal, Material material, vec3 tangentFragPos, vec3 viewDir);

void main()
{   
    vec4 texColor = texture(material.texture_diffuse1, TexCoords);
    if(texColor.a < 0.1)
        discard;

    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 pointColor;

    if(useNormalMapping)
    {
        // process normal map
        vec3 normal = texture(material.texture_normal1, TexCoords).rgb;
        normal = normalize(normal * 2.0 - 1.0); //transform normal vector to range [1, -1], is in tangent space

        for(int i = 0; i < NR_POINT_LIGHTS; i++)
        {
            pointColor += vec3(CalcPointLightTangent(pointLights[i], TangentLightPos[i], normal, material, TangentFragPos, viewDir));
        }
    }
    else
    {
        vec3 normal = normalize(Normal);
        for(int i = 0; i< NR_POINT_LIGHTS; i++)
        {
            pointColor += vec3(CalcPointLight(pointLights[i], normal, material, FragPos, viewDir));
        }
    }

    //vec4 dirColor = vec4(CalcDirLight(dirLight, norm, material, viewDir), 1.0);
    //dirColor = dirColor * vec4(0.1, 0.1, 0.1, 1.0);
    
    FragColor = vec4(pointColor, 1.0f);
}

vec3 CalcDirLight(DirLight light, vec3 normal, Material material, vec3 viewDir)
{
    vec3 lightDir = normalize(-light.direction);

    vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));

    vec3 norm = normalize(normal);

    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * texture(material.texture_diffuse1, TexCoords).rgb;

    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec * texture(material.texture_specular1, TexCoords).rgb;

    return (ambient + diffuse + specular);
}

vec3 CalcPointLight(PointLight light, vec3 normal, Material material, vec3 fragPos, vec3 viewDir)
{
    vec3 lightDir = normalize(light.position - fragPos);   

    float diff = max(dot(normal, lightDir), 0.0);

    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);

    float distance = length(light.position - fragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));

    vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, TexCoords));

    ambient *= attenuation;
    diffuse *= attenuation;
    specular *= attenuation;

    return (ambient + diffuse + specular);
}

vec3 CalcPointLightTangent(PointLight light, vec3 tangentLightPos, vec3 normal, Material material, vec3 tangentFragPos, vec3 viewDir)
{
    vec3 lightDir = normalize(tangentLightPos - tangentFragPos);

    float diff = max(dot(normal, lightDir), 0.0);

    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);

    float distance = length(tangentLightPos - tangentFragPos);
    float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));

    vec3 ambient = light.ambient * vec3(texture(material.texture_diffuse1, TexCoords));
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.texture_diffuse1, TexCoords));
    vec3 specular = light.specular * spec * vec3(texture(material.texture_specular1, TexCoords));

    ambient *= attenuation;
    diffuse *= attenuation;
    specular *= attenuation;

    return (ambient + diffuse + specular);
}
