/*
** task.h - Task scheduler
**
** See Copyright Notice in mruby.h
*/

#ifndef MRUBY_TASK_H
#define MRUBY_TASK_H

#include <mruby.h>

/*
 * Task status values (bit-mapped)
 */
enum {
  MRB_TASK_STATUS_DORMANT   = 0x00,  /* Not started or finished */
  MRB_TASK_STATUS_READY     = 0x02,  /* Ready to run */
  MRB_TASK_STATUS_RUNNING   = 0x03,  /* Currently executing */
  MRB_TASK_STATUS_WAITING   = 0x04,  /* Waiting for condition */
  MRB_TASK_STATUS_SUSPENDED = 0x08,  /* Manually suspended */
};

/*
 * Task wait reason
 */
enum {
  MRB_TASK_REASON_NONE  = 0x00,  /* No specific reason */
  MRB_TASK_REASON_SLEEP = 0x01,  /* Sleeping for time */
  MRB_TASK_REASON_MUTEX = 0x02,  /* Waiting for mutex (reserved) */
  MRB_TASK_REASON_JOIN  = 0x04,  /* Waiting for another task */
  MRB_TASK_REASON_QUEUE = 0x08,  /* Waiting for queue item */
};

struct mrb_task_queue;

/*
 * Task structure - represents a single task in the scheduler
 *
 * Memory-optimized layout:
 * - Removed priority_preemption (always equals priority): 1 byte
 * - Removed started flag (inferred from c.status): 1 byte
 * - Unified wakeup_tick/join/mutex into single union: 4 bytes
 * - Removed redundant proc field (stored in c.ci->proc): 8 bytes
 * Total savings: ~18 bytes per task (14% reduction)
 */
typedef struct mrb_task {
  struct mrb_task *next;           /* Linked list pointer */
  uint8_t priority;                /* Priority (0-255, 0=highest) */
  uint8_t status;                  /* Current status (TASKSTATUS enum) */
  uint8_t reason;                  /* Wait reason (TASKREASON enum) */
  volatile uint8_t timeslice;      /* Remaining ticks while RUNNING */
  mrb_value name;                  /* Optional task name */

  /* Wait-specific data - mutually exclusive based on reason field */
  union {
    uint32_t wakeup_tick;          /* Tick count to wake up (REASON_SLEEP) */
    const struct mrb_task *join;   /* Task being waited on (REASON_JOIN) */
    void *mutex;                   /* Mutex pointer (REASON_MUTEX, reserved) */
    struct mrb_task_queue *queue;  /* Queue being waited on (REASON_QUEUE) */
  } wait;

  mrb_value self;                  /* Ruby Task object reference */

  mrb_value result;                /* Task return value */

  struct mrb_context c;            /* Execution context (stack, callinfo, etc) */
} mrb_task;

/*
 * Task queue configuration
 * (mrb_task_state is defined in mruby.h)
 */
#define MRB_NUM_TASK_QUEUE 4

/* Queue indices */
#define MRB_TASK_QUEUE_DORMANT   0
#define MRB_TASK_QUEUE_READY     1
#define MRB_TASK_QUEUE_WAITING   2
#define MRB_TASK_QUEUE_SUSPENDED 3

/* Configuration */
#ifndef MRB_TICK_UNIT
#define MRB_TICK_UNIT 4  /* Tick period in milliseconds */
#endif

#ifndef MRB_TIMESLICE_TICK_COUNT
#define MRB_TIMESLICE_TICK_COUNT 3  /* Number of ticks per timeslice */
#endif

#define TASK_STACK_INIT_SIZE 64   /* Initial task stack size */
#define TASK_CI_INIT_SIZE 4       /* Initial task callinfo size */

/*
 * HAL (Hardware Abstraction Layer) functions are declared in task_hal.h.
 */

/*
 * GC integration
 */
void mrb_task_mark_all(mrb_state *mrb);

/*
 * Core task scheduler API
 */
MRB_API void mrb_tick(mrb_state *mrb);
MRB_API mrb_value mrb_task_run(mrb_state *mrb);
MRB_API mrb_value mrb_task_run_once(mrb_state *mrb);

/*
 * Task creation API
 */
MRB_API mrb_value mrb_create_task(mrb_state *mrb, struct RProc *proc, mrb_value name, mrb_value priority, mrb_value top_self);

/*
 * Synchronous execution API (for picoruby-wasm)
 */
MRB_API mrb_value mrb_execute_proc_synchronously(mrb_state *mrb, mrb_value proc, mrb_int argc, const mrb_value *argv);

/*
 * Task control API
 * Note: mrb_task_run is the main scheduler loop (for picoruby-sandbox and picoruby-wasm)
 */
MRB_API void mrb_suspend_task(mrb_state *mrb, mrb_value task);
MRB_API void mrb_resume_task(mrb_state *mrb, mrb_value task);
MRB_API void mrb_terminate_task(mrb_state *mrb, mrb_value task);
MRB_API mrb_bool mrb_stop_task(mrb_state *mrb, mrb_value task);
MRB_API mrb_value mrb_task_value(mrb_state *mrb, mrb_value task);
MRB_API mrb_value mrb_task_status(mrb_state *mrb, mrb_value self);

/*
 * Task context management API (for picoruby-sandbox)
 */
MRB_API void mrb_task_init_context(mrb_state *mrb, mrb_value task, struct RProc *proc);
MRB_API void mrb_task_reset_context(mrb_state *mrb, mrb_value task);
MRB_API void mrb_task_proc_set(mrb_state *mrb, mrb_value task, struct RProc *proc);

/*
 * Internal helpers - used by task.c and task_queue.c
 */
#include <stddef.h>
#include "task_hal.h"

/* Scheduler state accessors (require a local mrb variable in scope) */
#define q_dormant_   (mrb->task.queues[MRB_TASK_QUEUE_DORMANT])
#define q_ready_     (mrb->task.queues[MRB_TASK_QUEUE_READY])
#define q_waiting_   (mrb->task.queues[MRB_TASK_QUEUE_WAITING])
#define q_suspended_ (mrb->task.queues[MRB_TASK_QUEUE_SUSPENDED])
#define tick_        (mrb->task.tick)
#define wakeup_tick_ (mrb->task.wakeup_tick)
#define switching_   (mrb->task.switching)

/* Recover the mrb_task that owns the current mruby context */
#define MRB2TASK(mrb) ((mrb_task *)((uint8_t *)(mrb)->c - offsetof(mrb_task, c)))

/* Raise if the scheduler is locked (synchronous execution in progress) */
static inline void
task_check_scheduler_lock(mrb_state *mrb)
{
  if (mrb->task.scheduler_lock > 0) {
    mrb_raise(mrb, E_RUNTIME_ERROR, "Cannot use asynchronous Task API during synchronous execution");
  }
}

/* Priority-queue insert/delete - defined in task.c */
void mrb_task_q_insert(mrb_state *mrb, mrb_task *t);
void mrb_task_q_delete(mrb_state *mrb, mrb_task *t);

/* Task::Queue class registration - defined in task_queue.c */
void mrb_init_task_queue(mrb_state *mrb, struct RClass *task_class);

#endif /* MRUBY_TASK_H */
