///|
/// Transport-neutral Debug Adapter Protocol session backed by MoonWren's live
/// debugger. Frontends queue commands before execution; every real stop is
/// retained as a DAP-style snapshot.
pub(all) struct DebugAdapterSession {
  mut breakpoints : Array[DebugBreakpoint]
  commands : Array[DebugCommand]
  snapshots : Array[DebugSnapshot]
  mut pause_on_entry : Bool
}

///|
pub fn DebugAdapterSession::new() -> DebugAdapterSession {
  { breakpoints: [], commands: [], snapshots: [], pause_on_entry: true, }
}

///|
pub fn DebugAdapterSession::set_breakpoints(
  self : DebugAdapterSession,
  source_name : String,
  lines : Array[Int],
) -> Array[DebugBreakpoint] {
  let retained : Array[DebugBreakpoint] = []
  for breakpoint in self.breakpoints {
    if breakpoint.source_name != source_name {
      retained.push(breakpoint)
    }
  }
  for line in lines {
    if line > 0 {
      retained.push(DebugBreakpoint::new(source_name, line))
    }
  }
  self.breakpoints = retained
  self.breakpoints
}

///|
pub fn DebugAdapterSession::set_pause_on_entry(
  self : DebugAdapterSession,
  enabled : Bool,
) -> Unit {
  self.pause_on_entry = enabled
}

///|
pub fn DebugAdapterSession::enqueue(
  self : DebugAdapterSession,
  command : DebugCommand,
) -> Unit {
  self.commands.push(command)
}

///|
pub fn DebugAdapterSession::clear_stops(self : DebugAdapterSession) -> Unit {
  self.snapshots.clear()
}

///|
pub fn DebugAdapterSession::stops(
  self : DebugAdapterSession,
) -> Array[DebugSnapshot] {
  self.snapshots.copy()
}

///|
pub fn DebugAdapterSession::attach(self : DebugAdapterSession, vm : Vm) -> Bool {
  vm.attach_debugger(self.breakpoints, self.pause_on_entry, fn(snapshot) {
    self.snapshots.push(snapshot)
    if self.commands.is_empty() {
      DebugContinue
    } else {
      self.commands.remove(0)
    }
  })
}

///|
pub fn DebugAdapterSession::detach(self : DebugAdapterSession, vm : Vm) -> Bool {
  ignore(self)
  vm.detach_debugger()
}