#' The random number generator for doubly censored response variable with the latent variable following normal assumption.
#'
#' @param n Sample size.
#' @param L0 The lower censoring limit.
#' @param R0 The upper censoring limit.
#' @param theta The location parameter of the latent variable.
#' @param sigma The standard deviation of the latent variable.
#'
#' @returns The simulated doubly censored response variable.
#' @noRd
#'
#' @examples
#'
#' set.seed(100)
#' y <- doubly_censored_rng(n = 1000, L0 = 0, R0 = 1, theta = 0.5, sigma = 0.2)
#' summary(y)
#' hist(y,breaks = 50)
#'
doubly_censored_rng <- function(n,L0,R0,theta,sigma) {
  Z <- rnorm(n = n, mean = 0.0, sd = sigma) + theta
  indexL <- (Z <= L0) + 0.0
  indexR <- (Z >= R0) + 0.0
  indexM <- (L0 < Z) * (Z < R0) + 0.0
  Y <- L0 * indexL + Z * indexM + R0 * indexR
  return(Y)
}

outcome_model_fixed_effects <- function(yij_previous,aij,X1j) {
  treatment_effects <- (-0.1)*(aij == "TREATMENT A") + (0.1)*(aij == "TREATMENT B")
  covariate_effects <- 0.2 * X1j
  previous_effects <- 0.1 * yij_previous + 0.05 * yij_previous^2
  treatment_interaction <- (aij == "TREATMENT A") * (-0.05*yij_previous) + (aij == "TREATMENT B") * (0.03 * yij_previous)

  output <- treatment_effects + treatment_interaction + covariate_effects + previous_effects
  return(output)
}

true_inner_expectation <- function(y_previous,treatment,confounder,sigma,
                                   random_effects) {
  fixed_effects <- outcome_model_fixed_effects(yij_previous = y_previous,
                                               aij = treatment,
                                               X1j = confounder)
  theta <- fixed_effects + random_effects
  output <- doubly_censored_expectation(theta = theta,
                                        sigma = sigma)
  return(output)
}

true_causal_estimand <- function(y_previous, treatment, confounder, sigma, sigma_u) {

  integrand <- function(u) {
    # Handle scalar input for non-vectorizable functions
    sapply(u, function(ui) {
      inner_result <- true_inner_expectation(y_previous = y_previous,
                                             treatment = treatment,
                                             confounder = confounder,
                                             sigma = sigma,
                                             random_effects = ui)
      output <- mean(inner_result) * dnorm(ui, mean = 0, sd = sigma_u)
      return(output)
    })
  }

  result <- integrate(integrand,
                      lower = -Inf,
                      upper = Inf,
                      rel.tol = .Machine$double.eps^0.5,
                      abs.tol = .Machine$double.eps^0.5)

  return(result$value)
}

#' @title Data Generation Program
#'
#' @description
#' Generates simulated data for evaluating the causal inference models.
#'
#' @param random_seed a single random seed for reproducibility. The datatype is \code{integer}.
#' @param N the total number of subjects to simulate. The datatype is \code{integer}.
#' @param sigma the global error standard deviation. The datatype is \code{double}.
#' @param sigma_u the standard deviation of the subject-level random effects. The datatype is \code{double}.
#'
#' @returns \code{data_generation} returns a simulated \code{data.frame}.
#' @export
#'
#' @example /inst/examples/data_generation.r
data_generation <- function(random_seed,N,sigma,sigma_u) {
  set.seed(random_seed)

  df_list <- vector("list", N)

  for (i in 1:N) {
    ni <- rpois(n = 1, lambda = 1) + 2

    # initilize output
    yi_current <- numeric(ni)
    yi_previous <- numeric(ni)
    ai <- character(ni)
    propensityi <- numeric(ni)

    # initial periodontal status for subjecti
    yi0 <- doubly_censored_rng(n = 1,
                               L0 = 0.0,
                               R0 = 1.0,
                               theta = 0.5,
                               sigma = sigma)
    yi_previous[1] <- yi0

    # covariates
    X1 <- rnorm(n = ni,mean = 0, sd = 0.1)

    # random effects
    Ui <- rnorm(n = 1, mean = 0, sd = sigma_u)

    for (j in 1:ni) {
      prob_eta <- yi_previous[j] + 0.5*X1[j]
      prob_treatment <- 1/(1+exp(-prob_eta))
      # treatment decision for patient i at initial visit
      aij <- sample(x = c("TREATMENT A",
                          "TREATMENT B"),
                    size = 1,
                    prob = c(prob_treatment,1-prob_treatment))
      ai[j] <- aij
      propensityi[j] <- prob_treatment
      fixed_effects <- outcome_model_fixed_effects(yij_previous = yi_previous[j],
                                                   aij = ai[j],
                                                   X1j = X1[j])

      yi_current[j] <- doubly_censored_rng(n = 1,
                                           L0 = 0.0,
                                           R0 = 1.0,
                                           theta = fixed_effects + Ui,
                                           sigma = sigma)

      if (j < ni) {
        yi_previous[j+1] <- yi_current[j]
      }
    }

    dfi <- data.frame(subjectID = paste0("subject",i),
                      current_value = yi_current,
                      previous_value = yi_previous,
                      treatment = ai,
                      confounder = X1,
                      propensity = propensityi)

    df_list[[i]] <- dfi

  }

  df1 <- do.call("rbind",df_list)

  df1$treatment <- factor(df1$treatment,
                          levels = c("TREATMENT A",
                                     "TREATMENT B"))

  df1$subjectID <- factor(df1$subjectID,
                          levels = unique(df1$subjectID))

  return(df1)
}
