## Shared helpers + paths for the inflation-expectations analyses.
suppressWarnings(suppressMessages(library(here)))

path_raw    <- function(f) here::here("data", "data_raw", f)
path_clean  <- function(f) here::here("data", "data_cleaned", f)
path_output <- function(f) here::here("output", f)

# ---- Study-3 (preregistered, AsPredicted #297,841) constants ----
CONSENSUS <- 2.9  # consensus 12-month CPI forecast at preregistration; GenAI moves 3pp toward it

# 7 draggable uncertainty bars -> interval midpoints. The two unbounded tails are
# treated as-if 2pp wide per the prereg -> midpoints -3 and 9.
BIN_MIDPOINTS <- c(ltm2 = -3, m2_0 = -1, `0_2` = 1, `2_4` = 3, `4_6` = 5, `6_8` = 7, gt8 = 9)

# stored treatment code -> preregistration label (Control = regression reference)
COND_LABELS <- c(baseline = "Baseline", factors = "Optimized", unrelated = "Control")
COND_ORDER  <- c("Control", "Baseline", "Optimized")
COND_COLOR  <- c(Control = "#9e9e9e", Baseline = "#4C72B0", Optimized = "#55A868")

## SD of the inflation distribution encoded in a draggable-bar JSON string. NA if absent.
dist_sd <- function(raw) {
  if (length(raw) != 1 || is.na(raw) || !nzchar(trimws(as.character(raw)))) return(NA_real_)
  d <- tryCatch(jsonlite::fromJSON(as.character(raw)), error = function(e) NULL)
  if (is.null(d)) return(NA_real_)
  keys <- intersect(names(d), names(BIN_MIDPOINTS))
  if (!length(keys)) return(NA_real_)
  mids <- BIN_MIDPOINTS[keys]
  w <- suppressWarnings(as.numeric(unlist(d[keys]))); w[is.na(w)] <- 0
  if (sum(w) <= 0) return(NA_real_)
  p <- w / sum(w)
  mu <- sum(p * mids)
  sqrt(sum(p * (mids - mu)^2))
}

## We ALWAYS report two-sided p (conservative), even for directional hypotheses.
sig_stars <- function(p) ifelse(!is.finite(p), "",
  ifelse(p < .001, "***", ifelse(p < .01, "**", ifelse(p < .05, "*", ifelse(p < .1, "†", "")))))

## Two-sided contrast (Optimized - Baseline) from an lm, computed from vcov (no extra deps).
contrast_opt_vs_base <- function(m) {
  b <- coef(m); V <- vcov(m)
  if (!all(c("Optimized", "Baseline") %in% names(b))) return(c(estimate = NA, se = NA, t = NA, p = NA))
  est <- b[["Optimized"]] - b[["Baseline"]]
  se  <- sqrt(V["Optimized", "Optimized"] + V["Baseline", "Baseline"] - 2 * V["Optimized", "Baseline"])
  t   <- est / se
  c(estimate = est, se = se, t = t, p = 2 * stats::pt(-abs(t), m$df.residual))  # two-sided
}
