#' Compute the resistance distance matrix of a connected undirected graph
#'
#' For a connected undirected graph, the resistance distance between two vertices
#' is defined as the effective resistance when each edge is replaced by a unit resistor.
#' It can be computed from the Moore–Penrose pseudoinverse of the graph Laplacian.
#'
#' @param adj_matrix A symmetric adjacency matrix (0/1, no self-loops) representing
#'   a connected undirected graph.
#' @return A symmetric matrix \code{R} where \code{R[i,j]} is the resistance distance
#'   between vertices \code{i} and \code{j}. Diagonal entries are 0.
#' @importFrom MASS ginv
#' @references
#' D.J.Klein and M.Randic, “Resistance distance,” Journal of Mathematical." Chemistry 12, 81–95 (1993).
#' @examples
#' # Example: a path graph with 3 vertices
#' adj <- matrix(c(0,1,0,
#'                 1,0,1,
#'                 0,1,0), nrow = 3, byrow = TRUE)
#' R <- resistance_distance_matrix(adj)
#' print(R)
#' @export
resistance_distance_matrix <- function(adj_matrix) {
  # Input validation
  if (!is.matrix(adj_matrix)) {
    stop("Input must be a matrix.")
  }
  if (nrow(adj_matrix) != ncol(adj_matrix)) {
    stop("Adjacency matrix must be square.")
  }
  if (!isSymmetric(adj_matrix)) {
    stop("Adjacency matrix must be symmetric.")
  }

  n <- nrow(adj_matrix)

  # Connectivity check
  if (requireNamespace("igraph", quietly = TRUE)) {
    g <- igraph::graph_from_adjacency_matrix(adj_matrix, mode = "undirected")
    if (!igraph::is_connected(g)) {
      stop("Graph is not connected; resistance distances are undefined.")
    }
  } else {
    # Manual check using the second smallest eigenvalue of the Laplacian
    D <- diag(rowSums(adj_matrix))
    L <- D - adj_matrix
    eigvals <- eigen(L, symmetric = TRUE, only.values = TRUE)$values
    if (eigvals[2] < 1e-10) {
      stop("Graph is not connected; resistance distances are undefined.")
    }
  }

  # Laplacian matrix
  D <- diag(rowSums(adj_matrix))
  L <- D - adj_matrix

  # Moore–Penrose pseudoinverse (requires MASS)
  if (!requireNamespace("MASS", quietly = TRUE)) {
    stop("The 'MASS' package is required. Please install it: install.packages('MASS')")
  }
  L_pinv <- MASS::ginv(L)

  # Compute resistance distances
  R <- matrix(0, n, n)
  for (i in 1:n) {
    for (j in 1:n) {
      R[i, j] <- L_pinv[i, i] + L_pinv[j, j] - 2 * L_pinv[i, j]
    }
  }

  # Numerical adjustments
  diag(R) <- 0
  R <- (R + t(R)) / 2   # enforce symmetry

  return(R)
}
