// GC Trait Abstractions for Wasmoon
//
// This module defines two core traits for GC runtime:
// 1. GcHeap - Low-level object storage and access
// 2. GcRuntime - Runtime GC coordination (barriers, collection)
//
// GcCompiler belongs to the runtime boundary because it depends on GC state.

// ============================================================
// GcHeap - Object Storage Layer
// ============================================================
//
// Responsible for:
// - Allocating struct and array objects
// - Accessing object fields and elements
// - Tracking object types
//
// Implementations:
// - MarkSweepHeap: Simple mark-sweep with tombstones
// - CopyingHeap: Semi-space copying collector
// - BumpAllocHeap: Fast bump allocation, no collection (for arenas)

///|
/// Low-level GC heap interface for object storage
pub(open) trait GcHeap {
  // === Allocation ===

  /// Allocate a struct with given type index and field values
  /// Returns the object reference index
  fn alloc_struct(Self, Int32, Array[@types.Value]) -> Int32 raise RuntimeError

  /// Allocate an array with given type index and elements
  /// Returns the object reference index
  fn alloc_array(Self, Int32, Array[@types.Value]) -> Int32 raise RuntimeError

  // === Object Access ===

  /// Get a struct field value
  fn struct_get(Self, Int32, Int32) -> @types.Value raise RuntimeError

  /// Set a struct field value
  fn struct_set(Self, Int32, Int32, @types.Value) -> Unit raise RuntimeError

  /// Get array length
  fn array_len(Self, Int32) -> Int32 raise RuntimeError

  /// Get an array element
  fn array_get(Self, Int32, Int32) -> @types.Value raise RuntimeError

  /// Set an array element
  fn array_set(Self, Int32, Int32, @types.Value) -> Unit raise RuntimeError

  /// Fill array elements with a value
  fn array_fill(Self, Int32, Int32, @types.Value, Int32) -> Unit raise RuntimeError

  /// Copy elements between arrays
  fn array_copy(Self, Int32, Int32, Int32, Int32, Int32) -> Unit raise RuntimeError

  // === Type Information ===

  /// Get the type index of an object
  fn get_type_idx(Self, Int32) -> Int32 raise RuntimeError

  /// Check if an object reference is valid and alive
  fn is_valid(Self, Int32) -> Bool
}

// ============================================================
// GcRuntime - Runtime GC Coordination
// ============================================================
//
// Responsible for:
// - Triggering garbage collection
// - Managing roots (stack, globals)
// - Write/read barriers for incremental/concurrent GC
// - GC statistics and tuning
//
// Implementations:
// - StopTheWorldRuntime: Simple stop-the-world collection
// - IncrementalRuntime: Incremental collection with write barriers
// - NoGcRuntime: Never collect (for short-lived programs)

///|
/// GC statistics
pub struct GcStats {
  /// Total allocated objects (including freed slots)
  total_slots : Int32
  /// Currently live objects
  live_objects : Int32
  /// Free slots available for reuse
  free_slots : Int32
  /// Number of GC cycles performed
  collections : Int32
  /// Total bytes allocated (if tracked)
  bytes_allocated : Int64
  /// Total bytes collected (if tracked)
  bytes_collected : Int64
} derive(Debug)

///|
/// Runtime GC coordination interface
pub(open) trait GcRuntime {
  // === Collection Control ===

  /// Check if GC should be triggered (called after allocation)
  fn should_collect(Self) -> Bool

  /// Perform garbage collection with given roots
  /// Roots are values from stack and globals that keep objects alive
  fn collect(Self, Array[@types.Value]) -> Unit

  /// Force a full GC cycle regardless of threshold
  fn force_collect(Self, Array[@types.Value]) -> Unit

  // === Barriers (for incremental/concurrent GC) ===

  /// Write barrier: called BEFORE writing a reference field
  /// For simple stop-the-world GC, this is a no-op
  /// For incremental GC, this maintains the tri-color invariant
  ///
  /// obj_idx: object being modified
  /// old_value: current value (being overwritten)
  /// new_value: new value being stored
  fn write_barrier_pre(Self, Int32, @types.Value, @types.Value) -> Unit

  /// Write barrier: called AFTER writing a reference field
  /// Used by some GC algorithms (e.g., remembered sets)
  fn write_barrier_post(Self, Int32, @types.Value) -> Unit

  /// Read barrier: called before reading a reference field
  /// For most GCs, this is a no-op
  /// For concurrent compacting GC, this handles forwarding
  fn read_barrier(Self, Int32) -> @types.Value

  // === Statistics ===

  /// Get GC statistics
  fn stats(Self) -> GcStats

  /// Get number of collections performed
  fn collection_count(Self) -> Int32

  /// Set the collection threshold (interpretation depends on implementation)
  fn set_threshold(Self, Int32) -> Unit

  /// Get current threshold
  fn get_threshold(Self) -> Int32
}

// ============================================================
// Combined GC Manager
// ============================================================
//
// Combines heap and runtime into a unified interface.
// This is what Store will use.

///|
/// Combined GC manager interface
pub(open) trait GcManager {
  // === Heap Operations (delegated) ===
  fn alloc_struct(Self, Int32, Array[@types.Value]) -> Int32 raise RuntimeError
  fn alloc_array(Self, Int32, Array[@types.Value]) -> Int32 raise RuntimeError
  fn struct_get(Self, Int32, Int32) -> @types.Value raise RuntimeError
  fn struct_set(Self, Int32, Int32, @types.Value) -> Unit raise RuntimeError
  fn array_len(Self, Int32) -> Int32 raise RuntimeError
  fn array_get(Self, Int32, Int32) -> @types.Value raise RuntimeError
  fn array_set(Self, Int32, Int32, @types.Value) -> Unit raise RuntimeError
  fn array_fill(Self, Int32, Int32, @types.Value, Int32) -> Unit raise RuntimeError
  fn array_copy(Self, Int32, Int32, Int32, Int32, Int32) -> Unit raise RuntimeError
  fn get_type_idx(Self, Int32) -> Int32 raise RuntimeError
  fn is_valid(Self, Int32) -> Bool

  // === Runtime Operations (delegated) ===
  fn should_collect(Self) -> Bool
  fn collect(Self, Array[@types.Value]) -> Unit
  fn stats(Self) -> GcStats

  // === Barriers ===
  fn write_barrier(Self, Int32, @types.Value, @types.Value) -> Unit
}