#include "shader.h"
#include "aliases.h"

#define MAX_SHADER_COUNT 2048

typedef struct shader_repo ShaderRepo;
struct shader_repo {
  void *shaders[MAX_SHADER_COUNT];
  VertexShader *vertex_funcs[MAX_SHADER_COUNT];
  FragmentShader *fragment_funcs[MAX_SHADER_COUNT];
  u64 count;
};

internal ShaderRepo g_repository = {0};

ShaderID register_shader(void *shader, VertexShader *vertex,
                         FragmentShader *fragment) {
  if (g_repository.count + 1 >= MAX_SHADER_COUNT) {
    return INVALID_SHADER;
  }

  ++(g_repository.count);
  g_repository.shaders[g_repository.count] = shader;
  g_repository.vertex_funcs[g_repository.count] = vertex;
  g_repository.fragment_funcs[g_repository.count] = fragment;

  return (ShaderID){g_repository.count};
}

VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index,
                             const Model *model) {
  if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vert ||
      !model) {
    return (VertexData){0};
  }

  void *shader_obj = g_repository.shaders[shader.id];
  VertexShader *vertex_func = g_repository.vertex_funcs[shader.id];

  if (!shader_obj || !vertex_func) {
    return (VertexData){0};
  }

  return vertex_func(shader_obj, vert, index, model);
}

FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric,
                                   const Colour *colour, const Model *model) {
  if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) {
    return DISCARDED_FRAGMENT;
  }

  void *shader_obj = g_repository.shaders[shader.id];
  FragmentShader *fragment_func = g_repository.fragment_funcs[shader.id];

  if (!shader_obj || !fragment_func) {
    return DISCARDED_FRAGMENT;
  }

  return fragment_func(shader_obj, barycentric, colour, model);
}
