// alien-signals style reactive system for MoonBit
// Based on https://github.com/stackblitz/alien-signals

///|
/// Reactive flags for tracking node state
pub(all) enum ReactiveFlags {
  None = 0 // 0
  Mutable = 1 // 1 - Can be updated (signal/computed)
  Watching = 2 // 2 - Effect is watching
  RecursedCheck = 4 // 4 - Checking for recursion
  Recursed = 8 // 8 - Recursion detected
  Dirty = 16 // 16 - Value is stale
  Pending = 32 // 32 - Dependencies may have changed
}

///|
/// Convert flags to int for bitwise operations
pub fn ReactiveFlags::to_int(self : ReactiveFlags) -> Int {
  match self {
    None => 0
    Mutable => 1
    Watching => 2
    RecursedCheck => 4
    Recursed => 8
    Dirty => 16
    Pending => 32
  }
}

///|
/// Bitwise flag set
pub(all) struct Flags {
  mut value : Int
}

///|
pub fn Flags::new(initial : Int) -> Flags {
  { value: initial }
}

///|
pub fn Flags::has(self : Flags, flag : ReactiveFlags) -> Bool {
  (self.value & flag.to_int()) != 0
}

///|
pub fn Flags::set(self : Flags, flag : ReactiveFlags) -> Unit {
  self.value = self.value | flag.to_int()
}

///|
pub fn Flags::unset(self : Flags, flag : ReactiveFlags) -> Unit {
  self.value = self.value & (flag.to_int() ^ -1)
}

///|
pub fn Flags::has_any(self : Flags, flags : Array[ReactiveFlags]) -> Bool {
  let mask = flags.fold(init=0, fn(acc, f) { acc | f.to_int() })
  (self.value & mask) != 0
}

///|
pub fn Flags::set_value(self : Flags, v : Int) -> Unit {
  self.value = v
}

///|
pub fn Flags::get_value(self : Flags) -> Int {
  self.value
}

///|
/// Double-linked list node connecting dependencies and subscribers
pub(all) struct Link {
  mut version : Int
  dep : ReactiveNode
  sub : ReactiveNode
  mut prev_sub : Link?
  mut next_sub : Link?
  mut prev_dep : Link?
  mut next_dep : Link?
}

///|
/// Base reactive node - can be signal, computed, or effect
pub(all) struct ReactiveNode {
  mut deps : Link? // First dependency link
  mut deps_tail : Link? // Last dependency link
  mut subs : Link? // First subscriber link
  mut subs_tail : Link? // Last subscriber link
  flags : Flags
  mut last_modified_cycle : Int // Track when value was last modified
  mut effect_callback : (() -> Unit)? // Callback for effect re-run
}

///|
pub fn ReactiveNode::new(flags : Int) -> ReactiveNode {
  {
    deps: None,
    deps_tail: None,
    subs: None,
    subs_tail: None,
    flags: Flags::new(flags),
    last_modified_cycle: 0,
    effect_callback: None,
  }
}

///|
/// CoreSignal - internal reactive value container (use Signal for public API)
pub(all) struct CoreSignal[T] {
  node : ReactiveNode
  mut current_value : T
  mut pending_value : T
}

///|
/// Computed node - derives value from dependencies (internal)
pub(all) struct Computed[T] {
  node : ReactiveNode
  mut value : T?
  getter : () -> T
}

///|
/// Effect node - runs side effects
pub(all) struct EffectNode {
  node : ReactiveNode
  run_fn : () -> Unit
}