## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
set.seed(20260823)

## ----setup--------------------------------------------------------------------
library(EDI)
library(R6)

## ----shells-------------------------------------------------------------------
InferenceCustomAsymp <- getFromNamespace("InferenceCustomAsymp", "EDI")
InferenceCustomRand <- getFromNamespace("InferenceCustomRand", "EDI")
InferenceCustomBoot <- getFromNamespace("InferenceCustomBoot", "EDI")
DesignFixedCustom <- getFromNamespace("DesignFixedCustom", "EDI")
DesignCustomSequential <- getFromNamespace("DesignCustomSequential", "EDI")

## ----median-diff--------------------------------------------------------------
InferenceMedianDiff <- R6Class(
  "InferenceMedianDiff",
  inherit = InferenceCustomAsymp,
  # Required when subclassing EDI's factory-built classes: lazily loaded
  # components install their real methods onto the object after construction,
  # which needs an unlocked environment.
  lock_objects = FALSE,
  public = list(
    fit = function(estimate_only = FALSE) {
      dat <- self$get_analysis_data()
      y_t <- dat$y[dat$w == 1]
      y_c <- dat$y[dat$w == 0]

      est <- stats::median(y_t) - stats::median(y_c)
      if (estimate_only) {
        return(list(estimate = est))
      }

      list(
        estimate = est,
        se = sqrt(stats::var(y_t) / length(y_t) + stats::var(y_c) / length(y_c)),
        df = length(y_t) + length(y_c) - 2,
        model = NULL
      )
    }
  )
)

des <- DesignFixedBernoulli$new(n = 20, response_type = "continuous", verbose = FALSE)
des$add_all_subjects_to_experiment(data.frame(x = seq_len(20)))
des$overwrite_all_subject_assignments(rep(c(0, 1), each = 10))
des$add_all_subject_responses(rnorm(20))

inf <- InferenceMedianDiff$new(des)
inf$compute_estimate()
inf$compute_asymp_two_sided_pval()
inf$compute_asymp_confidence_interval()
inf$compute_bootstrap_two_sided_pval(B = 101, show_progress = FALSE)
inf$capabilities()
inf$supports("wald")

## ----rand-boot----------------------------------------------------------------
InferenceMedianDiffRand <- R6Class(
  "InferenceMedianDiffRand",
  inherit = InferenceCustomRand,
  lock_objects = FALSE,
  public = list(
    fit = function(estimate_only = FALSE) {
      dat <- self$get_analysis_data()
      list(estimate = stats::median(dat$y[dat$w == 1]) - stats::median(dat$y[dat$w == 0]))
    }
  )
)
inf_rand <- InferenceMedianDiffRand$new(des)
inf_rand$compute_estimate()
inf_rand$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
inf_rand$capabilities()

InferenceMedianDiffBoot <- R6Class(
  "InferenceMedianDiffBoot",
  inherit = InferenceCustomBoot,
  lock_objects = FALSE,
  public = list(
    fit = function(estimate_only = FALSE) {
      dat <- self$get_analysis_data()
      list(estimate = stats::median(dat$y[dat$w == 1]) - stats::median(dat$y[dat$w == 0]))
    }
  )
)
inf_boot <- InferenceMedianDiffBoot$new(des)
inf_boot$compute_bootstrap_confidence_interval(B = 101, show_progress = FALSE)

## ----rules--------------------------------------------------------------------
# Not registered ...
"InferenceMedianDiff" %in% des$applicable_inference_class_names()
# ... but capabilities resolve through the registered shell it inherits from.
identical(inf$capabilities(), InferenceCustomAsymp$new(des)$capabilities())

## ----custom-design------------------------------------------------------------
DesignFixedAlternating <- R6Class(
  "DesignFixedAlternating",
  inherit = DesignFixedCustom,
  lock_objects = FALSE,
  public = list(
    draw_assignments = function(r = 1) {
      n <- self$get_n()
      matrix(rep_len(c(0, 1), n), nrow = n, ncol = r)
    }
  )
)
des_alt <- DesignFixedAlternating$new(n = 10, response_type = "continuous", verbose = FALSE)
des_alt$add_all_subjects_to_experiment(data.frame(x = 1:10))
des_alt$assign_w_to_all_subjects()
des_alt$get_w()
des_alt$capabilities()
des_alt$add_all_subject_responses(rnorm(10))
head(des_alt$applicable_inference_class_names())

DesignSeqEveryOther <- R6Class(
  "DesignSeqEveryOther",
  inherit = DesignCustomSequential,
  lock_objects = FALSE,
  public = list(
    assignment_rule = function() as.numeric(self$get_t() %% 2 == 0)
  )
)
des_seq <- DesignSeqEveryOther$new(n = 6, response_type = "continuous", verbose = FALSE)
for (i in 1:6) des_seq$add_one_subject_to_experiment_and_assign(data.frame(x = i))
des_seq$get_w()

