#version 330 core

struct Material {
  sampler2D diffuse;
  sampler2D specular;
  float shininess;
};

struct Light {
  vec3 position;
  vec3 direction;
  vec3 ambient;
  vec3 diffuse;
  vec3 specular;
  float cutoff;
  float outer_cutoff;
};

in vec3 vert_normal;
in vec3 frag_position;
in vec2 uv_coords;

out vec4 color;

uniform Material material;
uniform Light light;
uniform vec3 camera_position;

void main() {
  float ambient_strength   = 0.15;
  float specular_strength  = 0.5;
  vec3  normal             = normalize(vert_normal);
  vec3 light_direction     = normalize(light.position - frag_position);
  float theta              = dot(light_direction, normalize(-light.direction));
  float epsilon            = light.cutoff - light.outer_cutoff;
  float intensity          = clamp((theta - light.outer_cutoff) / epsilon, 0.0, 1.0);
  vec3  view_direction     = normalize(camera_position - frag_position);
  vec3  reflect_direction  = reflect(-light_direction, normal);
  float diff               = max(dot(normal, light_direction), 0.0);
  float spec               = pow(max(dot(reflect_direction, view_direction), 0.0), material.shininess);
  vec3  diff_tex           = vec3(texture(material.diffuse, uv_coords));
  vec3  ambient            = light.ambient * diff_tex;
  vec3  diffuse            = light.diffuse * (diff * diff_tex) * intensity;
  vec3  specular           = light.specular * (spec * vec3(texture(material.specular, uv_coords))) * intensity;

  color = vec4(ambient + diffuse + specular, 1.0);
};