///|
/// Lexical path normalization for policy checks.
///
/// Without this, a prefix rule is trivially bypassed: `reports/../../etc/passwd`
/// starts with `reports/` and would pass a naive "must start with reports"
/// check. Normalization resolves `.` and `..` segments before matching, so the
/// comparison sees the path the operating system would actually open.
///
/// This is lexical only: it does not touch the filesystem, resolve symlinks, or
/// decode percent escapes. Symlink escape remains a limitation and is listed in
/// `docs/SEMANTICS.md`.
fn is_drive_letter(ch : UInt16) -> Bool {
  (ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)
}

///|
pub fn normalize_path(input : String) -> String {
  let slashed = input.replace_all(old="\\", new="/")
  let drive = if slashed.length() >= 2 &&
    slashed[1] == ':' &&
    is_drive_letter(slashed[0]) {
    slashed[0:2].to_owned()
  } else {
    ""
  }
  let rest = if drive.is_empty() { slashed } else { slashed[2:].to_owned() }
  let absolute = rest.has_prefix("/")
  let segments : Array[String] = []
  for raw in rest.split("/") {
    let part = raw.to_owned()
    if part.is_empty() || part == "." {
      continue
    }
    if part == ".." {
      if segments.length() > 0 && segments[segments.length() - 1] != ".." {
        let _ = segments.pop()
      } else if !absolute {
        segments.push("..")
      }
      continue
    }
    segments.push(part)
  }
  let body = segments.join("/")
  if !drive.is_empty() {
    if absolute {
      drive + "/" + body
    } else {
      drive + body
    }
  } else if absolute {
    "/" + body
  } else {
    body
  }
}