#' Simple Slopes Analysis
#'
#' Computes simple slopes for moderation analysis.
#'
#' @param object A fitted model
#' @param values Moderator values at which to compute slopes
#'
#' @return A data frame of slopes
#' @importFrom stats coef vcov lm df.residual pt pnorm qnorm qt
#' @importFrom sandwich vcovHC
#'
#' @examples
#' set.seed(123)
#'
#' n <- 100
#' x <- rnorm(n)
#' z <- 0.5 * x + sqrt(1 - 0.5^2) * rnorm(n)
#'
#' y <- 0.3 * x + 0.3 * z + 0.8 * x * z + rnorm(n)
#'
#' data <- data.frame(x, z, y)
#'
#' result <- moderated_regression(data, iv = "x", moderator = "z", dv = "y")
#'
#' simple_slopes(result)
#'
#' @export

simple_slopes <- function(object, values = NULL) {

  if (!inherits(object, "modlr")) stop("object must be of class modlr")

  data <- object$data
  type_mod <- object$type_moderator

  iv  <- object$iv
  mod <- object$moderator
  dv  <- object$dv


  # -------------------------------
  # Variable names (ALIGN WITH CENTERING)
  # -------------------------------
  if (object$center) {
    iv_name  <- paste0(iv, "_center")
    mod_name <- paste0(mod, "_center")
  } else {
    iv_name  <- iv
    mod_name <- mod
}

  # Use raw model

  mod_raw <- object$model


  b <- coef(mod_raw)

  # Variance structure
  if (object$robust_se) {
    vc <- sandwich::vcovHC(mod_raw, type = "HC3")
    crit <- qnorm(0.975)
  } else {
    vc <- vcov(mod_raw)
    crit <- qt(0.975, df.residual(mod_raw))
  }

  # SAFE coefficient extraction
  b1_name <- iv_name
  b3_name1 <- paste0(iv_name, ":", mod_name)
  b3_name2 <- paste0(mod_name, ":", iv_name)

  if (!b1_name %in% names(b)) stop("IV not found")

  if (b3_name1 %in% names(b)) {
    b3_name <- b3_name1
  } else if (b3_name2 %in% names(b)) {
    b3_name <- b3_name2
  } else if ("int_term" %in% names(b)) {
    b3_name <- "int_term"
  } else {
    stop("Interaction term not found")
  }

  b1 <- b[b1_name]
  b3 <- b[b3_name]

  # Variance components
  var_b1 <- vc[b1_name, b1_name]
  var_b3 <- vc[b3_name, b3_name]
  cov_b1b3 <- vc[b1_name, b3_name]

  # ===============================
  # BINARY MODERATOR
  # ===============================
  if (type_mod == "binary") {

    slope_0 <- b1
    slope_1 <- b1 + b3

    var_0 <- var_b1
    var_1 <- var_b1 + var_b3 + 2 * cov_b1b3

    se_0 <- sqrt(var_0)
    se_1 <- sqrt(var_1)

    t_0 <- slope_0 / se_0
    t_1 <- slope_1 / se_1

    if (object$robust_se) {
      p_0 <- 2 * (1 - pnorm(abs(t_0)))
      p_1 <- 2 * (1 - pnorm(abs(t_1)))
    } else {
      df_res <- df.residual(mod_raw)
      p_0 <- 2 * pt(abs(t_0), df_res, lower.tail = FALSE)
      p_1 <- 2 * pt(abs(t_1), df_res, lower.tail = FALSE)
    }

    results <- data.frame(
      Moderator = c("0", "1"),
      Slope = round(c(slope_0, slope_1), 3),
      SE = round(c(se_0, se_1), 3),
      t = round(c(t_0, t_1), 3),
      p_value = round(c(p_0, p_1), 4)
    )

  } else {

    # ===============================
    # CONTINUOUS MODERATOR
    # ===============================

    z <- data[[mod]]

    if (is.null(values)) {
      z_mean <- mean(z, na.rm = TRUE)
      z_sd   <- sd(z, na.rm = TRUE)
      values <- c(z_mean - z_sd, z_mean, z_mean + z_sd)
      labels <- c("M - 1 SD", "M (Mean)", "M + 1 SD")
    } else {
      labels <- paste("z =", round(values, 3))
    }

    results <- data.frame(
      Moderator_Level = labels,
      Moderator_Value = round(values, 3),
      Slope = NA, SE = NA, t = NA, p_value = NA
    )

    for (i in seq_along(values)) {

      z_val <- values[i]

      slope <- b1 + b3 * z_val

      var_slope <- var_b1 + z_val^2 * var_b3 + 2 * z_val * cov_b1b3
      se_slope <- sqrt(var_slope)

      t_val <- slope / se_slope

      if (object$robust_se) {
        p_val <- 2 * (1 - pnorm(abs(t_val)))
      } else {
        p_val <- 2 * pt(abs(t_val), df.residual(mod_raw), lower.tail = FALSE)
      }

      results$Slope[i]   <- round(slope, 3)
      results$SE[i]      <- round(se_slope, 3)
      results$t[i]       <- round(t_val, 3)
      results$p_value[i] <- round(p_val, 4)
    }
  }

  message("\n========================================\n")
  message("SIMPLE SLOPES ANALYSIS\n")
  message("========================================\n")

  if (object$robust_se) {
    message("(Using HC3 robust standard errors)\n")
  }

  # -------------------------------
  # Covariate note
  # -------------------------------
  if (!is.null(object$covariates) && length(object$covariates) > 0) {
    message("Note: Results are conditional on the included covariates (held constant).\n")
  }

  return(results)


}
