#' Benchmark domain estimates to an official aggregate
#'
#' @param estimates A fitted `inter_sae` object or a data frame containing
#'   `estimate` and the selected weight column.
#' @param target Official weighted mean/proportion to reproduce.
#' @param weight Name of the benchmarking-weight column.
#' @param method Ratio, additive, or bounded logit benchmarking.
#' @param lower,upper Permitted estimate range for logit benchmarking.
#' @return The input estimates with `original_estimate`, `benchmarked`, and
#'   `benchmark_adjustment` columns.
#' @export
benchmark_inter <- function(estimates, target, weight = "population",
                            method = c("logit", "ratio", "additive"),
                            lower = 0, upper = 1) {
  if (inherits(estimates, "inter_sae")) estimates <- estimates$estimates
  .inter_assert_data_frame(estimates, "estimates")
  method <- match.arg(method)
  if (!all(c("estimate", weight) %in% names(estimates))) {
    stop("The estimate and benchmarking-weight columns were not found.",
         call. = FALSE)
  }
  if (!is.numeric(target) || length(target) != 1L || !is.finite(target)) {
    stop("`target` must be one finite number.", call. = FALSE)
  }
  estimate <- estimates$estimate
  weights <- estimates[[weight]]
  if (any(!is.finite(estimate)) || any(!is.finite(weights)) ||
      any(weights < 0) || sum(weights) <= 0) {
    stop("Estimates and benchmarking weights must be finite; weights must be non-negative with positive total.",
         call. = FALSE)
  }
  current <- .inter_weighted_mean(estimate, weights)
  benchmarked <- switch(
    method,
    ratio = {
      if (abs(current) < .Machine$double.eps) {
        stop("Ratio benchmarking is undefined for a zero current aggregate.",
             call. = FALSE)
      }
      estimate * target / current
    },
    additive = estimate + target - current,
    logit = {
      if (!is.finite(lower) || !is.finite(upper) || lower >= upper ||
          target <= lower || target >= upper) {
        stop("For logit benchmarking, `lower < target < upper` is required.",
             call. = FALSE)
      }
      scaled <- (estimate - lower) / (upper - lower)
      scaled <- pmin(1 - 1e-10, pmax(1e-10, scaled))
      eta <- stats::qlogis(scaled)
      objective <- function(delta) {
        adjusted <- lower + (upper - lower) * stats::plogis(eta + delta)
        .inter_weighted_mean(adjusted, weights) - target
      }
      root <- stats::uniroot(objective, interval = c(-50, 50),
                             tol = 1e-12)$root
      lower + (upper - lower) * stats::plogis(eta + root)
    }
  )
  estimates$original_estimate <- estimate
  estimates$benchmarked <- benchmarked
  estimates$benchmark_adjustment <- benchmarked - estimate
  attr(estimates, "benchmark_target") <- target
  attr(estimates, "benchmark_achieved") <-
    .inter_weighted_mean(benchmarked, weights)
  attr(estimates, "benchmark_method") <- method
  estimates
}
