#ifndef TEXTURES_INTERNAL_API_H
#define TEXTURES_INTERNAL_API_H

#include "../util.h"
#include "../textures/modes.h"
#include "../twn_engine_api.h"

#include <SDL2/SDL.h>
#include <stb_rect_pack.h>
#include <glad/glad.h>

#include <stdbool.h>

struct texture {
    t_frect srcrect;            /* position in atlas */
    SDL_Surface *data;          /* original image data */
    int atlas_index;
    GLuint loner_texture;       /* stored directly for loners, == 0 means atlas_index should be used */
    GLuint repeating_texture;   /* separately allocated texture, for loners == loner_texture */
    enum texture_mode mode;
};


struct texture_cache_item {
    char *key;
    struct texture value;
};


struct texture_cache {
    SDL_Window *window;          /* from context */

    struct texture_cache_item *hash;

    stbrp_node *node_buffer;     /* used internally by stb_rect_pack */

    SDL_Surface **atlas_surfaces;
    GLuint *atlas_textures;      /* shared by atlas textures */
    int atlas_index;             /* atlas that is currently being built */

    bool is_dirty;               /* current atlas needs to be recreated */
};

/* type safe structure for persistent texture handles */
typedef struct { uint16_t id; } t_texture_key;

/* tests whether given key structure corresponds to any texture */
#define m_texture_key_is_valid(p_key) ((p_key).id != (uint16_t)-1)

TWN_API void textures_cache_init(struct texture_cache *cache, SDL_Window *window);
TWN_API void textures_cache_deinit(struct texture_cache *cache);

/* for debugging */
TWN_API void textures_dump_atlases(struct texture_cache *cache);

/* loads an image if it isn't in the cache, otherwise a no-op. */
/* can be called from anywhere at any time after init, useful if you want to */
/* preload textures you know will definitely be used */
// void textures_load(struct texture_cache *cache, const char *path);

/* repacks the current texture atlas based on the texture cache if needed */
/* any previously returned srcrect results are invalidated after that */
/* call it every time before rendering */
TWN_API void textures_update_atlas(struct texture_cache *cache);

/* returns a persistent handle to some texture in cache, loading it if needed */
/* check the result with m_texture_key_is_valid() */
TWN_API t_texture_key textures_get_key(struct texture_cache *cache, const char *path);

/* returns a rect in a texture cache of the given key */
TWN_API t_frect textures_get_srcrect(const struct texture_cache *cache, t_texture_key key);

/* returns a rect of dimensions of the whole texture (whole atlas) */
TWN_API t_frect textures_get_dims(const struct texture_cache *cache, t_texture_key key);

/* returns an identifier that is equal for all textures placed in the same atlas */
TWN_API int32_t textures_get_atlas_id(const struct texture_cache *cache, t_texture_key key);

/* binds atlas texture in opengl state */
TWN_API void textures_bind(const struct texture_cache *cache, t_texture_key key, GLenum target);

/* binds texture in opengl state, ensuring that it's usable with texture repeat */
TWN_API void textures_bind_repeating(const struct texture_cache *cache, t_texture_key key, GLenum target);

/* returns helpful information about contents of alpha channel in given texture */
TWN_API enum texture_mode textures_get_mode(const struct texture_cache *cache, t_texture_key key);

/* returns the number of atlases in the cache */
TWN_API size_t textures_get_num_atlases(const struct texture_cache *cache);

/* TODO: should recieve texture_cache, get_key optimization cache should be cleared some other way */
TWN_API void textures_reset_state(void);

#endif
