test_that("ggcoef_model()", {
  skip_on_cran()
  skip_if_not_installed("broom.helpers")
  skip_if_not_installed("reshape")

  data(tips, package = "reshape")
  mod_simple <- lm(tip ~ day + time + total_bill, data = tips)

  expect_doppelganger(
    "ggcoef_model() mod simple",
    ggcoef_model(mod_simple)
  )

  expect_doppelganger(
    "ggcoef_model() mod simple no guide",
    ggcoef_model(mod_simple, shape_guide = FALSE, colour_guide = FALSE)
  )

  expect_error(
    mod_simple |> ggcoef_dodged()
  )

  expect_error(
    mod_simple |> ggcoef_faceted()
  )

  # custom variable labels
  # you can use to define variable labels before computing model
  if (requireNamespace("labelled")) {
    tips_labelled <- tips |>
      labelled::set_variable_labels(
        day = "Day of the week",
        time = "Lunch or Dinner",
        total_bill = "Bill's total"
      )
    mod_labelled <- lm(tip ~ day + time + total_bill, data = tips_labelled)
    expect_doppelganger(
      "ggcoef_model() mod labelled",
      ggcoef_model(mod_labelled)
    )
  }

  expect_doppelganger(
    "ggcoef_model() mod simple with variable labels",
    ggcoef_model(
      mod_simple,
      variable_labels = c(
        day = "Week day",
        time = "Time (lunch or dinner ?)",
        total_bill = "Total of the bill"
      )
    )
  )

  # if labels are too long, you can use 'facet_labeller' to wrap them
  expect_doppelganger(
    "ggcoef_model() mod simple facet_labeller",
    ggcoef_model(
      mod_simple,
      variable_labels = c(
        day = "Week day",
        time = "Time (lunch or dinner ?)",
        total_bill = "Total of the bill"
      ),
      facet_labeller = ggplot2::label_wrap_gen(10)
    )
  )

  # do not display variable facets but add colour guide
  expect_doppelganger(
    "ggcoef_model() mod simple no variable facets",
    ggcoef_model(
      mod_simple,
      facet_row = NULL,
      colour_guide = TRUE
    )
  )

  # a logistic regression example
  d_titanic <- as.data.frame(Titanic)
  d_titanic$Survived <- factor(d_titanic$Survived, c("No", "Yes"))
  mod_titanic <- glm(
    Survived ~ Sex * Age + Class,
    weights = Freq,
    data = d_titanic,
    family = binomial
  )

  expect_doppelganger(
    "ggcoef_model() logistic regression",
    ggcoef_model(mod_titanic, exponentiate = TRUE)
  )

  # display intercept
  expect_doppelganger(
    "ggcoef_model() logistic regression with intercept",
    ggcoef_model(mod_titanic, exponentiate = TRUE, intercept = TRUE)
  )

  # display only a subset of terms
  expect_doppelganger(
    "ggcoef_model() logistic regression subset",
    ggcoef_model(mod_titanic, exponentiate = TRUE, include = c("Age", "Class"))
  )

  # do not change points' shape based on significance
  expect_doppelganger(
    "ggcoef_model() logistic regression no significance",
    ggcoef_model(mod_titanic, exponentiate = TRUE, significance = NULL)
  )

  # a black and white version
  expect_doppelganger(
    "ggcoef_model() logistic regression black and white",
    ggcoef_model(
      mod_titanic,
      exponentiate = TRUE,
      colour = NULL,
      stripped_rows = FALSE
    )
  )

  # show dichotomous terms on one row
  expect_doppelganger(
    "ggcoef_model() logistic regression no reference row",
    ggcoef_model(
      mod_titanic,
      exponentiate = TRUE,
      no_reference_row = broom.helpers::all_dichotomous(),
      categorical_terms_pattern =
        "{ifelse(dichotomous, paste0(level, ' / ', reference_level), level)}",
      show_p_values = FALSE
    )
  )

  # works also with with polynomial terms
  mod_poly <- lm(
    tip ~ poly(total_bill, 3) + day,
    data = tips,
  )
  expect_doppelganger(
    "ggcoef_model() polynomial terms",
    ggcoef_model(mod_poly)
  )

  # or with different type of contrasts
  # for sum contrasts, the value of the reference term is computed
  if (requireNamespace("emmeans")) {
    mod2 <- lm(
      tip ~ day + time + sex,
      data = tips,
      contrasts = list(time = contr.sum, day = contr.treatment(4, base = 3))
    )
    expect_doppelganger(
      "ggcoef_model() different types of contrasts",
      ggcoef_model(mod2)
    )
  }
})

