///|
/// OS capability descriptors for Lockwire backend profile gates.

///|
pub fn package_id() -> String {
  "lockwire/os"
}

///|
pub(all) enum CapabilityProfile {
  ProfileSimNative
  ProfileSimWasm
  ProfileReplay
  ProfileNativeReal
  ProfileRealLinux
  ProfileRealEmbedded
} derive(Eq, Debug)

///|
pub fn CapabilityProfile::label(self : CapabilityProfile) -> String {
  match self {
    ProfileSimNative => "sim-native"
    ProfileSimWasm => "sim-wasm"
    ProfileReplay => "replay"
    ProfileNativeReal => "native-real"
    ProfileRealLinux => "real-linux"
    ProfileRealEmbedded => "real-embedded"
  }
}

///|
pub fn capability_profiles() -> Array[CapabilityProfile] {
  [
    ProfileSimNative,
    ProfileSimWasm,
    ProfileReplay,
    ProfileNativeReal,
    ProfileRealLinux,
    ProfileRealEmbedded,
  ]
}

///|
pub fn CapabilityProfile::is_deterministic(self : CapabilityProfile) -> Bool {
  match self {
    ProfileSimNative | ProfileSimWasm | ProfileReplay => true
    ProfileNativeReal | ProfileRealLinux | ProfileRealEmbedded => false
  }
}

///|
pub(all) enum OsCapabilityKind {
  OsVirtualClock
  OsNativeClock
  OsVirtualTimer
  OsFileDescriptor
  OsEventLoop
  OsUdpSocket
  OsRawNic
  OsPacketCapture
  OsNativeStub
} derive(Eq, Debug)

///|
pub fn OsCapabilityKind::label(self : OsCapabilityKind) -> String {
  match self {
    OsVirtualClock => "virtual-clock"
    OsNativeClock => "native-clock"
    OsVirtualTimer => "virtual-timer"
    OsFileDescriptor => "file-descriptor"
    OsEventLoop => "event-loop"
    OsUdpSocket => "udp-socket"
    OsRawNic => "raw-nic"
    OsPacketCapture => "packet-capture"
    OsNativeStub => "native-stub"
  }
}

///|
pub(all) struct OsCapabilityDescriptor {
  id : String
  kind : OsCapabilityKind
  profiles : Array[CapabilityProfile]
  requires_native : Bool
  requires_c_ffi : Bool
  requires_os_fd : Bool
  requires_raw_nic : Bool
  deterministic : Bool
  live_io : Bool
  reference_path : String
} derive(Eq, Debug)

///|
pub fn OsCapabilityDescriptor::supports_profile(
  self : OsCapabilityDescriptor,
  profile : CapabilityProfile,
) -> Bool {
  self.profiles.any(fn(item) { item == profile })
}

///|
pub fn OsCapabilityDescriptor::violates_wasm_boundary(
  self : OsCapabilityDescriptor,
) -> Bool {
  self.supports_profile(ProfileSimWasm) &&
  (self.requires_c_ffi || self.requires_raw_nic || self.live_io)
}

///|
pub fn OsCapabilityDescriptor::is_real_io(
  self : OsCapabilityDescriptor,
) -> Bool {
  self.live_io || self.requires_raw_nic || self.requires_os_fd
}

///|
pub(all) struct OsCapabilityReport {
  catalog_count : Int
  sim_native_count : Int
  sim_wasm_count : Int
  native_real_count : Int
  real_linux_count : Int
  raw_nic_live_count : Int
  deterministic_non_live_count : Int
  c_ffi_count : Int
  wasm_violation_count : Int
} derive(Eq, Debug)

///|
pub fn OsCapabilityReport::passes(self : OsCapabilityReport) -> Bool {
  self.catalog_count >= 9 &&
  self.sim_native_count >= 2 &&
  self.sim_wasm_count >= 2 &&
  self.native_real_count >= 4 &&
  self.real_linux_count >= 3 &&
  self.raw_nic_live_count >= 2 &&
  self.deterministic_non_live_count >= 2 &&
  self.c_ffi_count >= 4 &&
  self.wasm_violation_count == 0
}

