## Loading relevant libraries for tests
library(testthat)
library(xml2)
library(tibble)
library(rtables)
library(dplyr)

# # Load and flag for pdftools to check for it
# check_pdf <- require(pdftools)


## eat the one-time warning
suppressWarnings(formatters::default_hsep())
makefakedat <- function(n = 1000) {
  datadf <- data.frame(
    stringsAsFactors = FALSE,
    ARM = c("ARM1", sample(c("ARM1", "ARM2"), n - 1, replace = TRUE)),
    SEX = c("M", sample(c("M", "F"), n - 1, replace = TRUE)),
    FACTOR2 = c("A", sample(c("A", "B", "C"), n - 1, replace = TRUE)),
    RACE = c("WHITE", sample(c("WHITE", "BLACK"), n - 1, replace = TRUE)),
    AGE = runif(n, 40, 70),
    VAR3 = c("level1", sample(c("level1", "level2"), n - 1,
      replace = TRUE
    ))
  )

  datadf$ethn_label <- c(WHITE = "Caucasian", BLACK = "African American")[datadf$RACE]
  datadf$fac2_label <- paste("Level", datadf$FACTOR2)
  datadf$gend_label <- c(M = "Male", F = "Female")[datadf$SEX]
  datadf
}



makefakedat2 <- function(n = 1000) {
  if (n %% 4 != 0) {
    stop("n not multiple of 4")
  }

  many2s <- rep(2, n / 2)
  datadf <- data.frame(
    stringsAsFactors = FALSE,
    ARM = rep(c("ARM1", "ARM2"), times = rep(n / 2, 2)),
    SEX = rep(
      sample(c("M", "F"), n / 2, replace = TRUE),
      many2s
    ),
    RACE = rep(sample(c("WHITE", "BLACK"), n / 2, replace = TRUE),
      times = many2s
    ),
    PATID = rep(seq(1, n / 2), many2s),
    VISIT = rep(c("BASELINE", "FOLLOWUP"))
  )
  datadf$ethn_label <- c(WHITE = "Caucasian", BLACK = "African American")[datadf$RACE]
  datadf$gend_label <- c(M = "Male", F = "Female")[datadf$SEX]
  mu <- 5 + (as.integer(factor(datadf$RACE)) + as.integer(factor(datadf$ARM)) + as.integer(factor(datadf$SEX))) / 2
  datadf$VALUE <- ifelse(
    datadf$VISIT == "BASELINE",
    5,
    5 + rnorm(n, mu, 4)
  )
  datadf$PCTDIFF <- NA_real_
  seconds <- seq(2, n, by = 2)
  datadf$PCTDIFF[seq(2, n, by = 2)] <- 100 * (datadf$VALUE[seconds] - datadf$VALUE[seconds - 1]) /
    datadf$VALUE[seconds - 1] # nolint

  datadf
}
set.seed(0)
rawdat <- makefakedat()
rawdat2 <- makefakedat2()

## used in multiple test files
refcompmean <- function(x, .ref_group, .in_ref_col, ...) {
  if (.in_ref_col) {
    val <- rcell(NULL)
  } else {
    val <- rcell(mean(x, ...) - mean(.ref_group, ...), format = "xx.xx")
  }

  in_rows(
    "Diff from reference - mean" = val
  )
}

complx_lyt_rnames <- c(
  "Caucasian (n)", "Level A", "Age Analysis", "mean", "median",
  "Age Analysis redux", "range", "Level B", "Age Analysis",
  "mean", "median", "Age Analysis redux", "range",
  "African American (n)", "Level A", "Age Analysis", "mean", "median",
  "Age Analysis redux", "range", "Level B", "Age Analysis",
  "mean", "median", "Age Analysis redux", "range",
  "level1", "level2"
)


