// Local file reading for `webfinger-tool --input-file`.
//
// The library performs no network access, and the CLI likewise reads
// only local files. Target support:
//
//   native (Windows) - `_wfopen`/`fgetc`/`fclose` from the C runtime.
//       MoonBit strings are UTF-16 in memory, which is exactly
//       `wchar_t*` on Windows, so the path is passed straight through.
//       FILE* values travel as Int64 (pointer-sized integer), matching
//       the 64-bit Windows calling convention; bytes are read one at a
//       time and re-decoded as UTF-8.
//   native (other)   - not implemented; reported as unavailable.
//   js               - Node `fs.readFileSync` (utf-8).
//   wasm-gc          - not supported; callers receive a clear error.

///|
/// Read a local file as UTF-8 text, or `None` when the file cannot be
/// read or is not valid UTF-8. The caller enforces the size limit.
#cfg(all(target="native", platform="windows"))
fn cli_read_file(path : String) -> String? {
  let file = c_wfopen(path, "rb")
  if file == 0 {
    return None
  }
  let bytes : Array[Byte] = []
  let mut ok = true
  while true {
    let b = c_fgetc(file)
    if b == -1 {
      break
    }
    if b < 0 || b > 255 {
      ok = false
      break
    }
    bytes.push(b.to_byte())
  }
  ignore(c_fclose(file))
  if !ok {
    return None
  }
  Some(decode_utf8_strict(strip_utf8_bom(bytes))) catch {
    _ => None
  }
}

///|
/// Internal: drop a leading UTF-8 byte-order mark (EF BB BF), if present,
/// before strict decoding. Only the native Windows reader needs it.
#cfg(all(target="native", platform="windows"))
fn strip_utf8_bom(bytes : Array[Byte]) -> Array[Byte] {
  if bytes.length() >= 3 &&
    bytes[0].to_int() == 0xEF &&
    bytes[1].to_int() == 0xBB &&
    bytes[2].to_int() == 0xBF {
    bytes[3:].to_owned()
  } else {
    bytes
  }
}

///|
#cfg(all(target="native", platform="windows"))
#borrow(path, mode)
extern "c" fn c_wfopen(path : String, mode : String) -> Int64 = "_wfopen"

///|
#cfg(all(target="native", platform="windows"))
extern "c" fn c_fgetc(file : Int64) -> Int = "fgetc"

///|
#cfg(all(target="native", platform="windows"))
extern "c" fn c_fclose(file : Int64) -> Int = "fclose"

///|
/// Non-Windows native has no file input in this MVP.
#cfg(all(target="native", not(platform="windows")))
fn cli_read_file(_path : String) -> String? {
  None
}

///|
/// Read a local file as UTF-8 text, or `None` when the file cannot be
/// read.
#cfg(target="js")
extern "js" fn cli_read_file(path : String) -> String? =
  #| function(path) {
  #|   try {
  #|     if (typeof require !== "function") {
  #|       return null;
  #|     }
  #|     const fs = require("fs");
  #|     return fs.readFileSync(path, "utf8");
  #|   } catch (e) {
  #|     return null;
  #|   }
  #| }

///|
/// The wasm-gc target has no local file access; report unavailability.
#cfg(any(target="wasm", target="wasm-gc"))
fn cli_read_file(_path : String) -> String? {
  None
}

///|
/// Whether `--input-file` is available on this target.
#cfg(all(target="native", platform="windows"))
pub fn cli_file_input_supported() -> Bool {
  true
}

///|
#cfg(all(target="native", not(platform="windows")))
pub fn cli_file_input_supported() -> Bool {
  false
}

///|
#cfg(target="js")
pub fn cli_file_input_supported() -> Bool {
  true
}

///|
#cfg(any(target="wasm", target="wasm-gc"))
pub fn cli_file_input_supported() -> Bool {
  false
}