// moon-embed: 将前端静态文件嵌入 MoonBit 二进制
//
// 用法:
//   1. scripts/gen.sh ./dist > embedded.mbt  (构建时)
//   2. 在 main.mbt 中引用 embedded.mbt 的数据
//   3. 调用 @embed.decode_all() 或 @embed.extract_all() 加载
//
// 两种模式:
//   - decode_all: 内存模式,所有文件解码到 Map[String, Bytes]
//   - extract_all: 磁盘模式,文件解压到 /tmp/,返回目录路径

/// 将 base64 编码的嵌入数据解码为内存 Map
///
/// ```
/// let files = @embed.decode_all(MY_PATHS, MY_DATA)
/// let html = files["/index.html"]
/// ```
pub fn decode_all(paths : Array[String], data : Array[String]) -> Map[String, Bytes] {
  let m : Map[String, Bytes] = {}
  for i = 0; i < paths.length(); i = i + 1 {
    match (try { @base64.decode(data[i]) } catch { _ => continue }) {
      bytes => m[paths[i]] = bytes
    }
  }
  m
}

/// 将嵌入文件解压到临时目录,返回目录路径
///
/// ```
/// let dir = @embed.extract_all(MY_PATHS, MY_DATA)
/// let html = @embed.read_file(dir, "/index.html")
/// ```
pub async fn extract_all(paths : Array[String], data : Array[String]) -> String {
  let dir = @fs.tmpdir(prefix="moon-embed-")
  for i = 0; i < paths.length(); i = i + 1 {
    let bytes = match (try { @base64.decode(data[i]) } catch { _ => continue }) {
      b => b
    }
    let full_path = dir + paths[i]
    // 确保父目录存在
    let parent = dirname(full_path)
    if !@fs.exists(parent) {
      @fs.mkdir(parent, recursive=true)
    }
    @fs.write_file(full_path, bytes, create_mode=@fs.CreateOrTruncate)
  }
  dir
}

/// 从解压目录中读取文件
pub async fn read_file(dir : String, path : String) -> Bytes? {
  let full = dir + path
  if !@fs.exists(full) { return None }
  let raw = try { @fs.read_file(full) } catch { _ => return None }
  Some(raw.binary())
}

/// 根据文件路径猜测 Content-Type
pub fn content_type(path : String) -> String {
  let len = path.length()
  if len >= 5 {
    let end = path[len - 5:]
    if end == ".html" { return "text/html; charset=utf-8" }
    if end == ".json" { return "application/json" }
  }
  if len >= 4 {
    let end = path[len - 4:]
    if end == ".css"  { return "text/css; charset=utf-8" }
    if end == ".svg"  { return "image/svg+xml" }
    if end == ".png"  { return "image/png" }
    if end == ".ico"  { return "image/x-icon" }
    if end == ".txt"  { return "text/plain; charset=utf-8" }
  }
  if len >= 5 {
    let end = path[len - 5:]
    if end == ".wasm" { return "application/wasm" }
  }
  if len >= 3 {
    let end = path[len - 3:]
    if end == ".js"   { return "application/javascript; charset=utf-8" }
    if end == ".gz"   { return "application/gzip" }
  }
  if len >= 2 {
    let end = path[len - 2:]
    if end == ".ts" || end == ".mjs" { return "application/javascript; charset=utf-8" }
  }
  "application/octet-stream"
}

/// 检查嵌入数据是否为空
///
/// 编译时:如果用户没生成 embedded.mbt,编译器会报
///   `The value identifier EMBED_PATHS is unbound.`
/// 这已经是接近编译期检查的效果。
///
/// 运行时:如果生成的文件为空数组,返回 Err 提示。
pub fn ensure_embedded(paths : Array[String]) -> Result[Unit, String] {
  if paths.is_empty() {
    Err("moon-embed: EMBED_PATHS is empty.\n  Run: bash scripts/gen.sh  > src/embedded.mbt")
  } else {
    Ok(())
  }
}

/// 获取路径的父目录
fn dirname(p : String) -> String {
  match p.rev_find("/") {
    Some(i) => p[:i].to_owned()
    None => "."
  }
}