///| OsFs - OS filesystem implementation for @bit.FileSystem and @bit.RepoFileSystem

///|
pub struct OsFs {
  priv _dummy : Int
}

///|
pub fn OsFs::new() -> OsFs {
  { _dummy: 0 }
}

///|
fn io_error(err : @fs.IOError) -> @bit.GitError {
  match err {
    @fs.IOError::IOError(message) => @bit.GitError::IoError(message)
  }
}

///|
fn ensure_dir(path : String) -> Unit raise @bit.GitError {
  let is_dir = @fs.is_dir(path) catch { _ => false }
  if is_dir {
    return
  }
  // Recursively create parent directories
  let parts = path.split("/").collect()
  let mut current = ""
  for part_view in parts {
    let part = part_view.to_owned()
    if part.length() == 0 {
      current = "/"
      continue
    }
    current = if current.length() == 0 || current == "/" {
      current + part
    } else {
      current + "/" + part
    }
    let exists = @fs.is_dir(current) catch { _ => false }
    if !exists {
      @fs.create_dir(current) catch {
        err => raise io_error(err)
      }
    }
  }
}

///|
pub impl @bit.FileSystem for OsFs with fn mkdir_p(_self, path) {
  ensure_dir(path)
}

///|
pub impl @bit.FileSystem for OsFs with fn write_file(_self, path, content) {
  @fs.write_bytes_to_file(path, content) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.FileSystem for OsFs with fn write_string(_self, path, content) {
  @fs.write_string_to_file(path, content) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.FileSystem for OsFs with fn remove_file(_self, path) {
  @fs.remove_file(path) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.FileSystem for OsFs with fn remove_dir(_self, path) {
  @fs.remove_dir(path) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.RepoFileSystem for OsFs with fn read_file(_self, path) {
  @fs.read_file_to_bytes(path) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.RepoFileSystem for OsFs with fn readdir(_self, path) {
  @fs.read_dir(path) catch {
    err => raise io_error(err)
  }
}

///|
pub impl @bit.RepoFileSystem for OsFs with fn is_dir(_self, path) {
  @fs.is_dir(path) catch {
    _ => false
  }
}

///|
pub impl @bit.RepoFileSystem for OsFs with fn is_file(_self, path) {
  @fs.is_file(path) catch {
    _ => false
  }
}

///|
pub impl @bit.RepoFileSystem for OsFs with fn mtime(self, path) {
  match @io.worktree_entry_meta_sync(self, path) {
    Some(meta) => meta.mtime()
    None => raise @bit.GitError::IoError("Unable to stat path: \{path}")
  }
}