#' Convert an odds ratio value and its standard error into several effect size measures
#'
#' @param or odds ratio value
#' @param logor log odds ratio value
#' @param logor_se the standard error of the log odds ratio
#' @param n_cases number of cases/events across exposed/non-exposed groups
#' @param n_controls number of controls/no-event across exposed/non-exposed groups
#' @param n_exp number of participants in the exposed group
#' @param n_nexp number of participants in the non-exposed group
#' @param n_sample total number of participants in the sample
#' @param baseline_risk proportion of cases in the non-exposed group
#' @param small_margin_prop smallest margin proportion of cases/events in the underlying 2x2 table
#' @param reverse_or a logical value indicating whether the direction of the generated effect sizes should be flipped.
#' @param or_to_rr formula used to convert the \code{or} value into a risk ratio (see details).
#' @param or_to_cor formula used to convert the \code{or} value into a correlation coefficient (see details).
#'
#' @details
#' This function converts the log odds ratio into a Risk ratio (RR), Cohen's d (D), Hedges' g (G)
#' and correlation coefficients (R/Z).
#'
#' **To estimate the Cohen's d value and its standard error**
#' The following formulas are used (Cooper et al., 2019):
#' \deqn{d = \log(or) * \frac{\sqrt{3}}{\pi}}
#' \deqn{d\_se = \sqrt{\frac{logor\_se^2 * 3}{\pi^2}}}
#'
#' **To estimate the risk ratio and its standard error, various formulas can be used.**
#'
#' **A.** First, the approach described in Grant (2014) can be used.
#' However, in the paper, only the formula to convert an OR value to a RR value
#' is described.
#' To derive the variance, we used this formula to convert the bounds of the 95% CI, which
#' were then used to obtain the variance.
#'
#' This argument requires (or + baseline_risk + or_ci_lo + or_ci_up) to generate a RR.
#' The following formulas are used (br = baseline_risk):
#' \deqn{rr = \frac{or}{1 - br + br*or}}
#' \deqn{rr\_ci\_lo = \frac{or\_ci\_lo}{1 - br + br*or\_ci\_lo}}
#' \deqn{rr\_ci\_up = \frac{or\_ci\_up}{1 - br + br*or\_ci\_up}}
#' \deqn{logrr\_se = \frac{log(rr\_ci\_up) - log(rr\_ci\_lo)}{2 * qnorm(.975)}}
#'
#'
#' **B.** Second, the formulas implemented in the metaumbrella package can be used
#' (\code{or_to_rr = "metaumbrella_cases"} or \code{or_to_rr = "metaumbrella_exp"}).
#' This argument requires (or + logor_se + n_cases + n_controls) or (or + logor_se + n_exp + n_nexp)
#' to generate a RR.
#' More precisely, when the OR value and its standard error, plus either
#' (i) the number of cases and controls or
#' (ii) the number of participants in the exposed and non-exposed groups,
#' are available, we previously developed functions that simulate all combinations of the possible
#' number of cases and controls
#' in the exposed and non-exposed groups compatible with the actual value of the OR.
#' Then, the functions select the contingency table whose standard error coincides best with
#' the standard error reported.
#' The RR value and its standard are obtained from this estimated contingency table.
#'
#' **C.** Third, it is possible to transpose the RR to a OR (\code{or_to_rr = "transpose"}).
#' This argument requires (or + logor_se) to generate a OR.
#' It is known that OR and RR are similar when the baseline risk is small.
#' Therefore, users can request to simply transpose the OR value & standard error into a RR value & standard error.
#' \deqn{rr = or}
#' \deqn{logrr\_se = logor\_se}
#'
#' **D.** Fourth, it is possible to recreate the 2x2 table using the dipietrantonj's formulas (\code{or_to_rr = "dipietrantonj"}).
#' This argument requires (or + logor_ci_lo + logor_ci_lo) to generate a RR. Information on this approach can be retrieved in
#' Di Pietrantonj (2006).
#'
#' **To estimate the NNT, the formulas used are :**
#' \deqn{treatment\_risk = \frac{or \times br}{1 - br + or \times br}}
#' \deqn{rd = br - treatment\_risk}
#' \deqn{nnt = \frac{1}{rd} = \frac{1 - br \times (1 - or)}{br \times (1 - br)}}
#'
#' **To estimate a correlation coefficient, various formulas can be used.**
#'
#' **A.** First, the approach described in Pearson (1900) can be used (\code{or_to_cor = "pearson"}).
#' This argument requires (or + logor_se) to generate a R/Z.
#' It converts the OR value and its standard error to a tetrachoric correlation.
#' Note that the formula assumes that each cell of the 2x2 used to estimate the OR has been added 1/2 before estimating the OR value and its standard error.
#' If it is not the case, formulas can produce slightly less accurate results.
#'
#' \deqn{c = \frac{1}{2}}
#' \deqn{r = \cos{\frac{\pi}{1+or^c}}}
#' \deqn{r\_se = logor\_se * (\pi * c * or^c) * \frac{\sin(\pi / (1+or^c))}{(1+or^c)^2}}
#' \deqn{or\_ci\_lo = exp(log(or) - qnorm(.975)*logor\_se)}
#' \deqn{or\_ci\_up = exp(log(or) + qnorm(.975)*logor\_se)}
#' \deqn{r\_ci\_lo = cos(\frac{\pi}{1 + or\_ci\_lo^c})}
#' \deqn{r\_ci\_up = cos(\frac{\pi}{1 + or\_ci\_up^c})}
#' \deqn{z = atanh(r)}
#' \deqn{z\_se = \sqrt{\frac{r\_se^2}{(1 - r^2)^2}}}
#' \deqn{z\_ci\_lo = atanh(r\_lo)}
#' \deqn{z\_ci\_up = atanh(r\_up)}
#'
#' **B.** Second, the approach described in Digby (1983) can be used (\code{or_to_cor = "digby"}).
#' This argument requires (or + logor_se) to generate a R/Z.
#' It converts the OR value and its standard error to a tetrachoric correlation.
#' Note that the formula assumes that each cell of the 2x2 used to estimate the OR has been added 1/2 before estimating the OR value and its standard error.
#' If it is not the case, formulas can produce slightly less accurate results.
#'
#' \deqn{c = \frac{3}{4}}
#' \deqn{r = \frac{or^c - 1}{or^c + 1}}
#' \deqn{r\_se = \sqrt{\frac{c^2}{4} * (1 - r^2)^2 * logor\_se^2}}
#' \deqn{z = atanh(r)}
#' \deqn{z\_se = \sqrt{\frac{r\_se^2}{(1 - r^2)^2}}}
#' \deqn{z\_ci\_lo = z - qnorm(.975)*\sqrt{\frac{c^2}{4} * logor\_se}}
#' \deqn{z\_ci\_up = z + qnorm(.975)*\sqrt{\frac{c^2}{4} * logor\_se}}
#' \deqn{r\_ci\_lo = tanh(z\_lo)}
#' \deqn{r\_ci\_up = tanh(z\_up)}
#'
#' **C.** Third, the approach described in Bonett (2005) can be used (\code{or_to_cor = "bonett"}).
#' This argument requires (or + logor_se + n_cases + n_exp + small_margin_prop) to generate a R/Z.
#' Note that the formula assumes that each cell of the 2x2 used to estimate the OR has been added 1/2 before estimating the OR value and its standard error.
#' If it is not the case, formulas can produce slightly less accurate results.
#'
#' \deqn{c = \frac{\frac{1 - |n\_exp - n\_cases|}{5} - (0.5 - small\_margin\_prop)^2}{2}}
#' \deqn{r = \cos{\frac{\pi}{1+or^c}}}
#' \deqn{r\_se = logor\_se * (\pi * c * or^c) * \frac{\sin(\frac{\pi}{1+or^c})}{(1+or^c)^2}}
#' \deqn{or\_ci\_lo = exp(log(or) - qnorm(.975)*logor\_se)}
#' \deqn{or\_ci\_up = exp(log(or) + qnorm(.975)*logor\_se)}
#' \deqn{r\_ci\_lo = cos(\frac{\pi}{1 + or\_ci\_lo^c})}
#' \deqn{r\_ci\_up = cos(\frac{\pi}{1 + or\_ci\_up^c})}
#' \deqn{z = atanh(r)}
#' \deqn{z\_se = \sqrt{\frac{r\_se^2}{(1 - r^2)^2}} }
#' \deqn{z\_ci\_lo = atanh(r\_lo)}
#' \deqn{z\_ci\_up = atanh(r\_up)}
#'
#' **D.** Last, the approach described in Cooper et al. (2019) can be used (\code{or_to_cor = "lipsey_cooper"}).
#' This argument requires (or + logor_se + n_exp + n_nexp) to generate a R/Z.
#' As shown above, the function starts to estimate a SMD from the OR.
#' Then, as described in \code{\link{es_from_cohen_d}}, it converts this Cohen's d value into a correlation
#' coefficient using the \code{"lipsey_cooper"} formulas.
#'
#'
#' @export es_from_or_se
#'
#' @md
#'
#' @return
#' This function estimates and converts between several effect size measures.
#'
#' \tabular{ll}{
#'  \code{natural effect size measure} \tab OR\cr
#'  \tab \cr
#'  \code{converted effect size measure} \tab RR + NNT + RD\cr
#'  \code{} \tab D + G + R + Z\cr
#'  \tab \cr
#'  \code{required input data} \tab See 'Section 2. Odds Ratio'\cr
#'  \tab https://metaconvert.org/input.html\cr
#'  \tab \cr
#' }
#'
#' @references
#' Bonett, Douglas G. and Robert M. Price. (2005). Inferential Methods for the Tetrachoric Correlation Coefficient. Journal of Educational and Behavioral Statistics 30:213-25.
#'
#' Bonett, D. G., & Price, R. M. (2007). Statistical inference for generalized Yule coefficients in 2* 2 contingency tables. Sociological methods & research, 35(3), 429-446.
#'
#' Cooper, H., Hedges, L. V., & Valentine, J. C. (Eds.). (2019). The handbook of research synthesis and meta-analysis. Russell Sage Foundation.
#'
#' Di Pietrantonj C. (2006). Four-fold table cell frequencies imputation in meta analysis. Statistics in medicine, 25(13), 2299-2322. https://doi.org/10.1002/sim.2287
#'
#' Digby, Peter G. N. (1983). Approximating the Tetrachoric Correlation Coefficient. Biometrics 39:753-7.
#'
#' Gosling, C. J., Solanes, A., Fusar-Poli, P., & Radua, J. (2023). metaumbrella: the first comprehensive suite to perform data analysis in umbrella reviews with stratification of the evidence. BMJ mental health, 26(1), e300534. https://doi.org/10.1136/bmjment-2022-300534
#'
#' Grant R. L. (2014). Converting an odds ratio to a range of plausible relative risks for better communication of research findings. BMJ (Clinical research ed.), 348, f7450. https://doi.org/10.1136/bmj.f7450
#'
#' Pearson, K. (1900). Mathematical Contributions to the Theory of Evolution. VII: On the Correlation of Characters Not Quantitatively Measurable. Philosophical Transactions of the Royal Statistical Society of London, Series A 19:1-47
#'
#' Veroniki, A. A., Pavlides, M., Patsopoulos, N. A., & Salanti, G. (2013). Reconstructing 2x2 contingency tables from odds ratios using the Di Pietrantonj method: difficulties, constraints and impact in meta-analysis results. Research synthesis methods, 4(1), 78-94. https://doi.org/10.1002/jrsm.1061
#'
#' @examples
#' es_from_or_se(or = 2.12, logor_se = 0.242, n_exp = 120, n_nexp = 44)
es_from_or_se <- function(or, logor, logor_se, baseline_risk,
                          small_margin_prop,
                          n_exp, n_nexp, n_cases, n_controls, n_sample,
                          or_to_rr = "metaumbrella_cases",
                          or_to_cor = "pearson", reverse_or) {

  if (!all(or_to_cor %in% c("pearson", "digby", "bonett", "lipsey_cooper"))) {
    stop(paste0("'",
                unique(or_to_cor[!or_to_cor %in% c("pearson", "digby", "bonett", "lipsey_cooper")]),
                "' not in tolerated values for the 'or_to_cor' argument.
                Possible inputs are: 'pearson', 'digby', 'bonett', 'lipsey_cooper'"))

  } else if (!all(or_to_rr %in% c("metaumbrella_cases", "metaumbrella_exp", "transpose", "grant", "dipietrantonj"))) {
    stop(paste0("'",
                unique(or_to_rr[!or_to_rr %in% c("metaumbrella_cases", "metaumbrella_exp", "transpose", "grant", "dipietrantonj")]),
                "' not in tolerated values for the 'or_to_rr' argument.
                Possible inputs are: 'metaumbrella_cases', 'metaumbrella_exp', 'transpose', 'grant', 'dipietrantonj'"))
  }


  # or = dat$or; logor = dat$logor; logor_se = dat$logor_se;
  # baseline_risk = dat$baseline_risk;
  # small_margin_prop = dat$small_margin_prop;
  # n_exp = dat$n_exp; n_nexp = dat$n_nexp; n_cases = dat$n_cases; n_controls = dat$n_controls;
  # or_to_rr = "metaumbrella_cases";
  # or_to_cor = "cooper_delta";
  # reverse_or <- rep(FALSE, length(or))
  # or_to_rr = "dipietrantonj"
  if (missing(or)) {
    or <- rep(NA_real_, length(logor))
  }
  if (missing(logor)) {
    logor <- rep(NA_real_, length(or))
  }
  if (missing(baseline_risk)) {
    baseline_risk <- rep(NA_real_, length(or))
  }
  if (missing(small_margin_prop)) {
    small_margin_prop <- rep(NA_real_, length(or))
  }
  if (missing(n_exp)) {
    n_exp <- rep(NA_real_, length(or))
  }
  if (missing(n_nexp)) {
    n_nexp <- rep(NA_real_, length(or))
  }
  if (missing(n_cases)) {
    n_cases <- rep(NA_real_, length(or))
  }
  if (missing(n_controls)) {
    n_controls <- rep(NA_real_, length(or))
  }
  if (missing(reverse_or)) {
    reverse_or <- rep(FALSE, length(or))
  }
  if (missing(n_sample)) {
    n_sample <- rep(NA_real_, length(or))
  }
  reverse_or[is.na(reverse_or)] <- FALSE
  if (length(reverse_or) == 1) reverse_or = c(rep(reverse_or, length(or)))
  if (length(reverse_or) != length(or)) stop("The length of the 'reverse_or' argument is incorrectly specified.")

  or <- ifelse(is.na(or) & !is.na(logor), exp(logor), or)

  logOR <- suppressWarnings(log(or))

  d <- logOR * sqrt(3) / pi
  d_se <- sqrt(logor_se^2 * 3 / (pi^2))

  n_sample <- ifelse(is.na(n_sample),
    ifelse(!is.na(n_cases) & !is.na(n_controls),
           n_cases + n_controls,
           n_exp + n_nexp),
    n_sample
  )

  es <- .es_from_d(
    d = d, d_se = d_se, n_exp = n_exp, n_nexp = n_nexp,
    n_sample = n_sample, reverse = reverse_or,
    smd_to_cor = rep("lipsey_cooper", length(d))
  )

  row_miss = which(is.na(d_se))
  es$d[row_miss] <- es$d_se[row_miss] <-
    es$d_ci_lo[row_miss] <- es$d_ci_up[row_miss] <-
    es$g[row_miss] <- es$g_se[row_miss] <-
    es$g_ci_lo[row_miss] <- es$g_ci_up[row_miss] <- NA
  es$r[row_miss] <- es$r_se[row_miss] <-
    es$r_ci_lo[row_miss] <- es$r_ci_up[row_miss] <-
    es$z[row_miss] <- es$z_se[row_miss] <-
    es$z_ci_lo[row_miss] <- es$z_ci_up[row_miss] <- NA


  # OR -------
  es$logor <- ifelse(reverse_or, -logOR, logOR)
  es$logor_se <- logor_se
  es$logor_ci_lo <- es$logor - es$logor_se * qnorm(.975)
  es$logor_ci_up <- es$logor + es$logor_se * qnorm(.975)
  or_ci_lo <- exp(log(or) - logor_se * qnorm(.975))
  or_ci_up <- exp(log(or) + logor_se * qnorm(.975))

  # RR -------
  es$logrr <- es$logrr_se <- es$logrr_ci_lo <- es$logrr_ci_up <- NA

  dat_rr <- data.frame(
    or = or, logor_se = logor_se, or_ci_lo = or_ci_lo, or_ci_up = or_ci_up,
    n_cases = n_cases, n_controls = n_controls, n_exp = n_exp, n_nexp = n_nexp,
    baseline_risk = baseline_risk, or_to_rr = or_to_rr
  )

  # print(paste0(or, ", ", or_ci_lo, ", ", or_ci_up, ", ",n_exp, ", ",n_nexp))
  nn_miss <- with(dat_rr, which(
      (or_to_rr == "grant" & !is.na(or) & !is.na(baseline_risk)) |
      (or_to_rr == "metaumbrella_cases" & !is.na(or) & !is.na(logor_se) &
         !is.na(n_cases) & !is.na(n_controls)) |
      (or_to_rr == "metaumbrella_exp" & !is.na(or) & !is.na(logor_se) &
         !is.na(n_exp) & !is.na(n_nexp)) |
      (or_to_rr == "transpose" & !is.na(or) & !is.na(logor_se)) |
      (or_to_rr == "dipietrantonj" & !is.na(or) & !is.na(or_ci_lo) & !is.na(or_ci_up) &
         !is.na(n_exp) & !is.na(n_nexp))
  ))


  if (length(nn_miss) != 0) {
    res_rr <- data.frame(t(mapply(.or_to_rr,
      or = dat_rr$or[nn_miss],
      logor_se = dat_rr$logor_se[nn_miss],
      or_ci_lo = dat_rr$or_ci_lo[nn_miss],
      or_ci_up = dat_rr$or_ci_up[nn_miss],
      n_cases = dat_rr$n_cases[nn_miss],
      n_controls = dat_rr$n_controls[nn_miss],
      n_exp = dat_rr$n_exp[nn_miss],
      n_nexp = dat_rr$n_nexp[nn_miss],
      baseline_risk = dat_rr$baseline_risk[nn_miss],
      or_to_rr = dat_rr$or_to_rr[nn_miss]
    )))
    res_rr$logrr = unlist(res_rr$logrr)
    res_rr$logrr_se = unlist(res_rr$logrr_se)
    res_rr$logrr_ci_lo = unlist(res_rr$logrr_ci_lo)
    res_rr$logrr_ci_up = unlist(res_rr$logrr_ci_up)
    es$logrr[nn_miss] <- ifelse(reverse_or[nn_miss], -res_rr[, 1], res_rr[, 1])
    es$logrr_se[nn_miss] <- res_rr[, 2]
    # On reverse: negate AND swap the CI bounds (new_lo = -old_up, new_up = -old_lo);
    # swapping alone left a wrong-signed, inverted interval that did not bracket -logrr.
    es$logrr_ci_lo[nn_miss] <- ifelse(reverse_or[nn_miss], -res_rr[, 4], res_rr[, 3])
    es$logrr_ci_up[nn_miss] <- ifelse(reverse_or[nn_miss], -res_rr[, 3], res_rr[, 4])
  }

  # COR -------
  dat_cor <- data.frame(
    or = or, logor_se = logor_se,
    n_cases = n_cases, n_exp = n_exp,
    n_sample = n_sample,
    small_margin_prop = small_margin_prop,
    or_to_cor = or_to_cor
  )

  nn_miss <- with(dat_cor, which(
    (or_to_cor == "bonett" & !is.na(or) & !is.na(logor_se) &
       !is.na(small_margin_prop) & !is.na(n_sample) &
      !is.na(n_exp) & !is.na(n_cases)) |
      (or_to_cor == "pearson" & !is.na(or) & !is.na(logor_se)) |
      (or_to_cor == "digby" & !is.na(or) & !is.na(logor_se))
  ))

  if (length(nn_miss) != 0) {
    no_cooper = which(or_to_cor != "lipsey_cooper")
    es$r[no_cooper] <- es$r_se[no_cooper] <- es$r_ci_lo[no_cooper] <- es$r_ci_up[no_cooper] <-
      es$z[no_cooper] <- es$z_se[no_cooper] <- es$z_ci_lo[no_cooper] <- es$z_ci_up[no_cooper] <- NA

    res_cor <- t(mapply(.or_to_cor,
      or = dat_cor$or[nn_miss],
      logor_se = dat_cor$logor_se[nn_miss],
      n_cases = dat_cor$n_cases[nn_miss],
      n_exp = dat_cor$n_exp[nn_miss],
      n_sample = dat_cor$n_sample[nn_miss],
      small_margin_prop = dat_cor$small_margin_prop[nn_miss],
      or_to_cor = dat_cor$or_to_cor[nn_miss]
    ))

    # On reverse: negate AND swap each CI (new_lo = -old_up, new_up = -old_lo). For r,
    # tanh is odd so negate-and-swap of the r bounds is correct even for the asymmetric,
    # z-back-transformed r interval. Swapping alone left inverted, wrong-signed bounds.
    es$r[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 1], res_cor[, 1])
    es$r_se[nn_miss] <- res_cor[, 2]
    es$r_ci_lo[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 4], res_cor[, 3])
    es$r_ci_up[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 3], res_cor[, 4])
    es$z[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 5], res_cor[, 5])
    es$z_se[nn_miss] <- res_cor[, 6]
    es$z_ci_lo[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 8], res_cor[, 7])
    es$z_ci_up[nn_miss] <- ifelse(reverse_or[nn_miss], -res_cor[, 7], res_cor[, 8])
  }

  # Risk difference from OR + baseline_risk (Grant 2014)
  treatment_risk <- (or * baseline_risk) / (1 - baseline_risk + or * baseline_risk)
  rd <- baseline_risk - treatment_risk

  es$rd <- ifelse(reverse_or, -rd, rd)
  # delta method
  drd_dor <- baseline_risk * (1 - baseline_risk) / (1 - baseline_risk + or * baseline_risk)^2
  rd_se <- abs(drd_dor) * or * logor_se
  es$rd_se <- rd_se
  es$rd_ci_lo <- es$rd - qnorm(.975) * rd_se
  es$rd_ci_up <- es$rd + qnorm(.975) * rd_se

  es$nnt <- ifelse(rd == 0, NA, 1 / rd)
  es$nnt <- ifelse(reverse_or, -es$nnt, es$nnt)
  es$nnt_se <- ifelse(rd == 0, NA, rd_se / rd^2)
  rd_ci_lo_raw <- rd - qnorm(.975) * rd_se
  rd_ci_up_raw <- rd + qnorm(.975) * rd_se
  crosses_zero <- (rd_ci_lo_raw < 0 & rd_ci_up_raw > 0) | rd == 0
  es$nnt_ci_lo <- ifelse(crosses_zero, NA,
                          ifelse(reverse_or, -1 / rd_ci_lo_raw, 1 / rd_ci_up_raw))
  es$nnt_ci_up <- ifelse(crosses_zero, NA,
                          ifelse(reverse_or, -1 / rd_ci_up_raw, 1 / rd_ci_lo_raw))

  es$info_used <- "or_se"
  return(es)
}

