///|
/// Convert a public platform value to the native stub ABI code.
fn platform_code(platform : @platform.Os) -> Int {
  match platform {
    Windows => 0
    MacOS => 1
    Linux => 2
    UnknownOs => 3
  }
}

///|
/// Convert a public wallpaper mode to the native stub ABI code.
fn mode_code(mode : WallpaperMode) -> Int {
  match mode {
    Fill => 0
    Fit => 1
    Stretch => 2
    Center => 3
    Span => 4
  }
}

///|
/// Convert a native stub status code to a public status value.
fn status_from_code(code : Int) -> WallpaperStatus {
  match code {
    0 => Applied
    1 => UnsupportedPlatform
    2 => UnsupportedDesktop
    3 => InvalidSource
    _ => NativeFailure
  }
}

///|
/// Normalize the image source for the native platform API.
fn normalized_source(platform : @platform.Os, source : String) -> String {
  match platform {
    Linux =>
      if source.has_prefix("file://") {
        source
      } else {
        "file://\{source}"
      }
    _ => source
  }
}

///|
/// Return whether an operating system has a native apply implementation.
///
/// Windows uses Win32 user and registry APIs, macOS uses AppKit through the
/// Objective-C runtime, and Linux uses GNOME GSettings through the GIO C API.
/// `UnknownOs` is always unsupported.
///
/// This checks only whether the package has code for the operating system. It
/// does not verify a specific desktop session, image path, permissions, or
/// user settings service. On Linux, for example, this returns `true` for the OS
/// even though `apply` may later return `UnsupportedDesktop` when GNOME
/// GSettings is unavailable.
///
/// # Example
/// ```mbt check
/// test {
///   inspect(@wallpaper.supports_platform(Linux), content="true")
///   inspect(@wallpaper.supports_platform(UnknownOs), content="false")
/// }
/// ```
pub fn supports_platform(platform : @platform.Os) -> Bool {
  match platform {
    Windows | MacOS | Linux => true
    UnknownOs => false
  }
}

///|
/// Return whether a wallpaper status represents a successful update.
///
/// This helper is useful when callers want a boolean branch while still keeping
/// the detailed status available for logging or user messages.
///
/// Only `Applied` is considered successful. Unsupported platforms, unsupported
/// desktops, validation failures, and native API rejections all return `false`
/// so callers can handle every non-applied outcome through one fallback branch
/// when detailed recovery is not needed.
///
/// # Example
/// ```mbt check
/// test {
///   inspect(@wallpaper.WallpaperStatus::Applied.is_success(), content="true")
///   inspect(
///     @wallpaper.WallpaperStatus::NativeFailure.is_success(),
///     content="false",
///   )
/// }
/// ```
pub fn WallpaperStatus::is_success(self : WallpaperStatus) -> Bool {
  self is Applied
}

///|
/// Apply a wallpaper request through the target platform API.
///
/// No shell commands or script runners are used. Windows calls Win32 APIs,
/// macOS calls AppKit through the Objective-C runtime, and Linux calls GNOME
/// GSettings through GIO. The function returns a `WallpaperStatus` instead of
/// raising so desktop applications can decide how to surface native failures.
///
/// `source` must be non-empty. Windows and macOS expect a local filesystem path.
/// Linux accepts either a local path or a `file://` URI; plain paths are
/// normalized before entering the GSettings API. A request whose platform is
/// `UnknownOs` never reaches a desktop API and returns `UnsupportedPlatform`.
///
/// # Example
/// ```mbt check
/// test {
///   let request : @wallpaper.WallpaperRequest = {
///     platform: UnknownOs,
///     source: "/tmp/wallpaper.jpg",
///     mode: Fill,
///   }
///   inspect(@wallpaper.apply(request), content="UnsupportedPlatform")
/// }
/// ```
pub fn apply(request : WallpaperRequest) -> WallpaperStatus {
  if request.source == "" {
    return InvalidSource
  }
  let source = normalized_source(request.platform, request.source)
  status_from_code(
    native_apply(
      platform_code(request.platform),
      @ffi.to_cstr(source),
      @ffi.to_wstr(source),
      mode_code(request.mode),
    ),
  )
}

///|
/// Apply a wallpaper source on the current operating system.
///
/// This is a convenience wrapper around `justjavac/platform.os` and `apply`.
/// It has the same side effects as `apply`, so callers should pass a real local
/// image path and be prepared to handle a non-`Applied` status.
///
/// Use this for the common case where the application wants to apply a wallpaper
/// to the machine it is running on. It performs the same empty-source
/// validation as `apply` before any native desktop API is called.
///
/// # Example
/// ```mbt check
/// test {
///   inspect(@wallpaper.apply_current("", Center), content="InvalidSource")
/// }
/// ```
pub fn apply_current(source : String, mode : WallpaperMode) -> WallpaperStatus {
  apply({ platform: @platform.os(), source, mode })
}