///|
/// 文件系统读接口(`/api/fs/*`)。

///|
/// 测测试目录的列表、对象详情、子目录与搜索;目录里有压缩包时再测归档信息。
///
/// 返回第一页条目,供调用方挑搜索关键词与压缩包。
pub async fn check_fs_read(
  client : @lib.OpenListClient,
  dir : String,
) -> Array[@lib.ObjResp] {
  section("文件系统(读) /api/fs/*")
  let listing = check(
    "POST /api/fs/list",
    "fs().list(dir)",
    Ok(client.fs().list(dir, page=1, per_page=50)) catch {
      error => Err(error)
    },
    fn(page) {
      "total=\{page.total},本页 \{page.content.length()} 项,provider=\{page.provider},可写=\{page.write},readme=\{page.readme.length()} 字符"
    },
  )
  dump_raw(
    client,
    @lib.Method::Post,
    "/api/fs/list",
    body=Json::object({
      "path": Json::string(dir),
      "page": Json::number(1),
      "per_page": Json::number(50),
      "refresh": Json::boolean(false),
    }),
  )
  let content = match listing {
    Some(page) => {
      say("     条目明细:")
      say(entry_lines(page.content))
      page.content
    }
    None => []
  }
  let _ = check(
    "POST /api/fs/get",
    "fs().get(dir)",
    Ok(client.fs().get(dir)) catch {
      error => Err(error)
    },
    fn(response) {
      "\{obj_summary(response.obj)} provider=\{response.provider} raw_url=\{brief(response.raw_url, 50)} 相关对象=\{response.related.length()} 个"
    },
  )
  dump_raw(
    client,
    @lib.Method::Post,
    "/api/fs/get",
    body=Json::object({ "path": Json::string(dir) }),
  )
  let _ = check(
    "POST /api/fs/dirs",
    "fs().dirs(path=dir)",
    Ok(client.fs().dirs(path=dir)) catch {
      error => Err(error)
    },
    fn(list) {
      "共 \{list.length()} 个子目录:\{joined(list.map(dir_summary))}"
    },
  )
  dump_raw(
    client,
    @lib.Method::Post,
    "/api/fs/dirs",
    body=Json::object({ "path": Json::string(dir) }),
  )
  let keyword = match content {
    [first, ..] => first.name
    [] => ""
  }
  say("     搜索关键词取列表第一条目的名字:\{keyword}")
  let _ = check(
    "POST /api/fs/search",
    "fs().search(dir, keyword, scope=0)",
    Ok(client.fs().search(dir, keyword, scope=0, page=1, per_page=20)) catch {
      error => Err(error)
    },
    fn(page) {
      "total=\{page.total},本页 \{page.content.length()} 项:\{joined(page.content.map(search_summary))}"
    },
  )
  dump_raw(
    client,
    @lib.Method::Post,
    "/api/fs/search",
    body=Json::object({
      "parent": Json::string(dir),
      "keywords": Json::string(keyword),
      "scope": Json::number(0),
      "page": Json::number(1),
      "per_page": Json::number(20),
    }),
  )
  check_archive(client, dir, content)
  content
}

///|
/// 目录里有压缩包时测归档元信息与归档内列表,否则记一条「跳过」。
async fn check_archive(
  client : @lib.OpenListClient,
  dir : String,
  items : Array[@lib.ObjResp],
) -> Unit {
  match find_archive(dir, items) {
    Some(archive) => {
      let _ = check(
        "POST /api/fs/archive/meta",
        "fs().archive_meta(archive)",
        Ok(client.fs().archive_meta(archive)) catch {
          error => Err(error)
        },
        archive_summary,
      )
      dump_raw(
        client,
        @lib.Method::Post,
        "/api/fs/archive/meta",
        body=Json::object({ "path": Json::string(archive) }),
      )
      let _ = check(
        "POST /api/fs/archive/list",
        "fs().archive_list(archive)",
        Ok(client.fs().archive_list(archive, page=1, per_page=20)) catch {
          error => Err(error)
        },
        fn(page) { "total=\{page.total},本页 \{page.content.length()} 项" },
      )
      dump_raw(
        client,
        @lib.Method::Post,
        "/api/fs/archive/list",
        body=Json::object({
          "path": Json::string(archive),
          "inner_path": Json::string(""),
          "page": Json::number(1),
          "per_page": Json::number(20),
        }),
      )
    }
    None =>
      skip(
        "POST /api/fs/archive/meta、/api/fs/archive/list", "归档接口", "测试目录里没有压缩包(.zip/.7z/.tar/.gz/.rar/.xz/.bz2)",
      )
  }
}

///|
/// 在目录列表里找一个压缩包,返回它的完整路径。
fn find_archive(dir : String, items : Array[@lib.ObjResp]) -> String? {
  for item in items {
    if !item.is_dir && is_archive_name(item.name) {
      return Some(dir + "/" + item.name)
    }
  }
  None
}

///|
/// 按扩展名判断是不是压缩包。
fn is_archive_name(name : String) -> Bool {
  for ext in [".zip", ".7z", ".tar", ".gz", ".rar", ".xz", ".bz2", ".zst"] {
    if name.has_suffix(ext) {
      return true
    }
  }
  false
}