///|
pub(all) struct SimulatedTrain {
  train_id : String
  route_id : @interlocking.RouteId
  mut current_section_index : Int
  mut distance_in_current_section : Double
  speed_m_per_s : Double
  mut is_finished : Bool
} derive(Debug)

///|
pub fn SimulatedTrain::new(
  train_id : String,
  route_id : @interlocking.RouteId,
  speed_kmh : Double,
) -> SimulatedTrain {
  {
    train_id,
    route_id,
    current_section_index: 0,
    distance_in_current_section: 0.0,
    speed_m_per_s: speed_kmh / 3.6,
    is_finished: false,
  }
}

///|
pub fn SimulatedTrain::step_movement(
  self : SimulatedTrain,
  delta_time_seconds : Double,
  rule : @interlocking.InterlockingRule,
  station : @topology.Station,
) -> SimulationEvent? {
  if self.is_finished {
    return None
  }

  let sections = rule.track_sections
  if self.current_section_index >= sections.length() {
    self.is_finished = true
    return None
  }

  let current_track_id = sections[self.current_section_index]
  let current_track = match station.graph.get_track(current_track_id) {
    None => {
      self.is_finished = true
      return None
    }
    Some(tr) => tr
  }

  // Ensure initial occupation
  if self.distance_in_current_section == 0.0 && current_track.state != Occupied {
    let _ = station.set_track_state(current_track_id, Occupied, self.train_id)
    return Some({
      event_id: 0,
      event_type: EventOccupyTrack,
      route_id: Some(self.route_id),
      track_id: Some(current_track_id),
      turnout_id: None,
      target_position: None,
      train_id: self.train_id,
      timestamp_ms: 0,
    })
  }

  let advance_dist = self.speed_m_per_s * delta_time_seconds
  self.distance_in_current_section = self.distance_in_current_section +
    advance_dist

  if self.distance_in_current_section >= current_track.length_meters {
    // Train moves to next section
    let _ = station.set_track_state(current_track_id, Clear, "")
    self.current_section_index = self.current_section_index + 1
    self.distance_in_current_section = 0.0

    if self.current_section_index >= sections.length() {
      self.is_finished = true
      return Some({
        event_id: 0,
        event_type: EventClearTrack,
        route_id: Some(self.route_id),
        track_id: Some(current_track_id),
        turnout_id: None,
        target_position: None,
        train_id: self.train_id,
        timestamp_ms: 0,
      })
    } else {
      let next_track_id = sections[self.current_section_index]
      let _ = station.set_track_state(next_track_id, Occupied, self.train_id)
      return Some({
        event_id: 0,
        event_type: EventOccupyTrack,
        route_id: Some(self.route_id),
        track_id: Some(next_track_id),
        turnout_id: None,
        target_position: None,
        train_id: self.train_id,
        timestamp_ms: 0,
      })
    }
  }

  None
}