#' Convert an odds ratio value to several effect size measures
#'
#' @param or odds ratio value
#' @param logor log odds ratio value
#' @param n_cases number of cases/events
#' @param n_controls number of controls/no-event
#' @param n_exp number of participants in the exposed group
#' @param n_nexp number of participants in the non-exposed group
#' @param n_sample total number of participants in the sample
#' @param baseline_risk proportion of cases in the non-exposed group (n_cases_nexp / n_nexp is used when missing)
#' @param small_margin_prop smallest margin proportion of the underlying 2x2 table
#' @param reverse_or a logical value indicating whether the direction of the generated effect sizes should be flipped.
#' @param or_to_rr formula used to convert the \code{or} value into a risk ratio (see details).
#' @param or_to_cor formula used to convert the \code{or} value into a correlation coefficient (see details).
#'
#' @details
#' This function computes the standard error of the log odds ratio.
#' Risk ratio (RR), Cohen's d (D), Hedges' g (G) and correlation coefficients (R/Z),
#' are converted from the odds ratio value.
#'
#' **Estimation of the standard error of the log OR.**
#' This function generates the standard error of an odds ratio (OR) based on the OR value and the number of cases and controls.
#' More precisely, this function simulates all combinations of the possible number of cases and controls in the exposed and non-exposed groups
#' compatible with the reported OR value and with the overall number of cases and controls. Then, our function assumes that the variance of the OR
#' is equal to the mean of the standard error of all possible situations. This estimation thus necessarily comes with some imprecision and should not
#' be used before having requested the value (or raw data) to authors of the original report.
#'
#' **Conversion of other effect size measures.**
#' Calculations of \code{\link{es_from_or_se}()} are then applied to
#' estimate the other effect size measures
#'
#' @references
#' Gosling, C. J., Solanes, A., Fusar-Poli, P., & Radua, J. (2023). metaumbrella: the first comprehensive suite to perform data analysis in umbrella reviews with stratification of the evidence. BMJ mental health, 26(1), e300534. https://doi.org/10.1136/bmjment-2022-300534
#'
#' @export es_from_or
#'
#' @return
#' This function estimates and converts between several effect size measures.
#'
#' \tabular{ll}{
#'  \code{natural effect size measure} \tab N/A\cr
#'  \tab \cr
#'  \code{converted effect size measure} \tab OR + RR + NNT\cr
#'  \code{} \tab D + G + R + Z\cr
#'  \tab \cr
#'  \code{required input data} \tab See 'Section 2. Odds Ratio'\cr
#'  \tab https://metaconvert.org/input.html\cr
#'  \tab \cr
#' }
#'
#' @md
#'
#' @examples
#' es_or_guess <- es_from_or(or = 0.5, n_cases = 210, n_controls = 220)
#' es_or <- es_from_or_se(or = 0.5, logor_se = 0.4, n_cases = 210, n_controls = 220)
#' round(es_or_guess$logor_se, 0.10) == round(es_or$logor_se, 0.10)
es_from_or <- function(or, logor, n_cases, n_controls, n_sample,
                       small_margin_prop, baseline_risk,
                       n_exp, n_nexp,
                       or_to_cor = "bonett", or_to_rr = "metaumbrella_cases",
                       reverse_or) {
  if (missing(or)) {
    or <- rep(NA_real_, length(logor))
  }
  if (missing(logor)) {
    logor <- rep(NA_real_, length(or))
  }
  if (missing(baseline_risk)) {
    baseline_risk <- rep(NA_real_, length(or))
  }
  if (missing(small_margin_prop)) {
    small_margin_prop <- rep(NA_real_, length(or))
  }
  if (missing(n_exp)) {
    n_exp <- rep(NA_real_, length(or))
  }
  if (missing(n_nexp)) {
    n_nexp <- rep(NA_real_, length(or))
  }
  if (missing(n_cases)) {
    n_cases <- rep(NA_real_, length(or))
  }
  if (missing(n_controls)) {
    n_controls <- rep(NA_real_, length(or))
  }
  if (missing(reverse_or)) {
    reverse_or <- rep(FALSE, length(or))
  }
  if (missing(n_sample)) {
    n_sample <- rep(NA_real_, length(or))
  }
  reverse_or[is.na(reverse_or)] <- FALSE

  or <- ifelse(is.na(or) & !is.na(logor), exp(logor), or)

  dat_or_se <- data.frame(or, n_cases, n_controls)
  log_or_se <- do.call(rbind, apply(dat_or_se, 1, .se_from_or))

  es <- es_from_or_se(
    or = or, logor_se = log_or_se$se,
    n_cases = n_cases, n_controls = n_controls,
    small_margin_prop = small_margin_prop,
    baseline_risk = baseline_risk, n_sample=n_sample,
    n_exp = n_exp, n_nexp = n_nexp,
    or_to_cor = or_to_cor, or_to_rr = or_to_rr,
    reverse_or = reverse_or
  )

  es$info_used <- "or"
  return(es)
}

