#' Series 6 PRBMS Design
#'
#' @description
#' This function generates a new series of PRBMS designs using initial sequence q4: [x^0, x^1, x^2, ..., x^(v - 2)] with parameters (v, s = 2, m = (v - 1)/2, p = v),
#' and calculates the canonical efficiency factors.
#'
#' @param v Total number of products
#' @param verbose Logical; if TRUE, prints design layout and efficiency factors
#'
#' @return A list containing design and efficiency measures
#'
#' @examples
#' SERIES6(7, verbose = FALSE)
#'
#' @export
SERIES6 <- function(v, verbose = TRUE) {

  if (v %% 2 == 0) stop("v must be odd prime")

  # ---------- PRIME CHECK ----------
  is_prime <- function(n) {
    if (n <= 1) return(FALSE)
    if (n <= 3) return(TRUE)
    if (n %% 2 == 0) return(FALSE)

    for (i in 3:floor(sqrt(n))) {
      if (n %% i == 0) return(FALSE)
    }

    TRUE
  }

  if (!is_prime(v)) stop("v must be prime")

  # ---------- Primitive ----------
  is_primitive <- function(g, p) {
    length(unique((g^(0:(p - 2))) %% p)) == (p - 1)
  }

  get_primitive <- function(p) {
    for (g in 2:(p - 1)) {
      if (is_primitive(g, p)) return(g)
    }

    stop("No primitive element")
  }

  g <- get_primitive(v)

  # ============================================================
  # 1. BIBD CONSTRUCTION
  # ============================================================

  k <- (v - 1) / 2

  even_powers <- seq(0, 2 * (k - 1), by = 2)
  odd_powers <- seq(1, 2 * k - 1, by = 2)

  D_even <- (g^even_powers) %% v
  D_odd <- (g^odd_powers) %% v

  gen_blocks <- function(D) {

    mat <- matrix(0, v, length(D))

    for (i in 0:(v - 1)) {
      mat[i + 1, ] <- (D + i) %% v
    }

    mat[mat == 0] <- v

    mat
  }

  B1 <- gen_blocks(D_even)
  B2 <- gen_blocks(D_odd)

  a <- rbind(t(B1), t(B2))

  # ============================================================
  # BASIC INFO
  # ============================================================

  n_panel <- v
  n_session <- 2
  periods_per_session <- rep((v - 1) / 2, 2)

  n_rows <- nrow(a)
  n_obs <- n_rows * n_panel

  # ============================================================
  # c MATRIX
  # ============================================================

  b <- matrix(0, nrow = 2, ncol = v)
  cmat <- matrix(0, n_rows, v)

  k <- 2
  kk <- 1

  for (i in 1:n_session) {
    for (j in 1:(periods_per_session[i] - 1)) {
      cmat[k, ] <- a[kk, ]
      k <- k + 1
      kk <- kk + 1
    }

    k <- k + 1
    kk <- kk + 1
  }

  kk <- 1
  for (i in 1:nrow(cmat)) {
    if (all(cmat[i, ] == 0)) {
      cmat[i, ] <- b[kk, ]
      kk <- kk + 1
    }
  }

  # ============================================================
  # DIRECT & RESIDUAL
  # ============================================================

  trt <- matrix(0, n_obs, v)
  residual <- matrix(0, n_obs, v)

  k <- 1

  for (i in 1:n_rows) {
    for (j in 1:n_panel) {

      trt[k, a[i, j]] <- 1

      if (cmat[i, j] > 0) {
        residual[k, cmat[i, j]] <- 1
      }

      k <- k + 1
    }
  }

  residual <- residual[, colSums(residual) > 0]

  # ============================================================
  # PERIOD
  # ============================================================

  period_mat <- matrix(0, n_obs, n_rows)

  r <- 1
  col <- 1

  for (s in 1:n_session) {
    for (p in 1:periods_per_session[s]) {
      for (j in 1:n_panel) {

        period_mat[r, col] <- 1
        r <- r + 1
      }

      col <- col + 1
    }
  }

  # ============================================================
  # PANEL + SESSION
  # ============================================================

  panel <- matrix(0, n_obs, v)
  session_mat <- matrix(0, n_obs, n_session)

  k <- 1

  for (s in 1:n_session) {
    for (p in 1:periods_per_session[s]) {
      for (j in 1:n_panel) {

        panel[k, j] <- 1
        session_mat[k, s] <- 1

        k <- k + 1
      }
    }
  }

  intercept <- matrix(1, n_obs, 1)

  # ============================================================
  # C-MATRIX
  # ============================================================

  X1 <- cbind(trt, residual)
  X2 <- cbind(intercept, period_mat, panel, session_mat)

  Cjoint <- t(X1) %*% X1 -
    t(X1) %*% X2 %*%
    MASS::ginv(t(X2) %*% X2) %*%
    t(X2) %*% X1

  t_cols <- ncol(trt)
  r_cols <- ncol(residual)

  C11 <- Cjoint[1:t_cols, 1:t_cols]

  C22 <- Cjoint[
    (t_cols + 1):(t_cols + r_cols),
    (t_cols + 1):(t_cols + r_cols)
  ]

  C12 <- Cjoint[
    1:t_cols,
    (t_cols + 1):(t_cols + r_cols)
  ]

  C_direct <- C11 -
    C12 %*% MASS::ginv(C22) %*% t(C12)

  C_carry <- C22 -
    t(C12) %*% MASS::ginv(C11) %*% C12

  # ============================================================
  # PRINT DESIGN
  # ============================================================

  if (verbose) {

    cat("\nPRBMS Design:\n\n")

    to_roman <- function(num) {

      roman_map <- c(
        M = 1000, CM = 900, D = 500, CD = 400,
        C = 100, XC = 90, L = 50, XL = 40,
        X = 10, IX = 9, V = 5, IV = 4, I = 1
      )

      result <- ""

      for (sym in names(roman_map)) {
        while (num >= roman_map[sym]) {
          result <- paste0(result, sym)
          num <- num - roman_map[sym]
        }
      }

      result
    }

    roman_periods <- sapply(1:100, to_roman)

    w_session <- 8
    w_period <- 8
    w_panel <- 4

    panel_width_total <- n_panel * w_panel
    total_left_width <- w_session + w_period

    left_padding <- total_left_width +
      floor((panel_width_total - nchar("Panelist")) / 2)

    cat(sprintf("%*s%s\n", left_padding, "", "Panelist"))

    cat(sprintf("%-*s%-*s", w_session, "Session", w_period, "Period"))

    for (j in 1:n_panel) {
      cat(sprintf("%*s", w_panel, paste0("P", j)))
    }

    cat("\n\n")

    row_counter <- 1

    for (s in 1:n_session) {

      for (p in 1:periods_per_session[s]) {

        if (p == 1) {
          cat(sprintf("%-*s", w_session, paste0("S", s)))
        } else {
          cat(sprintf("%-*s", w_session, ""))
        }

        cat(sprintf("%-*s", w_period, roman_periods[row_counter]))

        for (j in 1:n_panel) {
          cat(sprintf("%*d", w_panel, a[row_counter, j]))
        }

        cat("\n")
        row_counter <- row_counter + 1
      }

      cat("\n")
    }
  }

  # ============================================================
  # EFFICIENCY FACTORS
  # ============================================================

  eig_d <- eigen(C_direct)$values
  eig_d <- eig_d[eig_d > 1e-7]

  rep_d <- t(trt) %*% trt
  eff_d <- length(eig_d) / sum(1 / (eig_d / rep_d[1, 1]))

  eig_r <- eigen(C_carry)$values
  eig_r <- eig_r[eig_r > 1e-7]

  rep_r <- t(residual) %*% residual
  eff_r <- length(eig_r) / sum(1 / (eig_r / rep_r[1, 1]))

  if (verbose) {
    cat("\nEfficiency Factors:\n\n")
    cat(sprintf("Direct effect: %.3f\n", eff_d))
    cat(sprintf("Carryover effect: %.3f\n", eff_r))
  }

  invisible(list(
    design = a,
    C_direct = C_direct,
    C_carry = C_carry,
    efficiency = c(
      Direct = eff_d,
      Carryover = eff_r
    )
  ))
}
