#' Efficiency Measures for p-Rep Test-Control Designs
#'
#' Computes efficiency measures for partially replicated
#' test-control designs. Test treatments are identified from
#' numeric labels such as \code{1}, \code{2}, and \code{3}.
#' Control treatments must use labels beginning with \code{C},
#' such as \code{C1}, \code{C2}, and so on.
#'
#' The function calculates average variance for test-versus-test
#' comparisons, average variance for test-versus-control comparisons,
#' and the canonical efficiency factor.
#'
#' @param design A design matrix containing numeric test treatments
#'   and control labels such as \code{C1}, \code{C2}, etc.
#'
#' @return A data frame containing:
#' \describe{
#'   \item{Number of Test Treatments}{Number of numeric test labels.}
#'   \item{Number of Controls}{Number of controls labelled C1, C2, etc.}
#'   \item{Average Variance (Test vs Test)}{
#'     Average variance of all test-treatment contrasts.
#'   }
#'   \item{Average Variance (Test vs Control)}{
#'     Average variance of all test-versus-control contrasts.
#'   }
#'   \item{Canonical Efficiency Factor}{
#'     Harmonic mean of the non-zero canonical efficiency factors.
#'   }
#' }
#'
#' @details
#' Blank or missing cells in the design matrix are ignored. The design must
#' contain at least two numeric test treatments and at least one control
#' treatment whose label starts with \code{C}.
#'
#' @importFrom MASS ginv
#'
#' @examples
#' design <- matrix(c(
#'   1,  6, 11, "C1",
#'   2,  5, 12, "C1",
#'   3,  8,  9, "C1",
#'   4,  7, 10, "C1",
#'   1,  7, 12, "C1",
#'   2,  8, 11, "C1",
#'   1,  8, 10, "C1",
#'   2,  7,  9, "C1",
#'   3,  6, 12, "C1",
#'   4,  5, 11, "C1",
#'   3,  5, 10, "C1",
#'   4,  6,  9, "C1"
#' ), ncol = 4, byrow = TRUE)
#'
#' TCpRepEfficiency(design)
#'
#' @export
TCpRepEfficiency <- function(design) {
  
  if (!requireNamespace("MASS", quietly = TRUE)) {
    stop("Package 'MASS' is required.", call. = FALSE)
  }
  
  a <- as.matrix(design)
  a <- apply(a, c(1, 2), as.character)
  
  is_present <- !is.na(a) & trimws(a) != ""
  
  if (!any(is_present)) {
    stop("The design matrix contains no treatments.", call. = FALSE)
  }
  
  values <- a[is_present]
  
  test_labels <- sort(
    unique(values[grepl("^[0-9]+$", values)])
  )
  
  control_labels <- sort(
    unique(values[grepl("^C", values, ignore.case = TRUE)])
  )
  
  if (length(test_labels) < 2L) {
    stop(
      "The design must contain at least two numeric test treatments.",
      call. = FALSE
    )
  }
  
  if (!length(control_labels)) {
    stop(
      "The design must contain at least one control labelled C1, C2, etc.",
      call. = FALSE
    )
  }
  
  labels <- c(test_labels, control_labels)
  
  observations <- which(is_present, arr.ind = TRUE)
  
  n <- nrow(observations)
  b <- nrow(a)
  v <- length(labels)
  vt <- length(test_labels)
  vc <- length(control_labels)
  
  trt <- matrix(0, nrow = n, ncol = v)
  block <- matrix(0, nrow = n, ncol = b)
  
  for (i in seq_len(n)) {
    
    treatment <- a[
      observations[i, "row"],
      observations[i, "col"]
    ]
    
    trt[i, match(treatment, labels)] <- 1
    block[i, observations[i, "row"]] <- 1
  }
  
  intercept <- matrix(1, nrow = n, ncol = 1)
  
  X1 <- trt
  X2 <- cbind(intercept, block)
  
  C <- t(X1) %*% X1 -
    t(X1) %*% X2 %*%
    MASS::ginv(t(X2) %*% X2) %*%
    t(X2) %*% X1
  
  Cinv <- MASS::ginv(C)
  
  ############################################################
  ## Test versus Test
  ############################################################
  
  nTT <- choose(vt, 2)
  CM_TT <- matrix(0, nrow = nTT, ncol = v)
  
  row <- 1L
  
  for (i in 1:(vt - 1)) {
    for (j in (i + 1):vt) {
      CM_TT[row, i] <- 1
      CM_TT[row, j] <- -1
      row <- row + 1L
    }
  }
  
  AV_TT <- mean(
    diag(CM_TT %*% Cinv %*% t(CM_TT))
  )
  
  ############################################################
  ## Test versus Control
  ############################################################
  
  nTC <- vt * vc
  CM_TC <- matrix(0, nrow = nTC, ncol = v)
  
  row <- 1L
  
  for (i in seq_len(vt)) {
    for (j in (vt + 1):v) {
      CM_TC[row, i] <- 1
      CM_TC[row, j] <- -1
      row <- row + 1L
    }
  }
  
  AV_TC <- mean(
    diag(CM_TC %*% Cinv %*% t(CM_TC))
  )
  
  ############################################################
  ## Canonical Efficiency Factor
  ############################################################
  
  eigenvalues <- Re(eigen(C)$values)
  eigenvalues <- eigenvalues[eigenvalues > 1e-7]
  
  test_replications <- colSums(trt)[seq_len(vt)]
  
  average_test_replication <- mean(
    test_replications
  )
  
  cefs <- eigenvalues / average_test_replication
  
  CEF <- length(cefs) / sum(1 / cefs)
  
  ############################################################
  ## Output
  ############################################################
  
  data.frame(
    
    Measure = c(
      "Number of Test Treatments",
      "Number of Controls",
      "Average Variance (Test vs Test)",
      "Average Variance (Test vs Control)",
      "Canonical Efficiency Factor"
    ),
    
    Value = c(
      vt,
      vc,
      round(AV_TT, 4),
      round(AV_TC, 4),
      round(CEF, 4)
    ),
    
    stringsAsFactors = FALSE
  )
  
}