make_big_lyt <- function() {
  lyt <- basic_table(show_colcounts = TRUE) %>%
    split_cols_by("ARM") %>%
    ## add nested column split on SEX with value lables from gend_label
    split_cols_by("SEX", "Gender", labels_var = "gend_label") %>%
    ## No row splits have been introduced, so this adds
    ## a root split and puts summary content on it labelled Overall (N)
    ## add_colby_total(label = "All") %>%
    ##    summarize_row_groups(label = "Overall (N)", format = "(N=xx)") %>%
    ## add a new subtable that splits on RACE, value labels from ethn_label
    split_rows_by("RACE", "Ethnicity", labels_var = "ethn_label", label_pos = "hidden") %>%
    summarize_row_groups("RACE", label_fstr = "%s (n)") %>%
    ##
    ## Add nested row split within Race categories for FACTOR2
    ## using a split function that excludes level C
    ## value labels from fac2_label
    split_rows_by("FACTOR2", "Factor2",
      split_fun = remove_split_levels("C"),
      labels_var = "fac2_label",
      label_pos = "hidden"
    ) %>%
    ## Add count summary within FACTOR2 categories
    summarize_row_groups("FACTOR2") %>%
    ## Add analysis/data rows by analyzing AGE variable
    ## Note afun is a function that returns 2 values in a named list
    ## this will create 2 data rows
    analyze(
      "AGE", "Age Analysis",
      afun = function(x) list(mean = mean(x), median = median(x)),
      format = "xx.xx"
    ) %>%
    ## adding more analysis vars "compounds them", placing them at the same
    ## level of nesting as all previous analysis blocks, rather than
    ## attempting to further nest them
    analyze("AGE",
      "Age Analysis redux",
      afun = range,
      format = "xx.x - xx.x",
      table_names = "AgeRedux"
    ) %>%
    ## Note nested=TRUE, this creates a NEW subtable directly under the
    ## root split
    ## afun of table() gives us k count rows, where k is the number of
    ## levels of VAR3, in this case 2.
    analyze("VAR3", "Var3 Counts", afun = list_wrap_x(table), nested = FALSE)
  lyt
}

export_fact <- function() {
  tbl2 <- NULL
  function() {
    if (is.null(tbl2)) {
      lyt <- basic_table() %>%
        split_cols_by("ARM") %>%
        split_cols_by("SEX", split_fun = keep_split_levels(c("M", "F"))) %>%
        split_rows_by("STRATA1") %>%
        summarize_row_groups() %>%
        split_rows_by("RACE", split_fun = keep_split_levels(c("WHITE", "ASIAN"))) %>%
        analyze(c("AGE", "BMRKR2", "COUNTRY"))

      tbl2 <<- build_table(lyt, ex_adsl)
    }
    tbl2
  }
}

tt_to_export <- export_fact()

# Creating data-set with wide content to test wrapping
tt_to_test_wrapping <- function() {
  trimmed_data <- ex_adsl %>%
    filter(SEX %in% c("M", "F")) %>%
    filter(RACE %in% levels(RACE)[1:2])

  levels(trimmed_data$ARM)[1] <- "Incredibly long column name to be wrapped"
  levels(trimmed_data$ARM)[2] <- "This_should_be_somewhere_split"

  basic_table(
    title = "Enough long title to be probably wider than expected",
    main_footer = "Also this seems quite wider than expected initially."
  ) %>%
    split_cols_by("ARM") %>%
    split_rows_by("RACE", split_fun = drop_split_levels) %>%
    analyze(c("AGE", "EOSDY"),
      na_str = "A very long content to_be_wrapped_and_splitted",
      inclNAs = TRUE
    ) %>%
    build_table(trimmed_data)
}

tt_for_wrap <- tt_to_test_wrapping()

tt_to_test_newline_chars <- function() {
  set.seed(1)
  DM_trick <- DM %>%
    mutate(ARM = "ARM \n\nA\n") %>%
    mutate(ARM2 = sample(c("TWO\nwords\n ", "A wo\n\nrd\n\n"),
      replace = TRUE, nrow(DM)
    )) # last \n is eaten up if no empty space
  levels(DM_trick$SEX)[3] <- "U\nN\nD\n"
  tbl <- basic_table() %>%
    split_rows_by("SEX",
      split_label = "m\nannaggia\nsda\n",
      label_pos = "visible"
    ) %>%
    split_cols_by("ARM") %>%
    split_cols_by("ARM2", split_label = "sda") %>%
    analyze("BMRKR1", na_str = "asd\nasd") %>%
    build_table(DM_trick)

  main_footer(tbl) <- c("main_footer: This", "is\na\n\nweird one\n")
  prov_footer(tbl) <- c("prov_footer: This", "is\na\n\nweird one\n")
  fnotes_at_path(tbl, rowpath = row_paths(tbl)[[6]]) <- c("a fancy footnote\ncrazy\n", "ahahha")
  top_left(tbl) <- c("\na", "b\nd\n\n", "c\n\n") # last \n is eaten up if empty line everywhere
  main_title(tbl) <- "why not\nalso here\n"
  tbl
}

tt_for_nl <- tt_to_test_newline_chars()

# Helper function in R base to count how many times a character appears in a string.
# W: this works only for counting single characters from a single string of txt
.count_chr_from_str <- function(str, chr, negate = FALSE) {
  if (negate) {
    nchar(gsub(chr, "", str, fixed = TRUE))
  } else {
    nchar(str) - nchar(gsub(chr, "", str, fixed = TRUE))
  }
}

# Utility function for section_div tests
check_pattern <- function(element, letter, len) {
  # Regular expression to match exactly len of the same letter
  regex <- paste0(rep(letter, len), collapse = "")
  return(grepl(regex, element, fixed = TRUE))
}
