#' Tidying methods for spatially autoregressive models
#'
#' These methods tidy the coefficients of spatial autoregression
#' models generated by functions of the `spatialreg` package.
#'
#' @param x An object of object returned from [spatialreg::lagsarlm()] 
#' or [spatialreg::errorsarlm()].
#' @template param_confint
#' @template param_unused_dots
#' 
#' @evalRd return_tidy(regression = TRUE)
#' 
#' @examples 
#' \dontrun{ 
#' library(spatialreg)
#' data(oldcol, package="spdep")
#' listw <- spdep::nb2listw(COL.nb, style="W")
#' 
#' crime_sar <- lagsarlm(CRIME ~ INC + HOVAL, data=COL.OLD,  
#'   listw=listw, method="eigen")
#'   
#' tidy(crime_sar)
#' tidy(crime_sar, conf.int = TRUE)
#' glance(crime_sar)
#' augment(crime_sar)
#' 
#' crime_sem <- errorsarlm(CRIME ~ INC + HOVAL, data=COL.OLD, listw)
#' 
#' tidy(crime_sem)
#' tidy(crime_sem, conf.int = TRUE)
#' glance(crime_sem)
#' augment(crime_sem)
#' 
#' crime_sac <- sacsarlm(CRIME ~ INC + HOVAL, data=COL.OLD, listw)
#' 
#' tidy(crime_sac)
#' tidy(crime_sac, conf.int = TRUE)
#' glance(crime_sac)
#' augment(crime_sac)
#' }
#' 
#' @aliases spatialreg_tidiers
#' @export
#' @family spatialreg tidiers
#' @seealso [tidy()], [spatialreg::lagsarlm()], [spatialreg::errorsarlm()], 
#' [spatialreg::sacsarlm()]
tidy.sarlm <- function(x, conf.int = FALSE, conf.level = .95, ...) {
  # construct parameter table
  s <- summary(x)
  ret <- as_tidy_tibble(
    s$Coef,
    new_names = c("estimate", "std.error", "statistic", "p.value")
  )
  
  # append spatial autoregression coefficient to parameter table if it exists
  if (!is.null(s$rho)) {
    rho <- tibble(
        term = "rho",
        estimate = as.numeric(s$rho),
        std.error = as.numeric(s$rho.se),
        statistic = as.numeric(estimate / std.error),
        p.value = as.numeric(2 * (1 - pnorm(abs(statistic))))
      )
    ret <- bind_rows(rho, ret)
  }
  
  # append spatial error coefficient to parameter table if it exists
  if (!is.null(s$lambda))  {
    lambda <- tibble(
      term = "lambda",
      estimate = as.numeric(s$lambda),
      std.error = as.numeric(s$lambda.se),
      statistic = as.numeric(estimate / std.error),
      p.value = as.numeric(2 * (1 - pnorm(abs(statistic))))
    )
    ret <- bind_rows(ret, lambda)
  }
  
  
  
  # Calculate confidence interval
  if (conf.int) {
    ci <- broom_confint_terms(x, level = conf.level)
    ret <- dplyr::left_join(ret, ci, by = "term")
  }
  
  ret
}
#' @templateVar class spatialreg
#' @template title_desc_augment
#'
#' @evalRd return_augment(".fitted", ".resid")
#'
#' @inherit tidy.sarlm params examples
#' @param data Ignored, but included for internal consistency. See the details
#' below.
#'
#' @details 
#' The predict method for sarlm objects assumes that the response is 
#' known. See ?predict.sarlm for more discussion. As a result, since the
#' original data can be recovered from the fit object, this method
#' currently does not take in `data` or `newdata` arguments.
#'
#' @export
#' @seealso [augment()]
#' @family spatialreg tidiers
augment.sarlm <- function(x, data = x$X, ...) {
  
  observed_name <- all.vars(x$call$formula)[1]
  
  reg <- x$X %>%
    as_augment_tibble() %>%
    dplyr::select(-.rownames) %>%
    dplyr::mutate(
      !!observed_name := x$y,
      .fitted = x$fitted.values,
      .resid = x$residuals
    )

  reg

}


#' @templateVar class spatialreg
#' @template title_desc_glance
#' 
#' @inherit tidy.sarlm params examples
#' 
#' @evalRd return_glance(
#'   "logLik", 
#'   "AIC", 
#'   "BIC",
#'   "deviance", 
#'   "logLik", 
#'   "nobs"
#' )
#' @export
#' @family spatialreg tidiers
#' @seealso [glance()], [spatialreg::lagsarlm()], [spatialreg::errorsarlm()], 
#' [spatialreg::sacsarlm()]
glance.sarlm <- function(x, ...) {
  
  res <- as_glance_tibble(
      # Using Pseudo R squared.
      r.squared = stats::cor(x$fitted.values, x$y)^2,
      AIC = stats::AIC(x),
      BIC = stats::BIC(x),
      deviance = stats::deviance(x),
      logLik = as.numeric(x$LL),
      nobs = length(x$fitted.values),
      na_types = "rrrrri"
    )
  
  res
}
