#' Two-Factor ANOVA for Agricultural Experimental Designs
#'
#' Performs analysis of variance for two-factor experiments
#' Factorial CRD (FCRD), Factorial RBD (FRBD), Split-Plot, and Strip-Plot designs.
#'
#' @param data A data frame containing experimental data.
#' @param design Type of design "FCRD", "FRBD", "SPLIT" or "STRIP".
#' @param factor_A Name of Factor A column in the dataset.
#' @param factor_B Name of Factor B column in the dataset.
#' @param replication Name of replication/block column (required for FRBD, SPLIT, STRIP).
#' @param responsevar Specific variables c("v1" ,"v2", "v3") or "all".
#' @param test Mean comparison test. Options include"lsd", "tukey", or "duncan".
#' @param transform List or character specifying transformations ("log", "sqrt", "arcsine").
#' @param narc Numeric or list specifying denominator for arcsine transformation.
#' @param alpha Significance level (default 0.05).
#'
#' @return A list containing:
#' \describe{
#'   \item{Individual outputs}{
#'     Analysis results for each response variable separately.
#'   }
#'   \item{Summary statistics}{
#'     Arithmetic mean, standard deviation, minimum, and maximum values for each variable.
#'   }
#'   \item{Shapiro-Wilk test}{
#'     Results of the Shapiro-Wilk test for normality.
#'   }
#'   \item{ANOVA and mean comparison}{
#'     ANOVA table along with mean comparison based on the selected test for each response variable.
#'   }
#'   \item{Combined table}{
#'     A summary table -two way including mean ± SD, grouping letters, SEm, SEd, CD, and CV values for all variables.
#'   }
#' }#'
#' @importFrom stats anova as.formula ave sd setNames
#' @importFrom stats aov reformulate pf qt qtukey shapiro.test na.omit
#' @importFrom multcompView multcompLetters
#' @importFrom utils combn as.roman
#'
#' @examples
#' #Rice dataset with Factor A as TRT and Factor B as SPACE and replications in "BLOCK" column
#' data("Gnutdataset")
#' "head(Ricedataset)"
#'
#' #Example: Factorial CRD
#' out <- aov_tf(
#'   Ricedataset,
#'   design = "FCRD",
#'   factor_A = "TRT",
#'   factor_B = "SPACE",
#'   replication = "BLOCK",
#'   responsevar = "all",
#'   test = "lsd",
#'   transform = NULL,
#'   narc = 1,
#'   alpha = 0.05
#' )
#'
#' #Example: Split-plot with transformation
#' out2 <- aov_tf(
#'   Ricedataset,
#'   design = "SPLIT",
#'   factor_A = "TRT",
#'   factor_B = "SPACE",
#'   replication = "BLOCK",
#'   responsevar = "all",
#'   test = "lsd",
#'   transform = list(GPP = "log", Disease = "arcsine"),
#'   narc = list(Disease = 5),
#'   alpha = 0.05
#' )
#'
#' out2$PH
#' out2$GPP
#'
#' @export

