#ifndef PROSPERON_H
#define PROSPERON_H

#include <SDL3/SDL.h>
#include "quickjs.h"
#include "qjs_macros.h"
#include "qjs_blob.h"
#include "blob.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef HAVE_MIMALLOC
typedef struct mi_heap_s mi_heap_t;
#endif

/* Letter type for unified message queue */
typedef enum {
  LETTER_BLOB,     /* Blob message */
  LETTER_CALLBACK  /* JSValue callback function */
} letter_type;

typedef struct letter {
  letter_type type;
  union {
    blob *blob_data;   /* For LETTER_BLOB */
    JSValue callback;  /* For LETTER_CALLBACK */
  };
} letter;

#define STATE_VECTOR_LENGTH 312
#define STATE_VECTOR_M      156

#define ACTOR_IDLE      0 // Actor not doing anything
#define ACTOR_READY     1 // Actor ready for a turn
#define ACTOR_RUNNING   2 // Actor taking a turn
#define ACTOR_EXHAUSTED 3 // Actor waiting for GC
#define ACTOR_RECLAIMING 4 // Actor running GC
#define ACTOR_SLOW      5 // Actor going slowly; deprioritize

typedef JSValue (*MODULEFN)(JSContext *js);

extern int tracy_profiling_enabled;

typedef struct tagMTRand {
  uint64_t mt[STATE_VECTOR_LENGTH];
  int32_t index;
} MTRand;

typedef struct {
  const char *name;
  MODULEFN fn;
} ModuleEntry;

typedef struct cell_rt {
  JSContext *context;
#ifdef HAVE_MIMALLOC
mi_heap_t *heap;
#endif
  JSValue idx_buffer;
  JSValue on_exception;
  JSValue message_handle;

  void *init_wota;

  ModuleEntry *module_registry;
  
  /* Protects JSContext usage */
  SDL_Mutex *mutex; /* for everything else */
  SDL_Mutex *msg_mutex; /* For message queue and timers queue */
  
  char *id;
  MTRand mrand;

  int idx_count;

  /* The “mailbox” for incoming messages + a dedicated lock for it: */
  struct letter *letters;

  /* CHANGED FOR EVENTS: a separate lock for the actor->events queue */
  struct { Uint32 key; JSValue value; } *timers;

  int state;
  Uint32 ar;  // timer for unneeded
  double ar_secs;  // time for unneeded
  JSValue unneeded;  // fn to call before unneeded
    
  int disrupt;
  int main_thread_only;
  int affinity;
  
  JSAtom actor_sym;
  
  const char *name; // human friendly name
} cell_rt;

extern SDL_TLSID prosperon_id;

extern cell_rt *root_cell; // first actor in the system

cell_rt *create_actor(void *wota);
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
void actor_disrupt(cell_rt *actor);

const char *send_message(const char *id, void *msg);
Uint32 actor_timer_cb(cell_rt *actor, SDL_TimerID id, Uint32 interval);
JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv);
JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv);
void actor_unneeded(cell_rt *actor, JSValue fn, double seconds);
void script_startup(cell_rt *rt);
int uncaught_exception(JSContext *js, JSValue v);
int actor_exists(const char *id);
cell_rt *get_actor(char *id);
void set_actor_state(cell_rt *actor);
void actor_clock(cell_rt *actor, JSValue fn);

int JS_ArrayLength(JSContext *js, JSValue a);

int prosperon_mount_core(void);

#ifdef __cplusplus
}
#endif

#endif
