#' Tidying methods for multinomial logistic regression models
#'
#' These methods tidy the coefficients of multinomial logistic regression
#' models generated by `multinom` of the `nnet` package.
#'
#' @param x A `multinom` object returned from [nnet::multinom()].
#' @template param_confint
#' @template param_exponentiate
#' @template param_unused_dots
#' 
#' @return `tidy.multinom` returns one row for each coefficient at each
#' level of the response variable, with six columns:
#'   \item{y.value}{The response level}
#'   \item{term}{The term in the model being estimated and tested}
#'   \item{estimate}{The estimated coefficient}
#'   \item{std.error}{The standard error from the linear model}
#'   \item{statistic}{Wald z-statistic}
#'   \item{p.value}{two-sided p-value}
#'
#' If `conf.int = TRUE`, also includes columns for `conf.low` and
#' `conf.high`.
#'
#' @examples
#'
#' if (require(nnet) & require(MASS)){
#'   library(nnet)
#'   library(MASS)
#'   
#'   example(birthwt)
#'   bwt.mu <- multinom(low ~ ., bwt)
#'   tidy(bwt.mu)
#'   glance(bwt.mu)
#'
#'   #* This model is a truly terrible model
#'   #* but it should show you what the output looks
#'   #* like in a multinomial logistic regression
#'
#'   fit.gear <- multinom(gear ~ mpg + factor(am), data = mtcars)
#'   tidy(fit.gear)
#'   glance(fit.gear)
#' }
#'
#' @aliases multinom_tidiers nnet_tidiers
#' @export
#' @family multinom tidiers
#' @seealso [tidy()], [nnet::multinom()]
tidy.multinom <- function(x, conf.int = FALSE, conf.level = .95,
                          exponentiate = TRUE, ...) {
  col_names <- if (length(x$lev) > 2) colnames(coef(x)) else names(coef(x))
  s <- summary(x)

  coef <- matrix(coef(s),
    byrow = FALSE,
    nrow = length(x$lev) - 1,
    dimnames = list(
      x$lev[-1],
      col_names
    )
  )
  se <- matrix(s$standard.errors,
    byrow = FALSE,
    nrow = length(x$lev) - 1,
    dimnames = list(
      x$lev[-1],
      col_names
    )
  )

  multinomRowToDf <- function(r, coef, se, col_names) {
    unrowname(data.frame(
      y.level = rep(r, length(col_names)),
      term = colnames(coef),
      estimate = coef[r, ],
      std.error = se[r, ],
      stringsAsFactors = FALSE
    ))
  }

  ret <- lapply(rownames(coef), multinomRowToDf, coef, se, col_names)
  ret <- do.call("rbind", ret)

  ret$statistic <- ret$estimate / ret$std.error
  ret$p.value <- stats::pnorm(abs(ret$statistic), 0, 1, lower.tail = FALSE) * 2

  if (conf.int) {
    ci <- apply(stats::confint(x), 2, function(a) unlist(as.data.frame(a)))
    ci <- as.data.frame(ci)
    names(ci) <- c("conf.low", "conf.high")
    ret <- cbind(ret, ci)
  }

  if (exponentiate) {
    
    to_exp <- "estimate"
    
    if (conf.int) {
      to_exp <- c(to_exp, "conf.low", "conf.high")
    }
    
    # TODO: use mutate_at
    ret[, to_exp] <- lapply(ret[, to_exp, drop = FALSE], exp)
  }

  as_tibble(ret)
}

#' @templateVar class multinom
#' @template title_desc_glance
#' 
#' @inheritParams tidy.multinom
#' 
#' @return A one-row [tibble::tibble] with columns:
#' 
#'   \item{edf}{The effective degrees of freedom}
#'   \item{deviance}{deviance}
#'   \item{AIC}{the Akaike Information Criterion}
#'
#' @export
#' @family multinom tidiers
#' @seealso [glance()], [nnet::multinom()]
glance.multinom <- function(x, ...) {
  with(
    x,
    tibble(
      edf = edf,
      deviance = deviance,
      AIC = AIC
    )
  )
}
