#' Check the Format of a Data Frame for Multicentre Competing Risks with Frailty
#'
#' Validates whether the submitted data frame is correctly structured for the analysis
#' of multicentre competing risks with frailty.
#'
#' @param df A data frame to be checked.
#'
#' @return `TRUE` if `df` has the expected structure.
#' Otherwise, the function stops with an error describing the formatting issue.
#'
#' @examples
#' \donttest{
#' n_cov = 1
#' n_cluster = 5
#' n_per_cluster = 100
#' n = n_cluster * n_per_cluster
#' a1 = 0
#' b1 = 1
#' G <- rep(1:n_cluster, each = n_per_cluster)
#' Z <- matrix(runif(n * n_cov, a1, b1), ncol = n_cov)
#' df = simulate_data(
#'   G,
#'   Z,
#'   prop = 0.6,
#'   beta = c(0),
#'   theta = 0.01,
#'   cens = TRUE,
#'   pcens = 0.25,
#'   tau = 0
#' )
#' check_data_format(df)
#' }
#'
#' @export


check_data_format <- function(df)
{
  if (!is.data.frame(df)) {
    stop("The argument must be a data frame.")
  }

  n_cols <- ncol(df)
  if (n_cols < 3) {
    stop(
      "The data frame must contain at least 3 columns:\n - 'times': the observed time,\n - 'status': 0 for right-censoring, i in [1,n] otherwise, where i is the cause of failure,\n - 'clusters': cluster/group indicator."
    )
  }
  n_row <- nrow(df)
  if (n_row == 0) {
    stop(
      "The dataframe must contain at least one row, otherwise, these is nothing to analyse."
    )
  }

  col_names <- colnames(df)
  expected_names <- c("times", "status", "clusters")
  for (i in 1:3) {
    if (col_names[i] != expected_names[i]) {
      stop(paste0("Column ", i, " must be named '", expected_names[i], "'."))
    }
  }

  if (!(is.numeric(df$times) && all(is.finite(df$times)) && all(df$times >= 0)))
    stop("Some values in 'times' are missing (NA) or non-positive numeric.")
  if (!(is.numeric(df$status) && all(is.finite(df$status)) && all(df$status == floor(df$status)) && all(df$status >= 0)))
    stop("Some values in 'status' are missing (NA) or non-positive integer.")
  if (!(is.numeric(df$clusters) && all(is.finite(df$clusters)) && all(df$clusters == floor(df$clusters)) && all(df$clusters >= 0)))
    stop("Some values in 'clusters' are missing (NA) or non-positive integer.")
  if (n_cols > 3) {
    covariate_cols <- df[, 4:n_cols, drop = FALSE]
    if (!all(sapply(covariate_cols, is.numeric)) || any(is.na(covariate_cols))) {
      stop("All covariates (columns 4 to end) must be numeric and contain no missing values (NA).")
    }
  }
  return(TRUE)
}