///|
pub fn os_capability_catalog() -> Array[OsCapabilityDescriptor] {
  [
    {
      id: "os.clock.virtual",
      kind: OsVirtualClock,
      profiles: [ProfileSimNative, ProfileSimWasm, ProfileReplay],
      requires_native: false,
      requires_c_ffi: false,
      requires_os_fd: false,
      requires_raw_nic: false,
      deterministic: true,
      live_io: false,
      reference_path: "lockwire/clock/clock.mbt",
    },
    {
      id: "os.timer.virtual",
      kind: OsVirtualTimer,
      profiles: [ProfileSimNative, ProfileSimWasm, ProfileReplay],
      requires_native: false,
      requires_c_ffi: false,
      requires_os_fd: false,
      requires_raw_nic: false,
      deterministic: true,
      live_io: false,
      reference_path: "lockwire/scenario/scenario.mbt",
    },
    {
      id: "os.clock.native_highres",
      kind: OsNativeClock,
      profiles: [ProfileNativeReal, ProfileRealLinux],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: false,
      requires_raw_nic: false,
      deterministic: false,
      live_io: false,
      reference_path: "lockwire/driver/native/stub_clock.c",
    },
    {
      id: "os.native_stub.loader",
      kind: OsNativeStub,
      profiles: [ProfileNativeReal, ProfileRealLinux],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: false,
      requires_raw_nic: false,
      deterministic: false,
      live_io: false,
      reference_path: "lockwire/driver/native/moon.pkg",
    },
    {
      id: "os.event_loop.epoll_fd",
      kind: OsEventLoop,
      profiles: [ProfileRealLinux],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: true,
      requires_raw_nic: false,
      deterministic: false,
      live_io: true,
      reference_path: "docs/Isochronon-architecture.md#reactor_epoll",
    },
    {
      id: "os.event_loop.iocp",
      kind: OsEventLoop,
      profiles: [ProfileNativeReal],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: true,
      requires_raw_nic: false,
      deterministic: false,
      live_io: true,
      reference_path: "docs/lockwire-plan.md#native-wasm",
    },
    {
      id: "os.socket.udp",
      kind: OsUdpSocket,
      profiles: [ProfileNativeReal, ProfileRealLinux],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: true,
      requires_raw_nic: false,
      deterministic: false,
      live_io: true,
      reference_path: "lockwire/driver/native/stub_udp_windows.c",
    },
    {
      id: "os.raw_nic.windows_npcap",
      kind: OsRawNic,
      profiles: [ProfileNativeReal],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: false,
      requires_raw_nic: true,
      deterministic: false,
      live_io: true,
      reference_path: "lockwire/driver/native/stub_npcap_windows_loader.c",
    },
    {
      id: "os.raw_nic.linux_af_packet",
      kind: OsRawNic,
      profiles: [ProfileRealLinux],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: true,
      requires_raw_nic: true,
      deterministic: false,
      live_io: true,
      reference_path: "MoonECAT/hal/native/linux_raw_socket_ffi.mbt",
    },
    {
      id: "os.capture.pcap_file",
      kind: OsPacketCapture,
      profiles: [ProfileNativeReal, ProfileRealLinux, ProfileReplay],
      requires_native: true,
      requires_c_ffi: true,
      requires_os_fd: false,
      requires_raw_nic: false,
      deterministic: false,
      live_io: false,
      reference_path: "lockwire/driver/native/stub_pcap_writer.c",
    },
  ]
}

///|
pub fn os_capability_report() -> OsCapabilityReport {
  let catalog = os_capability_catalog()
  {
    catalog_count: catalog.length(),
    sim_native_count: count_profile(catalog, ProfileSimNative),
    sim_wasm_count: count_profile(catalog, ProfileSimWasm),
    native_real_count: count_profile(catalog, ProfileNativeReal),
    real_linux_count: count_profile(catalog, ProfileRealLinux),
    raw_nic_live_count: count_where(catalog, fn(item) {
      item.requires_raw_nic && item.live_io
    }),
    deterministic_non_live_count: count_where(catalog, fn(item) {
      item.deterministic && !item.live_io
    }),
    c_ffi_count: count_where(catalog, fn(item) { item.requires_c_ffi }),
    wasm_violation_count: count_where(catalog, fn(item) {
      item.violates_wasm_boundary()
    }),
  }
}

///|
fn count_profile(
  catalog : ArrayView[OsCapabilityDescriptor],
  profile : CapabilityProfile,
) -> Int {
  count_where(catalog, fn(item) { item.supports_profile(profile) })
}

///|
fn count_where(
  catalog : ArrayView[OsCapabilityDescriptor],
  predicate : (OsCapabilityDescriptor) -> Bool,
) -> Int {
  let mut count = 0
  for item in catalog {
    if predicate(item) {
      count += 1
    }
  }
  count
}