#' Convert an odds ratio value and its 95% confidence interval to several effect size measures
#'
#' @param or odds ratio value
#' @param logor log odds ratio value
#' @param or_ci_lo lower bound of the 95% CI around the odds ratio value
#' @param or_ci_up upper bound of the 95% CI around the odds ratio value
#' @param logor_ci_lo lower bound of the 95% CI around the log odds ratio value
#' @param logor_ci_up upper bound of the 95% CI around the log odds ratio value
#' @param n_cases number of cases/events
#' @param n_controls number of controls/no-event
#' @param n_exp number of participants in the exposed group (only required for the \code{or_to_rr = "grant"}, and \code{or_to_rr = "metaumbrella_exp"} arguments)
#' @param n_nexp number of participants in the non-exposed group (only required for the \code{or_to_rr = "grant"}, and \code{or_to_rr = "metaumbrella_exp"} arguments)
#' @param n_sample total number of participants in the sample
#' @param baseline_risk proportion of cases in the non-exposed group (only required for the \code{or_to_rr = "grant"} argument).
#' @param small_margin_prop smallest margin proportion of the underlying 2x2 table
#' @param reverse_or a logical value indicating whether the direction of the generated effect sizes should be flipped.
#' @param or_to_cor formula used to convert the \code{or} value into a correlation coefficient (see details).
#' @param or_to_rr formula used to convert the \code{or} value into a risk ratio (see details).
#' @param max_asymmetry A percentage indicating the tolerance before detecting asymmetry in the 95% CI bounds.
#'
#' @details
#' This function computes the standard error of the (log) odds ratio
#' into a standard error (Section 6.5.2.2 in the Cochrane Handbook).
#' \deqn{logor\_se = \frac{\log{or\_ci\_up} - \log{or\_ci\_lo}}{2 * qnorm(.975)}}
#'
#' Then, calculations of \code{\link{es_from_or_se}} are applied.
#'
#' @references
#' Higgins JPT, Li T, Deeks JJ (editors). Chapter 6: Choosing effect size measures and computing estimates of effect. In: Higgins JPT, Thomas J, Chandler J, Cumpston M, Li T, Page MJ, Welch VA (editors). Cochrane Handbook for Systematic Reviews of Interventions version 6.3 (updated February 2022). Cochrane, 2022. Available from www.training.cochrane.org/handbook.
#'
#' @export es_from_or_ci
#'
#' @return
#' This function estimates and converts between several effect size measures.
#'
#' \tabular{ll}{
#'  \code{natural effect size measure} \tab OR\cr
#'  \tab \cr
#'  \code{converted effect size measure} \tab RR + NNT\cr
#'  \code{} \tab D + G + R + Z\cr
#'  \tab \cr
#'  \code{required input data} \tab See 'Section 2. Odds Ratio'\cr
#'  \tab https://metaconvert.org/input.html\cr
#'  \tab \cr
#' }
#'
#' @md
#'
#' @examples
#' es_or <- es_from_or_ci(
#'   or = 1, or_ci_lo = 0.5, or_ci_up = 2,
#'   n_cases = 42, n_controls = 38, baseline_risk = 0.08,
#'   or_to_rr = "grant"
#' )
es_from_or_ci <- function(or, or_ci_lo, or_ci_up, logor, logor_ci_lo, logor_ci_up,
                          baseline_risk, small_margin_prop, n_exp, n_nexp,
                          n_cases, n_controls, n_sample, max_asymmetry = 10,
                          or_to_cor = "bonett", or_to_rr = "metaumbrella_cases",
                          reverse_or) {
  if (missing(or)) {
    or <- rep(NA_real_, length(logor))
  }
  if (missing(logor)) {
    logor <- rep(NA_real_, length(or))
  }
  if (missing(baseline_risk)) {
    baseline_risk <- rep(NA_real_, length(or))
  }
  if (missing(small_margin_prop)) {
    small_margin_prop <- rep(NA_real_, length(or))
  }
  if (missing(n_exp)) {
    n_exp <- rep(NA_real_, length(or))
  }
  if (missing(n_nexp)) {
    n_nexp <- rep(NA_real_, length(or))
  }
  if (missing(n_cases)) {
    n_cases <- rep(NA_real_, length(or))
  }
  if (missing(n_controls)) {
    n_controls <- rep(NA_real_, length(or))
  }
  if (missing(or_ci_lo)) {
    or_ci_lo <- rep(NA_real_, length(or))
  }
  if (missing(logor_ci_lo)) {
    logor_ci_lo <- rep(NA_real_, length(or))
  }
  if (missing(or_ci_up)) {
    or_ci_up <- rep(NA_real_, length(or))
  }
  if (missing(logor_ci_up)) {
    logor_ci_up <- rep(NA_real_, length(or))
  }
  if (missing(reverse_or)) {
    reverse_or <- rep(FALSE, length(or))
  }
  if (missing(n_sample)) {
    n_sample <- rep(NA_real_, length(or))
  }
  reverse_or[is.na(reverse_or)] <- FALSE

  or <- ifelse(is.na(or) & !is.na(logor), exp(logor), or)


  logor_ci_lo <- ifelse(is.na(logor_ci_lo) & !is.na(or_ci_lo), log(or_ci_lo), logor_ci_lo)
  logor_ci_up <- ifelse(is.na(logor_ci_up) & !is.na(or_ci_up), log(or_ci_up), logor_ci_up)
  logor_se <- (logor_ci_up - logor_ci_lo) / (2 * qnorm(.975))

  es <- es_from_or_se(
    or = or, logor_se = logor_se,
    n_cases = n_cases, n_controls = n_controls,
    baseline_risk = baseline_risk, small_margin_prop = small_margin_prop,
    n_exp = n_exp, n_nexp = n_nexp, n_sample = n_sample,
    or_to_cor = or_to_cor, or_to_rr = or_to_rr,
    reverse_or = reverse_or
  )

  es$info_used <- "or_ci"

  return(es)
}

