///|
/// A scheduled simulation event.
///
/// Events are ordered by tick, priority, then id. The id tie-breaker makes
/// same-tick execution stable and replayable.
pub(all) struct ScheduledEvent {
  id : Int
  tick : Int
  priority : Int
  name : String
  mut cancelled : Bool
  repeat_every : Int
  remaining_runs : Int
}

///|
pub fn ScheduledEvent::new(
  id : Int,
  tick : Int,
  name : String,
  priority? : Int = 0,
) -> ScheduledEvent {
  {
    id,
    tick,
    priority,
    name,
    cancelled: false,
    repeat_every: 0,
    remaining_runs: 1,
  }
}

///|
pub fn ScheduledEvent::repeating(
  id : Int,
  tick : Int,
  name : String,
  every : Int,
  times : Int,
  priority? : Int = 0,
) -> ScheduledEvent {
  {
    id,
    tick,
    priority,
    name,
    cancelled: false,
    repeat_every: if every < 1 {
      1
    } else {
      every
    },
    remaining_runs: if times < 1 {
      1
    } else {
      times
    },
  }
}

///|
pub fn ScheduledEvent::is_cancelled(self : ScheduledEvent) -> Bool {
  self.cancelled
}

///|
pub fn ScheduledEvent::cancel(self : ScheduledEvent) -> Unit {
  self.cancelled = true
}

///|
pub fn ScheduledEvent::is_repeating(self : ScheduledEvent) -> Bool {
  self.repeat_every > 0 && self.remaining_runs > 1
}

///|
pub fn ScheduledEvent::next_repeat(self : ScheduledEvent) -> ScheduledEvent {
  {
    id: self.id,
    tick: self.tick + self.repeat_every,
    priority: self.priority,
    name: self.name,
    cancelled: false,
    repeat_every: self.repeat_every,
    remaining_runs: self.remaining_runs - 1,
  }
}

///|
pub fn compare_event(a : ScheduledEvent, b : ScheduledEvent) -> Int {
  let tick_order = a.tick.compare(b.tick)
  if tick_order != 0 {
    tick_order
  } else {
    let priority_order = a.priority.compare(b.priority)
    if priority_order != 0 {
      priority_order
    } else {
      a.id.compare(b.id)
    }
  }
}