// SPDX-License-Identifier: Apache-2.0

///|
// Resolve existing files and the nearest existing parent of a new output.
// This resolves symlinks/junctions, but does not identify hard-link aliases or
// eliminate races between checking and opening files.
async fn output_identity(raw : String) -> Result[String, String] {
  let absolute = @path.Path(raw).resolve()
  if @fs.path_exists(absolute.to_string()) {
    let resolved = @asyncfs.realpath(absolute.to_string()) catch {
      error =>
        return Err("无法解析真实文件路径:" + error.to_string())
    }
    return Ok(resolved)
  }
  let mut parent = absolute.dirname()
  let tail = [absolute.basename().to_owned()]
  while !@fs.path_exists(parent.to_string()) {
    let next = parent.dirname()
    if next.to_string() == parent.to_string() {
      return Err("无法定位输出路径的现有父目录")
    }
    tail.push(parent.basename().to_owned())
    parent = next
  }
  let resolved = @asyncfs.realpath(parent.to_string()) catch {
    error => return Err("无法解析输出父目录:" + error.to_string())
  }
  let mut result = resolved
  for i = tail.length() - 1; i >= 0; i = i - 1 {
    result = result + "/" + tail[i]
  }
  Ok(@path.Path(result).resolve().to_string())
}

///|
async fn output_paths_safe(
  input : String,
  fix : String,
  svg : String,
) -> Result[Unit, String] {
  if fix == "" && svg == "" {
    return Ok(())
  }
  let source = match output_identity(input) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let outputs : Array[String] = []
  for path in [fix, svg] {
    if path == "" {
      continue
    }
    let value = match output_identity(path) {
      Ok(value) => value
      Err(error) => return Err(error)
    }
    if @path.Path(value).relative(base=@path.Path(source)).to_string() == "" {
      return Err(
        "输出真实路径与输入模型相同(含符号链接或目录链接);请选择新文件名",
      )
    }
    for previous in outputs {
      if @path.Path(value).relative(base=@path.Path(previous)).to_string() == "" {
        return Err(
          "--fix 与 --svg 必须使用不同的输出路径(真实路径相同)",
        )
      }
    }
    outputs.push(value)
  }
  Ok(())
}