#' Convert an odds ratio value and its standard error to several effect size measures
#'
#' @param or odds ratio value
#' @param logor log odds ratio value
#' @param or_pval p-value of the (log) odds ratio
#' @param n_cases number of cases/events
#' @param n_controls number of controls/no-event
#' @param n_exp number of participants in the exposed group (only required for the \code{or_to_rr = "grant"}, and \code{or_to_rr = "metaumbrella_exp"} arguments)
#' @param n_nexp number of participants in the non-exposed group (only required for the \code{or_to_rr = "grant"}, and \code{or_to_rr = "metaumbrella_exp"} arguments)
#' @param n_sample total number of participants in the sample
#' @param baseline_risk proportion of cases in the non-exposed group (only required for the \code{or_to_rr = "grant"} argument).
#' @param small_margin_prop smallest margin proportion of the underlying 2x2 table
#' @param reverse_or_pval a logical value indicating whether the direction of the generated effect sizes should be flipped.
#' @param or_to_cor formula used to convert the \code{or} value into a correlation coefficient (see details).
#' @param or_to_rr formula used to convert the \code{or} value into a risk ratio (see details).
#'
#' @details
#' This function computes the standard error of the (log) odds ratio into
#' from a p-value (Section 6.3.2 in the Cochrane Handbook).
#' \deqn{logor\_z = qnorm(or_pval/2, lower.tail=FALSE)}
#' \deqn{logor\_se = |\frac{\log(or)}{logor\_z}|}
#'
#' Then, calculations of \code{\link{es_from_or_se}()} are applied.
#'
#' @return
#' This function estimates and converts between several effect size measures.
#'
#' \tabular{ll}{
#'  \code{natural effect size measure} \tab OR\cr
#'  \tab \cr
#'  \code{converted effect size measure} \tab RR + NNT\cr
#'  \code{} \tab D + G + R + Z\cr
#'  \tab \cr
#'  \code{required input data} \tab See 'Section 2. Odds Ratio'\cr
#'  \tab https://metaconvert.org/input.html\cr
#'  \tab \cr
#' }
#'
#' @export es_from_or_pval
#'
#' @references
#' Higgins, J. P., Thomas, J., Chandler, J., Cumpston, M., Li, T., Page, M. J., & Welch, V. A. (Eds.). (2019). Cochrane handbook for systematic reviews of interventions. John Wiley & Sons.
#'
#' @md
#'
#' @examples
#' es_or <- es_from_or_pval(
#'   or = 3.51, or_pval = 0.001,
#'   n_cases = 12, n_controls = 68
#' )
es_from_or_pval <- function(or, logor, or_pval, baseline_risk, small_margin_prop,
                            n_exp, n_nexp, n_cases, n_controls, n_sample,
                            or_to_rr = "metaumbrella_cases",
                            or_to_cor = "bonett", reverse_or_pval) {
  if (missing(or)) {
    or <- rep(NA_real_, length(logor))
  }
  if (missing(logor)) {
    logor <- rep(NA_real_, length(or))
  }
  if (missing(baseline_risk)) {
    baseline_risk <- rep(NA_real_, length(or))
  }
  if (missing(small_margin_prop)) {
    small_margin_prop <- rep(NA_real_, length(or))
  }
  if (missing(n_exp)) {
    n_exp <- rep(NA_real_, length(or))
  }
  if (missing(n_nexp)) {
    n_nexp <- rep(NA_real_, length(or))
  }
  if (missing(n_cases)) {
    n_cases <- rep(NA_real_, length(or))
  }
  if (missing(n_controls)) {
    n_controls <- rep(NA_real_, length(or))
  }
  if (missing(reverse_or_pval)) {
    reverse_or_pval <- rep(FALSE, length(or))
  }
  if (missing(n_sample)) {
    n_sample <- rep(NA_real_, length(or))
  }
  reverse_or_pval[is.na(reverse_or_pval)] <- FALSE

  or <- ifelse(is.na(or) & !is.na(logor), exp(logor), or)
  logOR <- suppressWarnings(log(or))

  z_or <- qnorm(or_pval / 2, lower.tail = FALSE)
  logor_se <- abs(logOR / z_or)

  es <- es_from_or_se(
    or = or, logor_se = logor_se,
    baseline_risk = baseline_risk, small_margin_prop = small_margin_prop,
    n_exp = n_exp, n_nexp = n_nexp, n_sample = n_sample,
    n_cases = n_cases, n_controls = n_controls,
    or_to_cor = or_to_cor, or_to_rr = or_to_rr,
    reverse_or = reverse_or_pval
  )

  es$info_used <- "or_pval"

  return(es)
}

