#ifndef FFI_H
#define FFI_H

#include "cell.h"
#include "HandmadeMath.h"
#include "render.h"
#include "stb_ds.h"

#define JS_SetProperty(js, tar, str, val) JS_SetPropertyStr(js, tar, #str, val)
#define JS_GetProperty(js, tar, atom) JS_GetPropertyStr(js, tar, #atom)

// Core FFI functions
void ffi_load(JSContext *js);
int js_print_exception(JSContext *js, JSValue v);

// Global trace flag
extern int trace;

// Common type definitions - rect and colorf are defined in render.h

// Common conversion functions used across modules
JSValue rect2js(JSContext *js, rect r);
JSValue vec22js(JSContext *js, HMM_Vec2 v);
JSValue vec32js(JSContext *js, HMM_Vec3 v);
JSValue vec42js(JSContext *js, HMM_Vec4 v);
JSValue quat2js(JSContext *js, HMM_Quat q);
JSValue color2js(JSContext *js, colorf c);
JSValue number2js(JSContext *js, double d);
JSValue angle2js(JSContext *js, double a);

rect js2rect(JSContext *js, JSValue v);
HMM_Vec2 js2vec2(JSContext *js, JSValue v);
HMM_Vec3 js2vec3(JSContext *js, JSValue v);
HMM_Vec4 js2vec4(JSContext *js, JSValue v);
HMM_Quat js2quat(JSContext *js, JSValue v);
colorf js2color(JSContext *js, JSValue v);
double js2number(JSContext *js, JSValue v);
double js2angle(JSContext *js, JSValue v);

// Forward declaration for MTRand from prosperon.h
typedef struct tagMTRand MTRand;

// Random number generation functions
double genRand(MTRand *mrand);
int64_t genRandLong(MTRand *mrand);
void m_seedRand(MTRand *mrand, uint64_t seed);
double rand_range(JSContext *js, double min, double max);

// Common data structures
struct lrtb {
  float l;
  float r;
  float t;
  float b;
};
typedef struct lrtb lrtb;
typedef struct text_vert text_vert;

// Shader globals structure for camera transformations
#pragma pack(push, 1)
typedef struct shader_globals {
    HMM_Mat4 world_to_projection;
    HMM_Mat4 projection_to_world;
    HMM_Mat4 world_to_view;      
    HMM_Mat4 view_to_projection;
    HMM_Vec3 camera_pos_world;      
    HMM_Vec3 camera_dir_world;      
    float viewport_min_z;           
    float viewport_max_z;           
    HMM_Vec2 viewport_size;         
    HMM_Vec2 viewport_offset;       
    HMM_Vec2 render_size;           
    float time;                     
} shader_globals;
#pragma pack(pop)

// Common macros for property access
#define JS_GETPROP(JS, TARGET, VALUE, PROP, TYPE) {\
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#PROP); \
TARGET = js2##TYPE(JS, __##PROP##__v); \
JS_FreeValue(JS,__##PROP##__v); }\

#define JS_GETATOM(JS, TARGET, VALUE, ATOM, TYPE) {\
JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
TARGET = js2##TYPE(JS, __##PROP##__v); \
JS_FreeValue(JS,__##PROP##__v); }\

// Common conversion functions
lrtb js2lrtb(JSContext *js, JSValue v);
int js2bool(JSContext *js, JSValue v);
JSValue make_gpu_buffer(JSContext *js, void *data, size_t size, int type, int elements, int copy, int index);
JSValue make_quad_indices_buffer(JSContext *js, int quads);
JSValue quads_to_mesh(JSContext *js, text_vert *buffer);

// SDL type conversion functions  
SDL_Window *js2SDL_Window(JSContext *js, JSValue v);
JSValue SDL_Window2js(JSContext *js, SDL_Window *w);

#endif
