// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Host bytes interop helpers.
///
/// Similar to `with_host_string_id`, but for raw bytes (e.g. RGBA8 uploads).
/// We avoid passing wasm-gc `Bytes` across the host boundary directly.

///|
fn host_bytes_sink_reset() -> Unit = "mgstudio_host" "bytes_sink_reset"

///|
fn host_bytes_sink_push(byte : Int) -> Unit = "mgstudio_host" "bytes_sink_push"

///|
fn host_bytes_sink_push_u32(word : Int) -> Unit = "mgstudio_host" "bytes_sink_push_u32"

///|
fn host_bytes_sink_take() -> Int = "mgstudio_host" "bytes_sink_take"

///|
fn host_bytes_drop(id : Int) -> Unit = "mgstudio_host" "bytes_drop"

///|
pub fn[T] with_host_bytes_id(data : Bytes, f : (Int) -> T) -> T {
  if data.length() == 0 {
    return f(0)
  }
  host_bytes_sink_reset()
  let n = data.length()
  let mut i = 0
  while i + 4 <= n {
    let b0 = match data.get(i) {
      None => 0
      Some(v) => v.to_int()
    }
    let b1 = match data.get(i + 1) {
      None => 0
      Some(v) => v.to_int()
    }
    let b2 = match data.get(i + 2) {
      None => 0
      Some(v) => v.to_int()
    }
    let b3 = match data.get(i + 3) {
      None => 0
      Some(v) => v.to_int()
    }
    let word_u : UInt = (b0 & 0xFF).reinterpret_as_uint() |
      ((b1 & 0xFF).reinterpret_as_uint() << 8) |
      ((b2 & 0xFF).reinterpret_as_uint() << 16) |
      ((b3 & 0xFF).reinterpret_as_uint() << 24)
    host_bytes_sink_push_u32(word_u.reinterpret_as_int())
    i = i + 4
  }
  while i < n {
    let b = match data.get(i) {
      None => 0
      Some(v) => v.to_int()
    }
    host_bytes_sink_push(b)
    i = i + 1
  }
  let id = host_bytes_sink_take()
  let out = f(id)
  if id > 0 {
    host_bytes_drop(id)
  }
  out
}