#' Compute the local diffusion exponent for a given starting node
#'
#' Simulates random walks from a specified node on a graph and estimates
#' the local diffusion exponent from the scaling of the mean squared resistance distance.
#'
#' @param R Resistance distance matrix (symmetric, zero diagonal).
#' @param start_node Index or name of the starting node (must match row/column names of \code{R}).
#' @param adj Adjacency matrix (symmetric, 0/1, zero diagonal).
#' @param fit_range Numeric vector of length 2 specifying the time range for fitting,
#'   e.g. \code{c(t_start, t_end)} with \code{1 <= t_start < t_end <= max_time}.
#' @param num_paths Number of random walk paths to simulate. Default 100.
#' @param max_time Maximum number of steps (from 0 to \code{max_time}). Default 100.
#' @param seed Optional random seed for reproducibility.
#' @return A list containing:
#'   \item{H}{Estimated local diffusion exponent \(H_i\).}
#'   \item{msd}{Data frame with columns \code{t} (time) and \code{msd} (mean squared resistance distance).}
#'   \item{fit}{\code{lm} object from the log-log fit.}
#'   \item{paths}{Matrix of resistance distances for each path (rows = time steps, columns = paths).}
#' @importFrom stats lm coef
#' @export
#' @references
#' Nie, Chun-Xiao. "Vertex‑level diffusion scaling from resistance distance."  .Chaos, Under Review.
#' @examples
#' g<-make_lattice(length = 6, dim = 2)
#' adj <- as_adjacency_matrix(g,sparse = FALSE)
#' R <- resistance_distance_matrix(adj)
#' res <- localdiffexp(R, start_node = 1, adj = adj,fit_range = c(3, 30), max_time = 30)
#' print(res$H)
localdiffexp <- function(R, start_node, adj, fit_range,num_paths = 100, max_time = 100, seed = NULL) {

  if (!is.null(seed)) set.seed(seed)

  n <- nrow(adj)

  # Input consistency checks
  if (n != ncol(adj) || n != nrow(R) || n != ncol(R)) {
    stop("Dimensions of adjacency matrix and resistance distance matrix do not match.")
  }

  # Validate fit_range
  if (missing(fit_range)) {
    stop("fit_range must be provided, e.g. fit_range = c(10, max_time).")
  }
  if (!is.numeric(fit_range) || length(fit_range) != 2) {
    stop("fit_range must be a numeric vector of length 2.")
  }
  fit_range <- as.integer(fit_range)
  if (fit_range[1] < 1 || fit_range[2] > max_time || fit_range[1] >= fit_range[2]) {
    stop("fit_range must satisfy 1 <= start < end <= max_time.")
  }

  # Resolve start node index
  if (is.character(start_node)) {
    if (is.null(rownames(R))) stop("Resistance distance matrix has no row names to match start_node.")
    start_idx <- which(rownames(R) == start_node)
    if (length(start_idx) == 0) stop("Start node name not found in the matrix.")
  } else {
    start_idx <- as.integer(start_node)
    if (start_idx < 1 || start_idx > n) stop("Start node index out of range.")
  }

  # Precompute neighbor lists for efficiency
  neighbors <- vector("list", n)
  for (i in 1:n) {
    neighbors[[i]] <- which(adj[i, ] == 1)
  }

  # Simulate random walks
  distances <- matrix(NA, nrow = max_time + 1, ncol = num_paths)
  distances[1, ] <- 0  # distance at time 0

  for (path in 1:num_paths) {
    current <- start_idx
    for (t in 1:max_time) {
      nbrs <- neighbors[[current]]
      if (length(nbrs) == 0) {
        # Should not happen for a connected graph, but handle gracefully
        distances[(t+1):(max_time+1), path] <- NA
        break
      }
      next_node <- sample(nbrs, 1)
      distances[t+1, path] <- R[start_idx, next_node]
      current <- next_node
    }
  }

  # Compute mean squared displacement (MSD)
  t_vec <- 0:max_time
  msd <- sapply(0:max_time, function(t) mean(distances[t+1, ]^2, na.rm = TRUE))
  msd_df <- data.frame(t = t_vec, msd = msd)

  # Fit within the specified range
  fit_idx <- which(t_vec >= fit_range[1] & t_vec <= fit_range[2] & msd > 0)
  if (length(fit_idx) < 2) {
    warning("Insufficient valid data points in the fitting range. Cannot estimate exponent.")
    return(list(H = NA, msd = msd_df, fit = NULL, paths = distances))
  }

  log_t <- log(t_vec[fit_idx])
  log_msd <- log(msd[fit_idx])
  fit <- lm(log_msd ~ log_t)
  slope <- coef(fit)[2]
  H <- slope / 2

  list(H = H, msd = msd_df, fit = fit, paths = distances)
}
