#' The BFM function is to generate Beta Factor Models data.
#'
#' The function supports various distribution types for generating the data.
#'
#' @name BFM
#' @usage BFM(n, p, m, mub, phib, distribution_type)
#' @param n Sample size.
#' @param p Sample dimensionality.
#' @param m Number of factors.
#' @param mub Mean parameter for Beta distribution (numeric vector or scalar, 0 < mub < 1).
#' @param phib Precision parameter for Beta distribution (positive numeric vector or scalar).
#' @param distribution_type Type of Beta distribution.
#' @importFrom stats runif rbeta rt cor rnorm
#' @importFrom psych KMO cortest.bartlett
#' @importFrom MASS mvrnorm
#'
#' @return A list containing:
#' \item{data}{Generated BFM data matrix (n rows, p columns).}
#' \item{A}{A matrix representing the factor loadings.}
#' \item{D}{Diagonal matrix of unique variances.}
#' \item{kmo}{Kaiser-Meyer-Olkin sampling adequacy measure.}
#' \item{bartlett}{Bartlett's test of sphericity.}
#'
#' @examples
#' n <- 1000
#' p <- 10
#' m <- 5
#' mub <- runif(p, 0.2, 0.8)
#' phib <- runif(p, 5, 30)
#' dist_type <- "Elliptical Distribution"
#' X <- BFM(n, p, m, mub, phib, dist_type)
#'
#' @export
BFM <- function(n, p, m, mub, phib, distribution_type) {
  if (any(mub <= 0 | mub >= 1)) {
    stop("mub must be in (0, 1)")
  }
  if (any(phib <= 0)) {
    stop("phib must be positive")
  }

  mu <- t(matrix(rep(runif(p, 0, n), n), nrow = p, ncol = n))
  mu0 <- as.matrix(runif(m, 0))
  sigma0 <- diag(runif(m, 1))
  shape1 <- mub * phib
  shape2 <- (1 - mub) * phib
  
  F <- matrix(MASS::mvrnorm(n, mu = mu0, Sigma = sigma0), nrow = n)
  A <- matrix(runif(p * m, -1, 1), nrow = p)
  D <- diag(runif(p, 0, 1))
  
  if (distribution_type == "Elliptical-Normal Distribution") {
    eps_raw <- rbeta(n * p, shape1 = shape1, shape2 = shape2)
    epsilon <- matrix(eps_raw - mean(eps_raw), nrow = n)
  } else if (distribution_type == "Elliptical-t Distribution") {
    eps_beta <- rbeta(n * p, shape1 = shape1, shape2 = shape2)
    eps_t <- rt(n * p, df = 5)
    eps_raw <- eps_beta + 0.1 * eps_t
    epsilon <- matrix(eps_raw - mean(eps_raw), nrow = n)
  } else if (distribution_type == "Elliptical Distribution") {
    eps_raw <- rbeta(n * p, shape1 = shape1, shape2 = shape2)
    epsilon <- matrix(eps_raw - mean(eps_raw), nrow = n)
  } else {
    stop("Unsupported distribution_type! Choose from: 'Elliptical-Normal Distribution', 'Elliptical-t Distribution', 'Elliptical Distribution'")
  }
  
  data <- mu + F %*% t(A) + epsilon

  kmo <- psych::KMO(data)
  bartlett <- psych::cortest.bartlett(cor(data), n = n)
  
  return(list(
    data = data,
    A = A,
    D = D,
    kmo = kmo,
    bartlett = bartlett
  ))
}