aov_tf <- function(data,
                                   design = c("FCRD", "FRBD", "SPLIT", "STRIP"),
                                   factor_A,
                                   factor_B,
                                   replication = NULL,
                                   responsevar = "all",
                                   test = c("lsd", "tukey", "duncan"),
                                   transform = NULL,
                                   narc = 1,
                                   alpha = 0.05) {


  design <- match.arg(design)
  test   <- match.arg(test)

  # ---- Input validation helpers ----
  .check_name <- function(x, nm) {
    if (is.null(x) || length(x) != 1 || is.na(x) || !is.character(x) || !nzchar(trimws(x))) {
      stop(sprintf("'%s' must be a single non-empty column name", nm), call. = FALSE)
    }
    trimws(x)
  }

  factor_A <- .check_name(factor_A, "factor_A")
  factor_B <- .check_name(factor_B, "factor_B")

  # Column existence
  missing_cols <- setdiff(c(factor_A, factor_B), names(data))
  if (length(missing_cols) > 0) {
    stop("Column(s) not found in data: ", paste(missing_cols, collapse = ", "), call. = FALSE)
  }

  # Convert to factors
  for (f in c(factor_A, factor_B)) {
    if (!is.factor(data[[f]])) data[[f]] <- as.factor(data[[f]])
  }

  # Replication handling
  if (design %in% c("FRBD", "SPLIT", "STRIP")) {
    replication <- .check_name(replication, "replication")
    if (!replication %in% names(data)) {
      stop("Column not found in data: ", replication, call. = FALSE)
    }
    if (!is.factor(data[[replication]])) data[[replication]] <- as.factor(data[[replication]])
  }


  # Smart numeric level ordering (only if all levels look numeric)
  for (f in c(factor_A, factor_B)) {
    levs <- levels(data[[f]])
    num_part <- suppressWarnings(as.numeric(gsub("[^0-9]", "", levs)))
    if (!any(is.na(num_part)) && length(num_part) > 0) {
      data[[f]] <- factor(data[[f]], levels = levs[order(num_part)])
    }
  }

  # Formatting helpers
  fmtv  <- function(x) format(round(as.numeric(x), 2), nsmall = 2, trim = TRUE)
  fmtv2 <- function(x) format(round(as.numeric(x), 3), nsmall = 3, trim = TRUE)
  fmtP  <- function(x) {
    x <- as.numeric(x)
    ifelse(is.na(x), "", ifelse(x < 0.001, "<0.001", format(x, digits = 3)))
  }

  sig_star <- function(p) {
    p <- as.numeric(p)
    if (is.na(p)) return("")
    if (p <= 0.001) "***" else if (p <= 0.01) "**" else if (p <= 0.05) "*" else "NS"
  }

  # Select responses
  if (identical(responsevar, "all") || identical(responsevar[1], "all")) {
    responses <- names(data)[sapply(data, is.numeric)]
  } else {
    responses <- responsevar
  }

  missing_vars <- setdiff(responses, names(data))
  if (length(missing_vars) > 0) {
    stop("Variables not found: ", paste(missing_vars, collapse = ", "))
  }
  non_num <- responses[!sapply(data[responses], is.numeric)]
  if (length(non_num) > 0) {
    stop("Non-numeric variables: ", paste(non_num, collapse = ", "))
  }

  # Transform and narc lists
  transform_list <- setNames(rep(list(NULL), length(responses)), responses)
  if (!is.null(transform)) {
    if (is.character(transform) && length(transform) == 1) {
      transform_list[] <- transform
    } else if (is.list(transform) || is.character(transform)) {
      for (v in intersect(names(transform), responses)) {
        transform_list[[v]] <- transform[[v]]
      }
    }
  }

  narc_list <- setNames(rep(1L, length(responses)), responses)
  if (!is.null(narc)) {
    if (is.numeric(narc) && length(narc) == 1) {
      narc_list[] <- as.integer(narc)
    } else if (is.list(narc)) {
      for (v in intersect(names(narc), responses)) {
        val <- narc[[v]]
        if (is.numeric(val) && val == floor(val) && val >= 1) {
          narc_list[[v]] <- as.integer(val)
        }
      }
    }
  }

  results <- list()
  for (resp in responses) {
    y_original <- data[[resp]]
    y <- y_original
    transformed <- FALSE
    this_trans <- transform_list[[resp]]
    this_narc  <- narc_list[[resp]]

    if (!is.null(this_trans)) {
      method <- tolower(this_trans)
      if (method == "log") {
        y <- log(y_original + ifelse(any(y_original <= 0, na.rm = TRUE), 0.5, 0))
      } else if (method == "sqrt") {
        y <- sqrt(y_original + ifelse(any(y_original == 0, na.rm = TRUE), 0.5, 0))
      } else if (method %in% c("arcsine", "arcsin", "asin")) {
        y2 <- pmin(pmax(y_original, 0), 100)
        adj <- 1 / (4 * this_narc)
        y2[y2 == 0]   <- adj
        y2[y2 == 100] <- 100 - adj
        y <- asin(sqrt(y2 / 100)) * 180 / pi
      } else {
        warning("Unsupported transformation '", this_trans, "' for ", resp, call. = FALSE)
      }
      transformed <- TRUE
    }

    data[[".Ytmp"]] <- y

    # Summary & Normality
    summary_table <- data.frame(
      Data = "Original",
      Mean = round(mean(y_original, na.rm = TRUE), 4),
      SD   = round(sd(y_original, na.rm = TRUE), 4),
      Min  = round(min(y_original, na.rm = TRUE), 4),
      Max  = round(max(y_original, na.rm = TRUE), 4),
      stringsAsFactors = FALSE
    )

    normalitytest <- data.frame(
      Data = "Original",
      W = fmtv2(shapiro.test(y_original)$statistic),
      `P-value` = fmtP(shapiro.test(y_original)$p.value),
      Normal = ifelse(shapiro.test(y_original)$p.value > alpha, "YES", "NO"),
      stringsAsFactors = FALSE
    )

    if (transformed) {
      summary_table <- rbind(summary_table,
                             data.frame(Data = "Transformed",
                                        Mean = round(mean(y, na.rm = TRUE), 4),
                                        SD = round(sd(y, na.rm = TRUE), 4),
                                        Min = round(min(y, na.rm = TRUE), 4),
                                        Max = round(max(y, na.rm = TRUE), 4),
                                        stringsAsFactors = FALSE))
      normalitytest <- rbind(normalitytest,
                             data.frame(Data = "Transformed",
                                        W = fmtv2(shapiro.test(y)$statistic),
                                        `P-value` = fmtP(shapiro.test(y)$p.value),
                                        Normal = ifelse(shapiro.test(y)$p.value > alpha, "YES", "NO"),
                                        stringsAsFactors = FALSE))
    }

    # ---------------- Model formula ----------------
    form <- switch(design,
                   FCRD = reformulate(c(factor_A, factor_B, paste0(factor_A, ":", factor_B)), response = ".Ytmp"),
                   FRBD = reformulate(c(replication, factor_A, factor_B, paste0(factor_A, ":", factor_B)), response = ".Ytmp"),
                   SPLIT = reformulate(c(replication, factor_A, paste0(replication, ":", factor_A),
                                         factor_B, paste0(factor_A, ":", factor_B)), response = ".Ytmp"),
                   STRIP = reformulate(c(replication, factor_A, factor_B,
                                         paste0(replication, ":", factor_A),
                                         paste0(replication, ":", factor_B),
                                         paste0(factor_A, ":", factor_B)), response = ".Ytmp")
    )

    fit <- aov(form, data = data)
    tab <- anova(fit)
    src <- rownames(tab)

    get_stat <- function(term) {
      if (term %in% src) {
        c(Df = tab[term, "Df"], SS = tab[term, "Sum Sq"], MS = tab[term, "Mean Sq"])
      } else {
        c(Df = NA_real_, SS = NA_real_, MS = NA_real_)
      }
    }

    repT  <- get_stat(replication)
    A_T   <- get_stat(factor_A)
    B_T   <- get_stat(factor_B)
    AB_T  <- get_stat(paste(factor_A, factor_B, sep = ":"))
    repA  <- get_stat(paste(replication, factor_A, sep = ":"))
    repB  <- get_stat(paste(replication, factor_B, sep = ":"))
    resid <- get_stat("Residuals")

    # Error terms and F-values
    if (design %in% c("FCRD", "FRBD")) {
      err_ms_A <- err_ms_B <- err_ms_AB <- resid["MS"]
      err_df_A <- err_df_B <- err_df_AB <- resid["Df"]
      F_A  <- A_T["MS"] / resid["MS"]
      F_B  <- B_T["MS"] / resid["MS"]
      F_AB <- AB_T["MS"] / resid["MS"]
    } else if (design == "SPLIT") {
      err_ms_A <- repA["MS"]; err_df_A <- repA["Df"]
      err_ms_B <- err_ms_AB <- resid["MS"]; err_df_B <- err_df_AB <- resid["Df"]
      F_A  <- A_T["MS"] / repA["MS"]
      F_B  <- B_T["MS"] / resid["MS"]
      F_AB <- AB_T["MS"] / resid["MS"]
    } else { # STRIP
      err_ms_A <- repA["MS"]; err_df_A <- repA["Df"]
      err_ms_B <- repB["MS"]; err_df_B <- repB["Df"]
      err_ms_AB <- resid["MS"]; err_df_AB <- resid["Df"]
      F_A  <- A_T["MS"] / repA["MS"]
      F_B  <- B_T["MS"] / repB["MS"]
      F_AB <- AB_T["MS"] / resid["MS"]
    }

    p_A  <- pf(F_A,  A_T["Df"], err_df_A,  lower.tail = FALSE)
    p_B  <- pf(F_B,  B_T["Df"], err_df_B,  lower.tail = FALSE)
    p_AB <- pf(F_AB, AB_T["Df"], err_df_AB, lower.tail = FALSE)

    # ANOVA table
    anova_rows <- switch(design,
                         "FCRD" = list(
                           c(paste("Factor A (", factor_A, ")", sep=""), A_T["Df"], fmtv(A_T["SS"]), fmtv(A_T["MS"]), fmtv(F_A), fmtP(p_A), sig_star(p_A)),
                           c(paste("Factor B (", factor_B, ")", sep=""), B_T["Df"], fmtv(B_T["SS"]), fmtv(B_T["MS"]), fmtv(F_B), fmtP(p_B), sig_star(p_B)),
                           c(paste(factor_A,":", factor_B), AB_T["Df"], fmtv(AB_T["SS"]), fmtv(AB_T["MS"]), fmtv(F_AB), fmtP(p_AB), sig_star(p_AB)),
                           c("Residual", resid["Df"], fmtv(resid["SS"]), fmtv(resid["MS"]), "", "", "")
                         ),
                         "FRBD" = list(
                           c(paste("Replication (", replication, ")", sep=""), repT["Df"], fmtv(repT["SS"]), fmtv(repT["MS"]), "", "", ""),
                           c(paste("Factor A (", factor_A, ")", sep=""), A_T["Df"], fmtv(A_T["SS"]), fmtv(A_T["MS"]), fmtv(F_A), fmtP(p_A), sig_star(p_A)),
                           c(paste("Factor B (", factor_B, ")", sep=""), B_T["Df"], fmtv(B_T["SS"]), fmtv(B_T["MS"]), fmtv(F_B), fmtP(p_B), sig_star(p_B)),
                           c(paste(factor_A, ":", factor_B), AB_T["Df"], fmtv(AB_T["SS"]), fmtv(AB_T["MS"]), fmtv(F_AB), fmtP(p_AB), sig_star(p_AB)),
                           c("Residual", resid["Df"], fmtv(resid["SS"]), fmtv(resid["MS"]), "", "", "")
                         ),
                         "SPLIT" = list(
                           c(paste("Replication (", replication, ")", sep=""), repT["Df"], fmtv(repT["SS"]), fmtv(repT["MS"]), "", "", ""),
                           c(paste("Factor A (", factor_A, ")", sep=""), A_T["Df"], fmtv(A_T["SS"]), fmtv(A_T["MS"]), fmtv(F_A), fmtP(p_A), sig_star(p_A)),
                           c("Err A", repA["Df"], fmtv(repA["SS"]), fmtv(repA["MS"]), "", "", ""),
                           c(paste("Factor B (", factor_B, ")", sep=""), B_T["Df"], fmtv(B_T["SS"]), fmtv(B_T["MS"]), fmtv(F_B), fmtP(p_B), sig_star(p_B)),
                           c(paste(factor_A, ":", factor_B), AB_T["Df"], fmtv(AB_T["SS"]), fmtv(AB_T["MS"]), fmtv(F_AB), fmtP(p_AB), sig_star(p_AB)),
                           c("Err B", resid["Df"], fmtv(resid["SS"]), fmtv(resid["MS"]), "", "", "")
                         ),
                         list( # STRIP
                           c(paste("Replication (", replication, ")", sep=""), repT["Df"], fmtv(repT["SS"]), fmtv(repT["MS"]), "", "", ""),
                           c(paste("Factor A (", factor_A, ")", sep=""), A_T["Df"], fmtv(A_T["SS"]), fmtv(A_T["MS"]), fmtv(F_A), fmtP(p_A), sig_star(p_A)),
                           c("Err A", repA["Df"], fmtv(repA["SS"]), fmtv(repA["MS"]), "", "", ""),
                           c(paste("Factor B (", factor_B, ")", sep=""), B_T["Df"], fmtv(B_T["SS"]), fmtv(B_T["MS"]), fmtv(F_B), fmtP(p_B), sig_star(p_B)),
                           c("Err B", repB["Df"], fmtv(repB["SS"]), fmtv(repB["MS"]), "", "", ""),
                           c(paste(factor_A, ":", factor_B), AB_T["Df"], fmtv(AB_T["SS"]), fmtv(AB_T["MS"]), fmtv(F_AB), fmtP(p_AB), sig_star(p_AB)),
                           c("Err C", resid["Df"], fmtv(resid["SS"]), fmtv(resid["MS"]), "", "", "")
                         )
    )

    anova_tab <- as.data.frame(do.call(rbind, anova_rows), stringsAsFactors = FALSE)
    colnames(anova_tab) <- c("Source", "DF", "SS", "MS", "F", "P-value", "Signif")


    # Mean table helper (moved inside but kept logic)
    make_mean_table <- function(grp, divisor, overall_p, resp_y = y, y_orig = y_original,
                                error_ms = resid["MS"], error_df = resid["Df"]) {

      means_tr   <- tapply(resp_y,  grp, mean, na.rm = TRUE)
      sd_tr      <- tapply(resp_y,  grp, sd,   na.rm = TRUE)
      means_orig <- tapply(y_orig, grp, mean, na.rm = TRUE)
      sd_orig    <- tapply(y_orig, grp, sd,   na.rm = TRUE)

      all_lev <- levels(grp)
      means_tr   <- means_tr[all_lev]
      sd_tr      <- sd_tr[all_lev]
      means_orig <- means_orig[all_lev]
      sd_orig    <- sd_orig[all_lev]

      SEm <- sqrt(error_ms / divisor)
      SEd <- sqrt(2 * error_ms / divisor)
      CD  <- qt(1 - alpha/2, error_df) * SEd
      HSD <- if (test == "tukey") qtukey(1 - alpha, length(means_tr), error_df) * SEm else CD

      CV <- sqrt(error_ms) / mean(resp_y, na.rm = TRUE) * 100

      letters_grp <- rep("", length(means_tr))
      names(letters_grp) <- names(means_tr)

      if (overall_p <= alpha && length(means_tr) >= 2) {
        ord <- order(means_tr, decreasing = TRUE)
        m_sorted <- means_tr[ord]
        n_sorted <- names(m_sorted)
        diffmat <- abs(outer(m_sorted, m_sorted, `-`))
        sig <- matrix(FALSE, length(m_sorted), length(m_sorted))

        if (test == "lsd") sig <- diffmat > CD
        else if (test == "tukey") sig <- diffmat > HSD
        else if (test == "duncan") {
          R <- numeric(length(m_sorted))
          for (k in 2:length(m_sorted)) {
            qv <- qtukey(1 - alpha, nmeans = k, df = error_df) / sqrt(2)
            R[k] <- qv * sqrt(error_ms / divisor)
          }
          for (i in 1:(length(m_sorted)-1)) {
            for (j in (i+1):length(m_sorted)) {
              if (diffmat[i,j] >= R[j-i+1]) sig[i,j] <- TRUE
            }
          }
          sig <- sig | t(sig)
        }
        diag(sig) <- FALSE
        pairs <- sig[lower.tri(sig)]
        names(pairs) <- combn(n_sorted, 2, paste, collapse = "-")
        let <- multcompView::multcompLetters(pairs)$Letters
        letters_grp <- let[match(names(means_tr), names(let))]
        letters_grp[is.na(letters_grp)] <- ""
      }

      if (transformed) {
        values <- paste0(fmtv(means_orig), " +- ", fmtv(sd_orig),
                         " (", fmtv(means_tr), " +- ", fmtv(sd_tr), ")",
                         ifelse(nzchar(letters_grp), paste0(" ", letters_grp), ""))
      } else {
        values <- paste0(fmtv(means_orig), " +- ", fmtv(sd_orig),
                         ifelse(nzchar(letters_grp), paste0(" ", letters_grp), ""))
      }

      display_table <- data.frame(Level = names(means_tr), Value = values, stringsAsFactors = FALSE)

      stats_list <- list(
        data.frame(Level = "SEm+-", Value = fmtv(SEm), stringsAsFactors = FALSE),
        data.frame(Level = "SEd+-", Value = fmtv(SEd), stringsAsFactors = FALSE)
      )

      if (overall_p <= alpha) {
        if (test == "lsd") stats_list[[3]] <- data.frame(Level = "CD", Value = fmtv(CD), stringsAsFactors = FALSE)
        else if (test == "tukey") stats_list[[3]] <- data.frame(Level = "HSD", Value = fmtv(HSD), stringsAsFactors = FALSE)
      } else if (test %in% c("lsd", "tukey")) {
        crit_label <- ifelse(test == "tukey", "HSD", "CD")
        stats_list[[3]] <- data.frame(Level = crit_label, Value = "NS", stringsAsFactors = FALSE)
      }

      stats_list[[length(stats_list) + 1]] <- data.frame(Level = "CV%", Value = fmtv(CV), stringsAsFactors = FALSE)

      stats_df <- do.call(rbind, stats_list)

      if (transformed) {
        numeric_df <- data.frame(Level = names(means_orig), AVG = means_orig, STD = sd_orig,
                                 AVGt = means_tr, STDt = sd_tr, Ltr = letters_grp,
                                 stringsAsFactors = FALSE, row.names = NULL)
      } else {
        numeric_df <- data.frame(Level = names(means_orig), AVG = means_orig, STD = sd_orig,
                                 Ltr = letters_grp, stringsAsFactors = FALSE, row.names = NULL)
      }

      list(table = rbind(display_table, stats_df), numeric = numeric_df)
    }

    # Compute mean tables
    A_fac <- data[[factor_A]]
    B_fac <- data[[factor_B]]
    AB_fac <- interaction(A_fac, B_fac, sep = ":")

    n_A <- nlevels(A_fac)
    n_B <- nlevels(B_fac)
    r <- length(na.omit(y)) / (n_A * n_B)

    res_A  <- make_mean_table(A_fac, r * n_B, p_A, y, y_original, err_ms_A, err_df_A)
    res_B  <- make_mean_table(B_fac, r * n_A, p_B, y, y_original, err_ms_B, err_df_B)
    res_AB <- make_mean_table(AB_fac, r, p_AB, y, y_original, err_ms_AB, err_df_AB)

    table_A  <- res_A$table
    table_B  <- res_B$table
    table_AB <- res_AB$table

    outm_A  <- res_A$numeric
    outm_B  <- res_B$numeric
    outm_AB <- res_AB$numeric

    # Interaction Matrix
    lev_A <- levels(A_fac)
    lev_B <- levels(B_fac)

    mat <- matrix("", nrow = length(lev_A), ncol = length(lev_B) + 1)
    rownames(mat) <- lev_A
    colnames(mat) <- c(lev_B, "MeanA")

    for (i in seq_len(nrow(table_AB))) {
      lev <- table_AB$Level[i]
      if (!grepl(":", lev, fixed = TRUE)) next
      sp <- strsplit(lev, ":", fixed = TRUE)[[1]]
      if (length(sp) == 2 && sp[1] %in% lev_A && sp[2] %in% lev_B) {
        mat[sp[1], sp[2]] <- table_AB$Value[i]
      }
    }

    idx_A <- match(lev_A, table_A$Level)
    mat[, "MeanA"] <- ifelse(is.na(idx_A), "", table_A$Value[idx_A])

    idx_B <- match(lev_B, table_B$Level)
    meanB_vec <- ifelse(is.na(idx_B), "", table_B$Value[idx_B])
    mat <- rbind(mat, MeanB = c(meanB_vec, ""))

    mat[nrow(mat), ] <- toupper(mat[nrow(mat), ])
    mat[, ncol(mat)] <- toupper(mat[, ncol(mat)])

    Interaction_Table <- as.data.frame(mat, stringsAsFactors = FALSE)

    # SE Summary
    se_row_names <- table_A$Level[(n_A + 1):nrow(table_A)]

    SE_table <- data.frame(
      row.names = se_row_names,
      A  = table_A$Value[(n_A + 1):nrow(table_A)],
      B  = table_B$Value[(n_B + 1):nrow(table_B)],
      AB = table_AB$Value[(n_A * n_B + 1):nrow(table_AB)],
      check.names = FALSE,
      stringsAsFactors = FALSE
    )

    results[[resp]] <- list(
      Summary = summary_table,
      Normality = normalitytest,
      ANOVA = anova_tab,
      Main_A = table_A,
      Main_B = table_B,
      Interaction_AB = table_AB,
      outmA = outm_A,
      outmB = outm_B,
      outmAB = outm_AB,
      InteractionMatrix = Interaction_Table,
      SE_summary = SE_table
    )
  }

  # Combined tables (your original combine_tables function is fine)
  combine_tables <- function(results, element) {
    vars <- names(results)

    tabs <- lapply(vars, function(v) {
      tab <- results[[v]][[element]]
      tab$blank_col <- ""   # FIXED
      tab
    })

    out <- do.call(cbind, tabs)

    out <- cbind(Stat = rownames(results[[vars[1]]][[element]]), out)

    k <- ncol(results[[vars[1]]][[element]])

    mainhead <- c(" ", unlist(lapply(vars, function(v) c(v, rep("", k)))))  # FIXED

    if (element == "InteractionMatrix") {
      subhead <- c(" ", rep(c(colnames(results[[vars[1]]][[element]]), ""), length(vars)))  # FIXED
      out <- rbind(mainhead, subhead, out)
    } else {
      subhead <- c("Stat", rep(c(colnames(results[[vars[1]]][[element]]), ""), length(vars)))
      out <- rbind(mainhead, subhead, out)
    }

    return(out)
  }

  combined_interaction <- combine_tables(results, "InteractionMatrix")
  combined_se <- combine_tables(results, "SE_summary")

  results$Combined_Interaction <- combined_interaction
  results$Combined_SEtab <- combined_se

  return(results)
}
