#include "obj.h"
#include "mem_arena.h"
#include "pam.h"
#include "typed_list.h"
#include "vec.h"
#include <stdio.h>

Model load_obj_file(Arena *arena, const char *filename, const char *texture,
                    const char *normal_map) {
  if (!arena) {
    return INVALID_MODEL;
  }

  FILE *fp = fopen(filename, "r");
  if (!fp) {
    return INVALID_MODEL;
  }

  Model model = (Model){
      .vertices = list_create(V3f, arena),
      .normals = list_create(V3f, arena),
      .texture_coordinates = list_create(V2f, arena),
      .triangles = list_create(Triangle, arena),
  };
  if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) ||
      !(model.triangles)) {
    return INVALID_MODEL;
  }

  char line[8192];
  char identifier[8];
  V3f vertex;
  V3f normal;
  V2f coord;
  Triangle triangle;
  f32 vx, vy, vz;
  f32 nx, ny, nz;
  f32 u, v;
  u64 fp0, fp1, fp2;
  u64 vn0, vn1, vn2;
  u64 tx0, tx1, tx2;
  while (fgets(line, 8191, fp) != NULL) {
    sscanf(line, "%s", identifier);
    if (strncmp(identifier, "v", 8) == 0) {
      sscanf(line + 2, "%f %f %f", &vx, &vy, &vz);
      vertex.x = vx;
      vertex.y = vy;
      vertex.z = vz;
      list_append(V3f, arena, model.vertices, vertex);
    } else if (strncmp(identifier, "vn", 8) == 0) {
      sscanf(line + 2, "%f %f %f", &nx, &ny, &nz);
      normal.x = nx;
      normal.y = ny;
      normal.z = nz;
      list_append(V3f, arena, model.normals, normal);
    } else if (strncmp(identifier, "vt", 8) == 0) {
      sscanf(line + 2, "%f %f", &u, &v);
      coord.u = u;
      coord.v = 1.0f - v;
      list_append(V2f, arena, model.texture_coordinates, coord);
    } else if (strncmp(identifier, "f", 8) == 0) {
      sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", &fp0, &tx0, &vn0,
             &fp1, &tx1, &vn1, &fp2, &tx2, &vn2);
      // OBJ indices start from 1
      triangle.p0 = fp0 - 1;
      triangle.p1 = fp1 - 1;
      triangle.p2 = fp2 - 1;
      triangle.tx0 = tx0 - 1;
      triangle.tx1 = tx1 - 1;
      triangle.tx2 = tx2 - 1;
      triangle.n0 = vn0 - 1;
      triangle.n1 = vn1 - 1;
      triangle.n2 = vn2 - 1;
      list_append(Triangle, arena, model.triangles, triangle);
    }
  }

  if (texture) {
    model.texture = load_p6_image(arena, texture);
  }

  if (normal_map) {
    model.normal = load_p6_image(arena, normal_map);
  }

  return model;
}
