// CoreSignal - internal reactive value primitive
// alien-signals style API

///|
/// Create a new core signal with initial value
pub fn[T] core_signal(initial : T) -> CoreSignal[T] {
  {
    node: ReactiveNode::new(ReactiveFlags::Mutable.to_int()),
    current_value: initial,
    pending_value: initial,
  }
}

///|
/// Get the current value of a core signal
/// Automatically tracks dependency if called inside an effect/computed
pub fn[T] CoreSignal::get(self : CoreSignal[T]) -> T {
  let flags = self.node.flags.get_value()
  let dirty_flag = ReactiveFlags::Dirty.to_int()

  // If dirty, update current from pending
  if (flags & dirty_flag) != 0 {
    if not(physical_equal(self.current_value, self.pending_value)) {
      self.current_value = self.pending_value
      if self.node.subs is Some(subs) {
        shallow_propagate(subs)
      }
    }
    self.node.flags.set_value(ReactiveFlags::Mutable.to_int())
  }

  // Track dependency
  let mut found_sub = get_active_sub()
  while found_sub is Some(s) {
    let sub_flags = s.flags.get_value()
    let mutable_flag = ReactiveFlags::Mutable.to_int()
    let watching_flag = ReactiveFlags::Watching.to_int()
    if (sub_flags & (mutable_flag | watching_flag)) != 0 {
      link(self.node, s, get_cycle())
      break
    }
    found_sub = match s.subs {
      Some(subs) => Some(subs.sub)
      None => None
    }
  }
  self.current_value
}

///|
/// Set a new value for the core signal
/// Notifies all subscribers if value changed
pub fn[T] CoreSignal::set(self : CoreSignal[T], value : T) -> Unit {
  if not(physical_equal(self.pending_value, value)) {
    self.pending_value = value
    // Track when this signal was modified for diamond dependency resolution
    inc_cycle()
    self.node.last_modified_cycle = get_cycle()
    self.node.flags.set_value(
      ReactiveFlags::Mutable.to_int() | ReactiveFlags::Dirty.to_int(),
    )
    if self.node.subs is Some(subs) {
      propagate(subs)
      if get_batch_depth() == 0 {
        flush()
      }
    }
  }
}

///|
/// Update core signal value using a function
pub fn[T] CoreSignal::update(self : CoreSignal[T], f : (T) -> T) -> Unit {
  self.set(f(self.get()))
}

///|
/// Get value without tracking (peek)
/// Returns the latest value (pending if dirty, otherwise current)
pub fn[T] CoreSignal::peek(self : CoreSignal[T]) -> T {
  let flags = self.node.flags.get_value()
  let dirty_flag = ReactiveFlags::Dirty.to_int()
  if (flags & dirty_flag) != 0 {
    self.pending_value
  } else {
    self.current_value
  }
}

///|
/// Get number of subscribers (for debugging)
pub fn[T] CoreSignal::subscriber_count(self : CoreSignal[T]) -> Int {
  let mut count = 0
  let mut lnk = self.node.subs
  while lnk is Some(l) {
    count = count + 1
    lnk = l.next_sub
  }
  count
}

///|
/// Clear all subscribers
pub fn[T] CoreSignal::clear_subscribers(self : CoreSignal[T]) -> Unit {
  // Unlink all subs
  let mut lnk = self.node.subs
  while lnk is Some(l) {
    let next = l.next_sub
    let _ = unlink(l, l.sub)
    lnk = next
  }
  self.node.subs = None
  self.node.subs_tail = None
}