///|
/// Returns the native platform code for the current process.
extern "C" fn platform_code_ffi() -> Int = "mb_auto_launch_platform_code"

///|
/// Returns the current executable path as UTF-8 bytes, or an empty value.
extern "C" fn current_executable_path_ffi() -> Bytes = "mb_auto_launch_current_executable_path"

///|
/// Returns the current user's home directory as UTF-8 bytes, or an empty value.
extern "C" fn home_directory_ffi() -> Bytes = "mb_auto_launch_home_directory"

///|
/// Writes a UTF-8 text file and returns a native status code.
#borrow(path, contents)
extern "C" fn write_text_file_ffi(path : Bytes, contents : Bytes) -> Int = "mb_auto_launch_write_text_file"

///|
/// Removes the file at `path` and returns a native status code.
#borrow(path)
extern "C" fn remove_file_ffi(path : Bytes) -> Int = "mb_auto_launch_remove_file"

///|
/// Checks whether the file at `path` exists.
#borrow(path)
extern "C" fn file_exists_ffi(path : Bytes) -> Int = "mb_auto_launch_file_exists"

///|
/// Creates or updates a current-user Windows `Run` registry value.
#borrow(name, command)
extern "C" fn windows_set_run_entry_ffi(name : Bytes, command : Bytes) -> Int = "mb_auto_launch_windows_set_run_entry"

///|
/// Deletes a current-user Windows `Run` registry value.
#borrow(name)
extern "C" fn windows_delete_run_entry_ffi(name : Bytes) -> Int = "mb_auto_launch_windows_delete_run_entry"

///|
/// Queries whether a current-user Windows `Run` registry value exists.
#borrow(name)
extern "C" fn windows_run_entry_exists_ffi(name : Bytes) -> Int = "mb_auto_launch_windows_run_entry_exists"

///|
/// Returns the last native error code observed by the C shim.
extern "C" fn last_error_code_ffi() -> Int = "mb_auto_launch_last_error_code"

///|
/// Returns the last native error message as UTF-8 bytes.
extern "C" fn last_error_message_ffi() -> Bytes = "mb_auto_launch_last_error_message"

///|
/// Decodes UTF-8 bytes into a MoonBit string with lossy fallback.
fn decode_utf8(bytes : Bytes) -> String {
  @utf8.decode_lossy(bytes[:])
}

///|
/// Decodes optional text returned by the native layer.
fn decode_optional_text(bytes : Bytes) -> String? {
  let value = decode_utf8(bytes)
  if value.is_empty() {
    None
  } else {
    Some(value)
  }
}

///|
/// Decodes a native error message and falls back to `default_message`.
fn decode_error_message(bytes : Bytes, default_message : String) -> String {
  let message = decode_utf8(bytes)
  if message.is_empty() {
    default_message
  } else {
    message
  }
}

///|
/// Returns the last native error message or `default_message`.
fn last_error_message_or(default_message : String) -> String {
  decode_error_message(last_error_message_ffi(), default_message)
}

///|
/// Converts the last native failure into `AutoLaunchError`.
fn native_failure(
  action : String,
  fallback_message : String,
) -> AutoLaunchError {
  ignore(last_error_code_ffi())
  AutoLaunchError::NativeFailure(
    action~,
    message=last_error_message_or(fallback_message),
  )
}

///|
/// Converts an optional path into a `Result`.
fn optional_path_result(
  path : String?,
  missing_error : AutoLaunchError,
) -> Result[String, AutoLaunchError] {
  match path {
    Some(value) => Ok(value)
    None => Err(missing_error)
  }
}

///|
/// Converts a native "0 means success" status code into `Result[Unit, _]`.
fn unit_result_from_status(
  status : Int,
  action : String,
  fallback_message : String,
) -> Result[Unit, AutoLaunchError] {
  if status == 0 {
    Ok(())
  } else {
    Err(native_failure(action, fallback_message))
  }
}

///|
/// Converts a native tri-state existence status into `Result[Bool, _]`.
fn bool_result_from_status(
  status : Int,
  action : String,
  fallback_message : String,
) -> Result[Bool, AutoLaunchError] {
  match status {
    0 => Ok(false)
    1 => Ok(true)
    _ => Err(native_failure(action, fallback_message))
  }
}

///|
/// Returns the current executable path or a typed discovery error.
fn current_executable_path_result() -> Result[String, AutoLaunchError] {
  optional_path_result(
    decode_optional_text(current_executable_path_ffi()),
    AutoLaunchError::ExecutablePathUnavailable,
  )
}

///|
/// Returns the current home directory or a typed discovery error.
fn home_directory_result() -> Result[String, AutoLaunchError] {
  optional_path_result(
    decode_optional_text(home_directory_ffi()),
    AutoLaunchError::HomeDirectoryUnavailable,
  )
}

///|
/// Writes a text file through the native layer.
fn write_text_file_result(
  path : String,
  contents : String,
) -> Result[Unit, AutoLaunchError] {
  unit_result_from_status(
    write_text_file_ffi(@utf8.encode(path), @utf8.encode(contents)),
    "write file",
    "Failed to write auto-launch entry file",
  )
}

///|
/// Removes a file through the native layer.
fn remove_file_result(path : String) -> Result[Unit, AutoLaunchError] {
  unit_result_from_status(
    remove_file_ffi(@utf8.encode(path)),
    "remove file",
    "Failed to remove auto-launch entry file",
  )
}

///|
/// Checks file existence through the native layer.
fn file_exists_result(path : String) -> Result[Bool, AutoLaunchError] {
  bool_result_from_status(
    file_exists_ffi(@utf8.encode(path)),
    "file exists",
    "Failed to check auto-launch entry file",
  )
}

///|
/// Creates or updates a Windows `Run` registry entry.
fn windows_set_run_entry_result(
  name : String,
  command : String,
) -> Result[Unit, AutoLaunchError] {
  unit_result_from_status(
    windows_set_run_entry_ffi(@utf8.encode(name), @utf8.encode(command)),
    "set windows run entry",
    "Failed to write Windows Run registry value",
  )
}

///|
/// Deletes a Windows `Run` registry entry.
fn windows_delete_run_entry_result(
  name : String,
) -> Result[Unit, AutoLaunchError] {
  unit_result_from_status(
    windows_delete_run_entry_ffi(@utf8.encode(name)),
    "delete windows run entry",
    "Failed to delete Windows Run registry value",
  )
}

///|
/// Checks whether a Windows `Run` registry entry exists.
fn windows_run_entry_exists_result(
  name : String,
) -> Result[Bool, AutoLaunchError] {
  bool_result_from_status(
    windows_run_entry_exists_ffi(@utf8.encode(name)),
    "windows run entry exists",
    "Failed to query Windows Run registry value",
  )
}