///|
pub(all) struct InteractiveRunner {
  engine : @simulator.SimulationEngine
} derive(Debug)

///|
pub fn InteractiveRunner::new(
  engine : @simulator.SimulationEngine,
) -> InteractiveRunner {
  { engine, }
}

///|
pub fn InteractiveRunner::execute_command(
  self : InteractiveRunner,
  cmd : String,
) -> String {
  let parts = cmd.split(" ").collect()
  if parts.length() == 0 {
    return "Empty command"
  }

  let op = parts[0].to_owned()
  match op {
    "status" => render_station_dashboard(self.engine)
    "request" =>
      if parts.length() < 2 {
        "Usage: request "
      } else {
        let r_id_int = match parse_int_custom(parts[1].to_owned()) {
          Some(v) => v
          None => return "Invalid route_id"
        }
        let r_id = @interlocking.RouteId::new(r_id_int)
        let ev = @simulator.SimulationEvent::{
          event_id: 1,
          event_type: EventRequestRoute,
          route_id: Some(r_id),
          track_id: None,
          turnout_id: None,
          target_position: None,
          train_id: "CLI_TRAIN",
          timestamp_ms: 0,
        }
        let _ = self.engine.push_event(ev)
        let report = self.engine.step_cycle()
        "Requested route #" +
        r_id_int.to_string() +
        ". Cycle report: Events=" +
        report.events_processed.to_string() +
        " ActiveRoutes=" +
        report.routes_active.to_string()
      }
    "cancel" =>
      if parts.length() < 2 {
        "Usage: cancel "
      } else {
        let r_id_int = match parse_int_custom(parts[1].to_owned()) {
          Some(v) => v
          None => return "Invalid route_id"
        }
        let r_id = @interlocking.RouteId::new(r_id_int)
        let ev = @simulator.SimulationEvent::{
          event_id: 2,
          event_type: EventCancelRoute,
          route_id: Some(r_id),
          track_id: None,
          turnout_id: None,
          target_position: None,
          train_id: "",
          timestamp_ms: 0,
        }
        let _ = self.engine.push_event(ev)
        let _ = self.engine.step_cycle()
        "Cancelled route #" + r_id_int.to_string()
      }
    "step" => {
      let count = if parts.length() >= 2 {
        match parse_int_custom(parts[1].to_owned()) {
          Some(v) => v
          None => return "Invalid step count"
        }
      } else {
        1
      }
      for i = 0; i < count; i = i + 1 {
        let _ = self.engine.step_cycle()
      }
      "Executed " + count.to_string() + " simulation 10ms cycles."
    }
    "audit" => {
      let report = self.engine.audit()
      "safety fatal=" +
      report.fatal_count.to_string() +
      " warning=" +
      report.warning_count.to_string() +
      " violations=" +
      report.violations().length().to_string() +
      " can_clear_signal=" +
      report.can_clear_signal.to_string()
    }
    "scenario" =>
      if parts.length() < 2 {
        "Usage: scenario "
      } else {
        match parts[1] {
          "standard" =>
            @scenarios.run_scenario(@scenarios.StandardRoute).render()
          "hostile" => @scenarios.run_scenario(@scenarios.HostileRoute).render()
          "fault" => @scenarios.run_scenario(@scenarios.FaultRecovery).render()
          "topology" =>
            @scenarios.run_scenario(@scenarios.InvalidTopology).render()
          _ => "Usage: scenario "
        }
      }
    "benchmark" => @benchmarks.run_fixed_benchmark().render()
    _ =>
      "Unknown command: " +
      op +
      ". Available: status, request, cancel, step, audit, scenario, benchmark"
  }
}

///|
fn parse_int_custom(s : String) -> Int? {
  let mut acc = 0
  for ch in s {
    if ch >= '0' && ch <= '9' {
      acc = acc * 10 + (ch.to_int() - '0'.to_int())
    } else {
      return None
    }
  }
  Some(acc)
}