#' Convert an odds ratio or risk ratio and a Wald t-statistic from a regression model into several effect size measures
#'
#' @param or odds ratio value (from logistic regression)
#' @param logor log odds ratio value
#' @param rr risk ratio value (from log-binomial or modified Poisson regression)
#' @param logrr log risk ratio value
#' @param logreg_t a t-statistic (Wald statistic) from a logistic, log-binomial, or modified Poisson regression model
#' @param n_cases number of cases/events across exposed/non-exposed groups
#' @param n_controls number of controls/no-event across exposed/non-exposed groups
#' @param n_exp number of participants in the exposed group
#' @param n_nexp number of participants in the non-exposed group
#' @param n_sample total number of participants in the sample
#' @param baseline_risk proportion of cases in the non-exposed group
#' @param small_margin_prop smallest margin proportion of cases/events in the underlying 2x2 table
#' @param reverse_logreg_t a logical value indicating whether the direction of the generated effect sizes should be flipped.
#' @param or_to_rr formula used to convert the \code{or} value into a risk ratio (see details).
#' @param or_to_cor formula used to convert the \code{or} value into a correlation coefficient (see details).
#' @param rr_to_or formula used to convert the \code{rr} value into an odds ratio (see details).
#'
#' @details
#' This function derives the standard error of the log odds ratio (or log risk ratio) from a
#' Wald t-statistic reported in a regression model.
#'
#' **To estimate the standard error of the log OR (or log RR)**, the formulas used are:
#' \deqn{t = \frac{\beta}{SE(\beta)}}
#' \deqn{SE(\beta) = \frac{|\beta|}{|t|}}
#' where \eqn{\beta} is \eqn{\log(OR)} or \eqn{\log(RR)} depending on the model.
#'
#' Then, if an OR (or logOR) is entered, calculations of \code{\link{es_from_or_se}()} are applied.
#' If a RR (or logRR) is entered, calculations of \code{\link{es_from_rr_se}()} are applied.
#'
#' Note that the standardized-mean-difference and correlation conversions (D, G, R, Z) are
#' produced for **OR inputs only**. RR inputs are treated as a ratio measure and yield
#' RR + OR + NNT + RD: RR is not converted to a standardized mean difference or correlation,
#' because that would require going through the OR and the baseline risk (see
#' \code{\link{es_from_rr_se}}). To obtain a SMD or correlation from an RR, convert it to an
#' OR first (supplying the baseline risk) and then use the OR path.
#'
#' @return
#' This function estimates and converts between several effect size measures.
#' \tabular{ll}{
#'  \code{natural effect size measure} \tab OR + RR \cr
#'  \tab \cr
#'  \code{converted effect size measure} \tab OR inputs: D + G + R + Z (+ RR + NNT + RD); RR inputs: OR + NNT + RD \cr
#' }
#'
#' @references
#' Sanchez-Meca, J., Marin-Martinez, F., & Chacon-Moscoso, S. (2003). Effect-size indices for
#' dichotomized outcomes in meta-analysis. \emph{Psychological Methods}, 8(4), 448--467.
#'
#' @md
#'
#' @export es_from_logreg_t
#'
#' @examples
#' es_or <- es_from_logreg_t(
#'   or = 2.12, logreg_t = 3.21,
#'   n_cases = 50, n_controls = 150
#' )
#'
#' es_rr <- es_from_logreg_t(
#'   rr = 1.5, logreg_t = 2.8,
#'   n_exp = 100, n_nexp = 100
#' )
es_from_logreg_t <- function(or, logor, rr, logrr, logreg_t,
                         baseline_risk, small_margin_prop,
                         n_exp, n_nexp, n_cases, n_controls, n_sample,
                         or_to_rr = "metaumbrella_cases",
                         or_to_cor = "bonett",
                         rr_to_or = "metaumbrella",
                         reverse_logreg_t) {

  len <- if (!missing(or)) length(or) else if (!missing(logor)) length(logor) else if (!missing(rr)) length(rr) else if (!missing(logrr)) length(logrr) else length(logreg_t)

  if (missing(or)) or <- rep(NA_real_, len)
  if (missing(logor)) logor <- rep(NA_real_, len)
  if (missing(rr)) rr <- rep(NA_real_, len)
  if (missing(logrr)) logrr <- rep(NA_real_, len)
  if (missing(baseline_risk)) baseline_risk <- rep(NA_real_, len)
  if (missing(small_margin_prop)) small_margin_prop <- rep(NA_real_, len)
  if (missing(n_exp)) n_exp <- rep(NA_real_, len)
  if (missing(n_nexp)) n_nexp <- rep(NA_real_, len)
  if (missing(n_cases)) n_cases <- rep(NA_real_, len)
  if (missing(n_controls)) n_controls <- rep(NA_real_, len)
  if (missing(n_sample)) n_sample <- rep(NA_real_, len)
  if (missing(logreg_t)) logreg_t <- rep(NA_real_, len)
  if (missing(reverse_logreg_t)) reverse_logreg_t <- rep(FALSE, len)
  reverse_logreg_t[is.na(reverse_logreg_t)] <- FALSE

  has_or <- !is.na(or) | !is.na(logor)
  has_rr <- !is.na(rr) | !is.na(logrr)

  # OR -------
  or <- ifelse(is.na(or) & !is.na(logor), exp(logor), or)
  logOR <- suppressWarnings(log(or))
  logor_se <- abs(logOR / logreg_t)

  es_or <- es_from_or_se(
    or = or, logor_se = logor_se,
    baseline_risk = baseline_risk, small_margin_prop = small_margin_prop,
    n_exp = n_exp, n_nexp = n_nexp, n_sample = n_sample,
    n_cases = n_cases, n_controls = n_controls,
    or_to_cor = or_to_cor, or_to_rr = or_to_rr,
    reverse_or = reverse_logreg_t
  )

  # RR -------
  rr <- ifelse(is.na(rr) & !is.na(logrr), exp(logrr), rr)
  logRR <- suppressWarnings(log(rr))
  logrr_se <- abs(logRR / logreg_t)

  es_rr <- es_from_rr_se(
    rr = rr, logrr_se = logrr_se,
    baseline_risk = baseline_risk,
    n_exp = n_exp, n_nexp = n_nexp,
    n_cases = n_cases, n_controls = n_controls,
    rr_to_or = rr_to_or,
    reverse_rr = reverse_logreg_t
  )

  use_rr <- has_rr & !has_or

  if (!any(use_rr)) {
    es_or$info_used <- "logreg_t"
    return(es_or)
  } else if (all(use_rr)) {
    es_rr$info_used <- "logreg_t"
    return(es_rr)
  }

  all_cols <- union(names(es_or), names(es_rr))
  es <- data.frame(matrix(NA_real_, nrow = len, ncol = 0))
  for (col in all_cols) {
    if (col == "info_used") next
    or_val <- if (col %in% names(es_or)) es_or[[col]] else rep(NA_real_, len)
    rr_val <- if (col %in% names(es_rr)) es_rr[[col]] else rep(NA_real_, len)
    es[[col]] <- ifelse(use_rr, rr_val, or_val)
  }
  es$info_used <- "logreg_t"

  return(es)
}
