///|
/// Converts a MoonBit string into a UTF-8 C string for native FFI calls.
fn to_cstr(value : String) -> Bytes {
  let bytes = @utf8.encode(value).to_array()
  bytes.push(0)
  Bytes::from_array(bytes)
}

///|
/// Maps the public severity enum to the native integer level used by the backends.
fn level_to_native_code(level : NotificationLevel) -> Int {
  match level {
    Info => 0
    Warning => 1
    Error => 2
  }
}

///|
/// Native backend identifier for the Windows shell notification path.
let backend_kind_windows : Int = 1

///|
/// Native backend identifier for the macOS `osascript` path.
let backend_kind_macos : Int = 2

///|
/// Native backend identifier for the Linux `notify-send` path.
let backend_kind_linux : Int = 3

///|
/// Status returned across the native FFI seam.
///
/// The variants are ordered to match `DESKTOP_NOTIFICATION_STATUS_*` in
/// `notification_native.h`.
priv enum DeliveryStatus {
  Success = 0
  Unsupported
  BackendUnavailable
  AppIdentityRequired
  AuthorizationDenied
  AuthorizationFailed
  SchedulingFailed
  DeliveryFailed
  AppBackendUnavailable
}

///|
/// Returns the backend selected by the native build.
extern "C" fn notification_backend_kind_ffi() -> Int = "desktop_notification_backend_kind"

///|
/// Returns whether the current runtime can deliver notifications.
extern "C" fn notification_support_status_ffi() -> DeliveryStatus = "desktop_notification_support_status"

///|
/// Invokes the native backend selected at compile time.
#borrow(title, body)
extern "C" fn show_notification_ffi(
  window_handle : Int64,
  title : Bytes,
  body : Bytes,
  level : Int,
) -> DeliveryStatus = "desktop_notification_show"

///|
/// Invokes the app-oriented native backend.
#borrow(title, body)
extern "C" fn show_app_notification_ffi(
  window_handle : Int64,
  title : Bytes,
  body : Bytes,
  level : Int,
) -> DeliveryStatus = "desktop_notification_show_app"

///|
/// Invokes the command-line-oriented native backend.
#borrow(title, body)
extern "C" fn show_cli_notification_ffi(
  window_handle : Int64,
  title : Bytes,
  body : Bytes,
  level : Int,
) -> DeliveryStatus = "desktop_notification_show_cli"

///|
/// Returns whether the current build/runtime can attempt to deliver a notification.
fn backend_is_supported() -> Bool {
  notification_support_status_ffi() is Success
}

///|
/// Returns the support error for the active native backend.
fn backend_support_error() -> String {
  delivery_error(notification_support_status_ffi())
}

///|
/// Maps native delivery status into stable public error text.
fn delivery_error(status : DeliveryStatus) -> String {
  let backend_kind = notification_backend_kind_ffi()
  match status {
    BackendUnavailable =>
      if backend_kind == backend_kind_windows {
        "desktop notifications are unavailable on the current Windows runtime"
      } else if backend_kind == backend_kind_macos {
        "CLI notifications on macOS require /usr/bin/osascript"
      } else if backend_kind == backend_kind_linux {
        "desktop notifications on Linux require the notify-send executable"
      } else {
        "desktop notifications are not supported on this platform"
      }
    AppIdentityRequired =>
      "App Notifications on macOS require an identified .app bundle"
    AuthorizationDenied => "App Notification authorization was denied"
    AuthorizationFailed =>
      "App Notification authorization could not be determined"
    SchedulingFailed => "macOS failed to schedule the App Notification"
    AppBackendUnavailable =>
      "App Notifications require UserNotifications on macOS 10.14 or later"
    Unsupported => "desktop notifications are not supported on this platform"
    Success | DeliveryFailed => "native notification delivery failed"
  }
}

///|
/// Executes the selected native backend and normalizes native failures.
fn backend_deliver(
  window_handle : Int64,
  title : String,
  body : String,
  level : NotificationLevel,
) -> Result[Unit, String] {
  let status = show_notification_ffi(
    window_handle,
    to_cstr(title),
    to_cstr(body),
    level_to_native_code(level),
  )
  match status {
    Success => Ok(())
    _ => Err(delivery_error(status))
  }
}

///|
/// Executes the app-oriented backend and normalizes native failures.
fn backend_deliver_app(
  window_handle : Int64,
  title : String,
  body : String,
  level : NotificationLevel,
) -> Result[Unit, String] {
  let status = show_app_notification_ffi(
    window_handle,
    to_cstr(title),
    to_cstr(body),
    level_to_native_code(level),
  )
  match status {
    Success => Ok(())
    _ => Err(delivery_error(status))
  }
}

///|
/// Executes the command-line-oriented backend and normalizes native failures.
fn backend_deliver_cli(
  window_handle : Int64,
  title : String,
  body : String,
  level : NotificationLevel,
) -> Result[Unit, String] {
  let status = show_cli_notification_ffi(
    window_handle,
    to_cstr(title),
    to_cstr(body),
    level_to_native_code(level),
  )
  match status {
    Success => Ok(())
    _ => Err(delivery_error(status))
  }
}

///|
/// Dispatches through the delivery path selected by the caller.
fn backend_deliver_with_mode(
  window_handle : Int64,
  title : String,
  body : String,
  level : NotificationLevel,
  delivery : NotificationDelivery,
) -> Result[Unit, String] {
  match delivery {
    Auto => backend_deliver(window_handle, title, body, level)
    App => backend_deliver_app(window_handle, title, body, level)
    Cli => backend_deliver_cli(window_handle, title, body, level)
  }
}