#include "camera/camera.h"
#include "mem_arena.h"
#include "mem_utils.h"
#include "misc/misc_utils.h"
#include "rasteriser/rasteriser.h"
#include "vector/vec.h"
#include "window/window.h"
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_keycode.h>
#include <stdlib.h>

int main(void) {
  colour_t bg =
      (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
  camera_t camera = {
      .position = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
      .rotation = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
  };
  vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f};

  window_t window = {0};

  if (!init_window(&window, 800, 800, "CG From Scratch Rasteriser")) {
    return EXIT_FAILURE;
  }

  bool running = true;
  SDL_Event event = {0};

  // i32 w_min = ((i32)window.half_width) * -1;
  // i32 w_max = (i32)window.half_width;
  // i32 h_min = ((i32)window.half_height) * -1;
  // i32 h_max = (i32)window.half_height;

  // The four "front" vertices
  vec3f_t vAf = {-2, -0.5, 5};
  vec3f_t vBf = {-2, 0.5, 5};
  vec3f_t vCf = {-1, 0.5, 5};
  vec3f_t vDf = {-1, -0.5, 5};

  // The four "back" vertices
  vec3f_t vAb = {-2, -0.5, 6};
  vec3f_t vBb = {-2, 0.5, 6};
  vec3f_t vCb = {-1, 0.5, 6};
  vec3f_t vDb = {-1, -0.5, 6};

  // The front face
  line_t lABf = {project_point(vAf, &window, &camera, viewport),
                 project_point(vBf, &window, &camera, viewport)};
  line_t lBCf = {project_point(vBf, &window, &camera, viewport),
                 project_point(vCf, &window, &camera, viewport)};
  line_t lCDf = {project_point(vCf, &window, &camera, viewport),
                 project_point(vDf, &window, &camera, viewport)};
  line_t lDAf = {project_point(vDf, &window, &camera, viewport),
                 project_point(vAf, &window, &camera, viewport)};

  // The back face
  line_t lABb = {project_point(vAb, &window, &camera, viewport),
                 project_point(vBb, &window, &camera, viewport)};
  line_t lBCb = {project_point(vBb, &window, &camera, viewport),
                 project_point(vCb, &window, &camera, viewport)};
  line_t lCDb = {project_point(vCb, &window, &camera, viewport),
                 project_point(vDb, &window, &camera, viewport)};
  line_t lDAb = {project_point(vDb, &window, &camera, viewport),
                 project_point(vAb, &window, &camera, viewport)};

  // The front-to-back edges
  line_t lABfb = {project_point(vAf, &window, &camera, viewport),
                  project_point(vAb, &window, &camera, viewport)};
  line_t lBCfb = {project_point(vBf, &window, &camera, viewport),
                  project_point(vBb, &window, &camera, viewport)};
  line_t lCDfb = {project_point(vCf, &window, &camera, viewport),
                  project_point(vCb, &window, &camera, viewport)};
  line_t lDAfb = {project_point(vDf, &window, &camera, viewport),
                  project_point(vDb, &window, &camera, viewport)};

  Arena *frame_arena = NULL;
  u64 capacity = 10ull * 1024ull * 1024ull * 1024ull;
  if (!wapp_mem_arena_init(&frame_arena, capacity, WAPP_MEM_ALLOC_RESERVE,
                           false)) {
    return EXIT_FAILURE;
  }

  colour_t front = {.colour = 0x00ffaaff};
  colour_t back = {.colour = 0xee0099ff};
  colour_t fb = {.colour = 0xffaa00ff};

  while (running) {
    while (SDL_PollEvent(&event)) {
      switch (event.type) {
      case SDL_QUIT:
        running = false;
        break;
      }
    }

    clear_window(&window, bg);

    draw_line(&window, frame_arena, lABf, front);
    draw_line(&window, frame_arena, lBCf, front);
    draw_line(&window, frame_arena, lCDf, front);
    draw_line(&window, frame_arena, lDAf, front);

    draw_line(&window, frame_arena, lABb, back);
    draw_line(&window, frame_arena, lBCb, back);
    draw_line(&window, frame_arena, lCDb, back);
    draw_line(&window, frame_arena, lDAb, back);

    draw_line(&window, frame_arena, lABfb, fb);
    draw_line(&window, frame_arena, lBCfb, fb);
    draw_line(&window, frame_arena, lCDfb, fb);
    draw_line(&window, frame_arena, lDAfb, fb);

    swap_buffers(&window);

    wapp_mem_arena_clear(frame_arena);
  }

  wapp_mem_arena_destroy(&frame_arena);
  close_window(&window);

  return EXIT_SUCCESS;
}