///|
const STATUS_OK : Int = 0

///|
const STATUS_NOT_AVAILABLE : Int = 1

///|
const STATUS_PERMISSION_DENIED : Int = 2

///|
const STATUS_BACKEND_FAILURE : Int = 3

///|
extern "C" fn c_read_text() -> Bytes = "mb_clipboard_read_text"

///|
extern "C" fn c_last_error_code() -> Int = "mb_clipboard_last_error_code"

///|
extern "C" fn c_last_error_message() -> Bytes = "mb_clipboard_last_error_message"

///|
#borrow(text)
extern "C" fn c_write_text(text : Bytes) -> Int = "mb_clipboard_write_text"

///|
fn status_to_error(status : Int, message : String) -> ClipboardError {
  match status {
    STATUS_NOT_AVAILABLE => NotAvailable
    STATUS_PERMISSION_DENIED => PermissionDenied
    STATUS_BACKEND_FAILURE => BackendFailure(message)
    _ => BackendFailure(message)
  }
}

///|
fn ensure_ok(status : Int) -> Unit raise ClipboardError {
  if status == STATUS_OK {
    return
  }
  let message = @utf8.decode_lossy(c_last_error_message())
  raise status_to_error(status, message)
}

///|
fn read_text_sync_impl() -> String raise ClipboardError {
  let bytes = c_read_text()
  ensure_ok(c_last_error_code())
  @utf8.decode_lossy(bytes)
}

///|
fn write_text_sync_impl(text : String) -> Unit raise ClipboardError {
  let status = c_write_text(@utf8.encode(text))
  ensure_ok(status)
}

///|
#warnings("-unused_async")
async fn read_text_async_impl() -> String raise ClipboardError {
  read_text_sync_impl()
}

///|
#warnings("-unused_async")
async fn write_text_async_impl(text : String) -> Unit raise ClipboardError {
  write_text_sync_impl(text)
}