test_that("ggcoef_compare()", {
  skip_if_not_installed("broom.helpers")
  skip_on_cran()

  # Use ggcoef_compare() for comparing several models on the same plot
  mod1 <- lm(Fertility ~ ., data = swiss)
  mod2 <- step(mod1, trace = 0)
  mod3 <- lm(Fertility ~ Agriculture + Education * Catholic, data = swiss)
  models <- list(
    "Full model" = mod1,
    "Simplified model" = mod2,
    "With interaction" = mod3
  )

  expect_doppelganger(
    "ggcoef_compare() dodged",
    ggcoef_compare(models)
  )

  expect_doppelganger(
    "ggcoef_compare() faceted",
    ggcoef_compare(models, type = "faceted")
  )

  expect_doppelganger(
    "ggcoef_compare() table",
    ggcoef_compare(models, type = "table")
  )

  d <- as.data.frame(Titanic)
  m1 <- glm(Survived ~ Sex + Age, family = binomial, data = d, weights = Freq)
  m2 <- glm(
    Survived ~ Sex + Age + Class,
    family = binomial,
    data = d,
    weights = Freq
  )
  models <- list("Model 1" = m1, "Model 2" = m2)

  expect_doppelganger(
    "ggcoef_compare() titanic dodged",
    ggcoef_compare(models)
  )

  expect_doppelganger(
    "ggcoef_compare() titanic faceted",
    ggcoef_compare(models, type = "faceted")
  )

  expect_doppelganger(
    "ggcoef_compare() titanic table",
    ggcoef_compare(models, type = "table")
  )

  rd <- ggcoef_compare(models, return_data = TRUE)
  expect_equal(
    levels(rd$label),
    c("Male", "Female", "Child", "Adult", "1st", "2nd", "3rd", "Crew")
  )

  expect_no_error(
    ggcoef_compare(models, add_reference_rows = FALSE)
  )
})

test_that("ggcoef_*() and multinom models", {
  skip_if_not_installed("broom.helpers")
  skip_if_not_installed("nnet")
  skip_on_cran()

  library(nnet)
  hec <- as.data.frame(HairEyeColor)
  mod <- multinom(
    Hair ~ Eye + Sex,
    data = hec,
    weights = hec$Freq
  )

  expect_doppelganger(
    "ggcoef_model() multinom",
    ggcoef_model(mod, exponentiate = TRUE)
  )

  expect_doppelganger(
    "ggcoef_table() multinom",
    ggcoef_table(mod, exponentiate = TRUE)
  )

  expect_doppelganger(
    "ggcoef_dodged() multinom",
    ggcoef_dodged(mod, exponentiate = TRUE)
  )

  expect_doppelganger(
    "ggcoef_faceted() multinom",
    ggcoef_faceted(mod, exponentiate = TRUE)
  )

  expect_doppelganger(
    "ggcoef_faceted() with custom group_labels",
    ggcoef_faceted(
      mod,
      group_labels = c("Brown" = "Brown\n(ref: Black)"),
      exponentiate = TRUE
    )
  )
})


test_that("ggcoef_model() works with tieders not returning p-values", {
  skip_if_not_installed("broom.helpers")
  skip_on_cran()

  mod <- lm(Sepal.Width ~ Species, iris)
  my_tidier <- function(x, ...) {
    x |>
      broom::tidy(...) |>
      dplyr::select(-dplyr::all_of("p.value"))
  }
  expect_doppelganger(
    "ggcoef_model() no p values",
    ggcoef_model(mod, tidy_fun = my_tidier)
  )
})

test_that("ggcoef_compare() complete NA respecting variables order", {
  skip_if_not_installed("broom.helpers")

  m1 <- lm(Fertility ~ Education + Catholic, data = swiss)
  m2 <- lm(Fertility ~ Education + Catholic + Agriculture, data = swiss)
  m3 <- lm(
    Fertility ~ Education + Catholic + Agriculture + Infant.Mortality,
    data = swiss
  )
  res <- ggcoef_compare(models = list(m1, m2, m3), return_data = TRUE)
  expect_equal(
    res$variable[1:4],
    structure(1:4, .Label = c(
      "Education", "Catholic", "Agriculture",
      "Infant.Mortality"
    ), class = "factor")
  )
})

test_that("ggcoef_compare() does not produce an error with an include", {
  skip_if_not_installed("survival")
  skip_if_not_installed("broom.helpers")
  skip_on_cran()
  m1 <- survival::coxph(
    survival::Surv(time, status) ~ prior + age,
    data = survival::veteran
  )
  m2 <- survival::coxph(
    survival::Surv(time, status) ~ prior + celltype,
    data = survival::veteran
  )
  models <- list("Model 1" = m1, "Model 2" = m2)

  expect_doppelganger(
    "ggcoef_compare() with include",
    ggcoef_compare(models, include = broom.helpers::starts_with("p"))
  )
})

