
#include <pthread.h>
#include <stdatomic.h>

/* 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 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
#define ACTOR_REFRESHED 6 // GC finished, ready to resume

// #define ACTOR_TRACE

#define ACTOR_FAST_TIMER_NS     (10ULL * 1000000)      // 10ms per turn
#define ACTOR_SLOW_TIMER_NS     (5000ULL * 1000000)    // 5s for slow actors
#define ACTOR_SLOW_STRIKES_MAX  3                       // consecutive slow turns -> kill
#define ACTOR_MEMORY_LIMIT      (16ULL * 1024 * 1024)  // 16MB heap cap

typedef struct cell_rt {
  JSContext *context;

  /* JSValues on the GC heap — each paired with a JSGCRef so the
     Cheney GC can relocate them during compaction. */
  JSGCRef idx_buffer_ref;
  JSGCRef on_exception_ref;
  JSGCRef message_handle_ref;
  JSGCRef unneeded_ref;
  JSGCRef actor_sym_ref;

  void *init_wota;

  /* Protects JSContext usage */
  pthread_mutex_t *mutex; /* for everything else */
  pthread_mutex_t *msg_mutex; /* For message queue and timers queue */

  char *id;

  int idx_count;

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

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

  int state;
  uint32_t ar;  // timer for unneeded
  double ar_secs;  // time for unneeded

  int disrupt;
  int is_quiescent;  // tracked by scheduler for quiescence detection
  int main_thread_only;
  int affinity;

  uint64_t turn_start_ns;       // cell_ns() when turn began
  _Atomic uint32_t turn_gen;    // incremented each turn start
  int slow_strikes;             // consecutive slow-completed turns
  int vm_suspended;             // 1 if VM is paused mid-turn

  const char *name; // human friendly name
  cell_hook trace_hook;
} cell_rt;

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);
const char *register_actor(const char *id, cell_rt *actor, int mainthread, double ar);
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);

void set_actor_state(cell_rt *actor);
void enqueue_actor_priority(cell_rt *actor);
void actor_clock(cell_rt *actor, JSValue fn);
uint32_t actor_delay(cell_rt *actor, JSValue fn, double seconds);
JSValue actor_remove_timer(cell_rt *actor, uint32_t timer_id);
void exit_handler(void);
void actor_loop();
void actor_initialize(void);
void actor_free(cell_rt *actor);
int scheduler_actor_count(void);
void scheduler_enable_quiescence(void);

JSValue JS_ResumeRegisterVM(JSContext *ctx);

uint64_t cell_ns();
void cell_sleep(double seconds);
int randombytes(void *buf, size_t n);
