///|
pub(all) struct SimulationEngine {
  station : @topology.Station
  table : @interlocking.InterlockingTable
  detector : @conflict.ConflictDetector
  event_queue : PreallocatedEventQueue
  trains : Map[String, SimulatedTrain]
  mut current_cycle : Int64
  mut current_time_ms : Int64
  scan_period_ms : Int64
} derive(Debug)

///|
pub fn SimulationEngine::new(
  station : @topology.Station,
  table : @interlocking.InterlockingTable,
) -> SimulationEngine {
  let detector = @conflict.ConflictDetector::new(table)
  let queue = PreallocatedEventQueue::new(1024)
  {
    station,
    table,
    detector,
    event_queue: queue,
    trains: Map([]),
    current_cycle: 0,
    current_time_ms: 0,
    scan_period_ms: 10,
  }
}

///|
pub fn SimulationEngine::push_event(
  self : SimulationEngine,
  event : SimulationEvent,
) -> Bool {
  self.event_queue.push(event)
}

///|
pub fn SimulationEngine::register_train(
  self : SimulationEngine,
  train : SimulatedTrain,
) -> Unit {
  self.trains.set(train.train_id, train)
}

///|
pub fn SimulationEngine::audit(
  self : SimulationEngine,
) -> @interlocking.SafetyAuditReport {
  self.table.audit_safety(self.station)
}

///|
pub fn SimulationEngine::step_cycle_fast(
  self : SimulationEngine,
) -> CycleReport {
  self.current_cycle = self.current_cycle + 1
  self.current_time_ms = self.current_time_ms + self.scan_period_ms

  let mut events_processed = 0

  // 1. Process queued events
  while !self.event_queue.is_empty() {
    match self.event_queue.pop() {
      None => break
      Some(ev) => {
        events_processed = events_processed + 1
        match ev.event_type {
          EventRequestRoute =>
            match ev.route_id {
              Some(r_id) =>
                if self.detector.is_route_allowed_fast(self.table, r_id) {
                  let _ = self.table.request_and_lock_route_fast(
                    self.station,
                    r_id,
                  )
                }
              None => ()
            }
          EventCancelRoute =>
            match ev.route_id {
              Some(r_id) => {
                let _ = self.table.cancel_route(self.station, r_id)
              }
              None => ()
            }
          EventThrowSwitch =>
            match (ev.turnout_id, ev.target_position) {
              (Some(t_id), Some(pos)) => {
                let _ = self.station.set_turnout_position(t_id, pos)
              }
              _ => ()
            }
          EventOccupyTrack =>
            match ev.track_id {
              Some(tr_id) => {
                let _ = self.station.set_track_state(
                  tr_id,
                  Occupied,
                  ev.train_id,
                )
              }
              None => ()
            }
          EventClearTrack =>
            match ev.track_id {
              Some(tr_id) => {
                let _ = self.station.set_track_state(tr_id, Clear, "")
              }
              None => ()
            }
          EventInjectFault =>
            match ev.track_id {
              Some(tr_id) => {
                let _ = self.station.set_track_state(tr_id, Fault, "")
              }
              None => ()
            }
          EventClearFault =>
            match ev.track_id {
              Some(tr_id) => {
                let _ = self.station.set_track_state(tr_id, Clear, "")
              }
              None => ()
            }
          EventTrainStep => ()
        }
      }
    }
  }

  // 2. Advance simulated trains
  let delta_sec = Double::from_int(self.scan_period_ms.to_int()) / 1000.0
  for _, train in self.trains {
    if !train.is_finished {
      match self.table.get_rule(train.route_id) {
        Some(rule) =>
          match train.step_movement(delta_sec, rule, self.station) {
            Some(generated_ev) => {
              let _ = self.event_queue.push(generated_ev)
            }
            None => ()
          }
        None => ()
      }
    }
  }

  // 3. Process all route slots using fixed numeric traversal.
  let release_counters = self.process_active_routes_fast()

  // 4. Enforce fail-safe signal drops before reading the fixed scan summary.
  let emergency_actions = self.table.enforce_emergency_fail_safe(self.station)
  let safety_summary = self.table.scan_safety_summary(self.station)

  {
    cycle_count: self.current_cycle,
    events_processed,
    routes_active: self.table.active_slot_count(),
    safety_violations: safety_summary.fatal_count + safety_summary.warning_count,
    active_slots_scanned: release_counters.active_slots_scanned,
    sections_released: release_counters.sections_released,
    switches_released: release_counters.switches_released,
    emergency_actions,
    execution_micro_seconds: 0,
  }
}

///|
pub fn SimulationEngine::step_cycle(self : SimulationEngine) -> CycleReport {
  self.step_cycle_fast()
}