#ifndef _ENGINE_LOCAL_H_
#define _ENGINE_LOCAL_H_

// #include <tabula.h>
#include <stdarg.h>
#include <uchar.h>

#include <uv.h>

#include "gfx_cpp.h"
#include <GLFW/glfw3.h>

#include <alias/ecs.h>
#include <alias/log.h>
#include <alias/data_structure/inline_list.h>
#include <alias/data_structure/vector.h>
#include <alias/ui.h>

// cleanup some silly defines from windows
#if _WIN32
#undef near
#undef DrawText
#endif

#include <engine/engine.h>
#include <engine/render.h>
#include <engine/input.h>
#include <engine/transform.h>
#include <engine/ui.h>
#include <engine/state.h>
#include <engine/physics.h>
#include <engine/variable.h>

// global engine state
extern bool Engine__should_exit;

// gfx
struct BackendUIVertex {
  float xy[2];
  float rgba[4];
  float st[2];
};

enum BackendSampler { BackendSampler_NEAREST, BackendSampler_LINEAR, NUM_BACKEND_SAMPLERS };

struct BackendImage {
  uint32_t width;
  uint32_t height;
  uint32_t depth;

  uint32_t levels;
  uint32_t layers;

  uint32_t internal_format;

  union {
    struct {
      uint32_t image;
    } gl;
    struct {
      uint64_t image;
      uint64_t memory;
      uint64_t imageview;
    } vk;
  };
};

void BackendImage_load(struct BackendImage *, const char *path);
void BackendImage_unload(struct BackendImage *);

struct glProgram {
  GLuint vertex_shader;
  GLuint fragment_shader;
  GLuint program;
};

struct engine_render_PerFrame {
  uint32_t frame_index;
  float realtime_now;
  float realtime_delta;
  float simtime_now;
  float simtime_delta;
};

struct engine_render_PerView {
  float perspective_matrix[16];
  float view_matrix[16];
};

extern struct GL_ShaderResource run_render_per_frame;
extern struct GL_ShaderResource run_render_per_view;

void BackendUIVertex_begin_draw(uint32_t num_indexes, uint32_t **indexes_ptr, uint32_t num_vertexes,
                                struct BackendUIVertex **vertexes_ptr);
void BackendUIVertex_draw(struct BackendImage *image, uint32_t index_offset, uint32_t num_indexes);
void BackendUIVertex_end_draw(void);

void replacement_DrawText(const char *text, float x, float y, float size, alias_Color color);
void replacement_MeasureTextEx(const char *text, float size, float spacing, float *width, float *height);

// font
enum FontAtlasType { FontAtlasType_Bitmap, FontAtlasType_SDF };

struct FontGlyph {
  uint32_t codepoint;

  float advance;

  float plane_left;
  float plane_top;
  float plane_right;
  float plane_bottom;

  float atlas_left;
  float atlas_top;
  float atlas_right;
  float atlas_bottom;
};

struct Font {
  struct Image atlas;
  enum FontAtlasType atlas_type;
  uint32_t num_glyphs;
  const struct FontGlyph *glyphs;
};

void Font_draw(struct Font *font, const char *text, float x, float y, float size, float spacing, alias_Color color);
void Font_measure(struct Font *font, const char *text, float size, float spacing, float *width, float *height);

// resource
enum ResourceType { ResourceType_Invalid, ResourceType_Image };

struct LoadedResource {
  alias_InlineList list;

  enum ResourceType type;
  uint32_t id, gen;

  union {
    struct BackendImage image;
  };
};

void Engine__resources_gc(void);
void Engine__touch_resource(struct LoadedResource *resource);
struct LoadedResource *Engine__loaded_resource_by_id(uint32_t id);
struct LoadedResource *Engine__load_image(struct Image *img);

//
extern uv_loop_t run_libuv_loop;
extern alias_ecs_Instance *run_alias_ecs;
extern GLFWwindow *run_glfw_window;

void Engine__update_input(void);
void Engine__update_ui(void);
bool Engine__update_state(void);
void Engine__update_state_hud(void);
void Engine__update_physics(void);

#endif