test_that("ggcoef_model() works with pairwise contratst", {
  skip_if_not_installed("broom.helpers")
  skip_if_not_installed("emmeans")
  mod <- lm(Sepal.Length ~ Sepal.Width + Species, data = iris)
  expect_no_error(
    ggcoef_model(mod, add_pairwise_contrasts = TRUE)
  )
  expect_no_error(
    ggcoef_model(
      mod,
      add_pairwise_contrasts = TRUE,
      pairwise_variables = dplyr::starts_with("Sp"),
      keep_model_terms = TRUE
    )
  )
  mod2 <- lm(Sepal.Length ~ Species, data = iris)
  expect_no_error(
    ggcoef_compare(list(mod, mod2), add_pairwise_contrasts = TRUE)
  )
})

test_that("tidy_args is supported", {
  mod <- lm(Sepal.Length ~ Sepal.Width, data = iris)
  custom <- function(x, force = 1, ...) {
    broom::tidy(x, ...) |>
      dplyr::mutate(estimate = force)
  }
  res <- ggcoef_model(
    mod,
    tidy_fun = custom,
    tidy_args = list(force = 3),
    return_data = TRUE
  )
  expect_equal(res$estimate, 3)
})


test_that("ggcoef_table()", {
  skip_on_cran()
  skip_if_not_installed("broom.helpers")
  skip_if_not_installed("reshape")

  data(tips, package = "reshape")
  mod_simple <- lm(tip ~ day + time + total_bill, data = tips)

  expect_doppelganger(
    "ggcoef_table() mod simple",
    ggcoef_table(mod_simple)
  )

  expect_doppelganger(
    "ggcoef_table() table_stat",
    ggcoef_table(mod_simple, table_stat = c("p.value", "ci"))
  )

  expect_doppelganger(
    "ggcoef_table() table_header",
    ggcoef_table(mod_simple, table_header = c("A", "B", "C"))
  )

  expect_error(
    ggcoef_table(mod_simple, table_header = c("A", "B", "C", "D"))
  )

  expect_doppelganger(
    "ggcoef_table() table_text_size",
    ggcoef_table(mod_simple, table_text_size = 5)
  )

  expect_doppelganger(
    "ggcoef_table() table_stat_label ",
    ggcoef_table(
      mod_simple,
      table_stat_label = list(
        estimate = scales::label_percent(.1)
      )
    )
  )

  expect_doppelganger(
    "ggcoef_table() ci_pattern",
    ggcoef_table(mod_simple, ci_pattern = "{conf.low} to {conf.high}")
  )

  expect_doppelganger(
    "ggcoef_table() table_widths",
    ggcoef_table(mod_simple, table_widths = c(1, 2))
  )

  expect_doppelganger(
    "ggcoef_table() stripped_rows",
    ggcoef_table(mod_simple, stripped_rows = FALSE)
  )

  expect_doppelganger(
    "ggcoef_table() show_p_values & signif_stars",
    ggcoef_table(mod_simple, show_p_values = TRUE, signif_stars = TRUE)
  )

  expect_doppelganger(
    "ggcoef_table() show_p_values only",
    ggcoef_table(mod_simple, show_p_values = TRUE, signif_stars = FALSE)
  )

  expect_doppelganger(
    "ggcoef_table() signif_stars only",
    ggcoef_table(mod_simple, show_p_values = FALSE, signif_stars = TRUE)
  )

  expect_doppelganger(
    "ggcoef_table() customized statistics",
    ggcoef_table(
      mod_simple,
      table_stat = c("label", "estimate", "std.error", "ci"),
      ci_pattern = "{conf.low} to {conf.high}",
      table_stat_label = list(
        estimate = scales::label_number(accuracy = .01),
        conf.low = scales::label_number(accuracy = .1),
        conf.high = scales::label_number(accuracy = .1),
        std.error = scales::label_number(accuracy = .001),
        label = toupper
      ),
      table_header = c("Term", "Coef.", "SE", "CI"),
      table_widths = c(2, 3)
    )
  )
})

test_that("ggcoef_*() and multicomponents models", {
  skip_on_cran()
  skip_if_not_installed("broom.helpers")
  skip_if_not_installed("pscl")

  library(pscl)
  data("bioChemists", package = "pscl")
  mod <- zeroinfl(art ~ fem * mar | fem + mar, data = bioChemists)

  expect_doppelganger(
    "ggcoef_model() zeroinfl",
    ggcoef_model(mod)
  )

  expect_doppelganger(
    "ggcoef_table() zeroinfl",
    ggcoef_table(mod)
  )

  expect_doppelganger(
    "ggcoef_dodged() zeroinfl",
    ggcoef_dodged(mod)
  )

  expect_doppelganger(
    "ggcoef_faceted() zeroinfl",
    ggcoef_faceted(mod)
  )

  expect_doppelganger(
    "ggcoef_faceted() zeroinfl with custom group_labels",
    ggcoef_faceted(
      mod,
      group_labels = c(
        conditional = "Count",
        zero_inflated = "Zero-inflated"
      )
    )
  )
})
