#' Internal Prior Table Printer
#'
#' Formats and displays the current parameter specifications in a clean,
#' readable table within the R console.
#'
#' @param parms A \code{data.frame} containing current prior specifications,
#' typically generated by \code{.make_default_parms()}.
#'
#' @return No return value; called for side effects (printing to console).
#' @keywords internal
.print_parms_table <- function(parms) {
  cat("\n")
  cat(sprintf("  %-3s  %-20s  %-30s  %-45s\n",
              "#", "Variable name", "Default prior (Enter # to change)", "Description"))
  cat(sprintf("  %-3s  %-20s  %-30s  %-45s\n",
              "--", "--------------------", "------------------------------",
              "---------------------------------------------"))
  for (i in seq_len(nrow(parms))) {
    prior_name  <- parms$priors[i]
    dist_label  <- .dist_label(parms$distribution[i])
    args_fmt    <- .format_args(parms$arguments[i])
    description <- .prior_descriptions[prior_name]
    cat(sprintf("  %-3s  %-20s  %-30s  %-45s\n",
                i,
                prior_name,
                paste0(dist_label, args_fmt),
                description))
  }
  cat("\n")
}

#' Interactive Prior Specification Wizard
#'
#' Launches an interactive console-based interface to guide users through
#' viewing and modifying Bayesian prior distributions for mediation models.
#'
#' @description
#' This function allows users to customize priors without needing to manually
#' construct complex data frames. It displays current defaults, allows
#' selection of specific parameters to change, and provides a menu of
#' available probabilistic distributions (e.g., Normal, Gamma, Beta).
#'
#' @details
#' The wizard handles two main types of customization:
#' \itemize{
#'   \item \strong{Distribution Selection:} Choose from supported probabilistic distributions.
#'   \item \strong{Argument Specification:} Set numeric values for
#'   hyperparameters (e.g., shape, rate, mean, precision).
#' }
#'
#' For coefficients like \eqn{a} and \eqn{b}, the wizard will note if they
#' reference hyperpriors (back-references). It is generally recommended to
#' modify the shape of the hyperprior rather than the coefficient's distribution
#' directly to maintain the hierarchical structure.
#'
#' @return A \code{data.frame} with columns \code{priors}, \code{distribution},
#' and \code{arguments}. This dataframe is formatted to be passed directly
#' to the \code{my_prior} argument in related fitting functions.
#'
#' @param verbose Logical. If \code{TRUE} (default), the wizard prints
#' introductory text and the summary review table. If \code{FALSE}, only
#' the interactive prompts are displayed.
#'
#' @note
#' This function requires an interactive R session. It will return
#' \code{invisible(NULL)} if the user cancels the process.
#'
#'
#' @examples
#' # Create toy data
#' toy_data <- data.frame(
#'    X = rbinom(100, 1, 0.5),
#'    M = rbinom(100, 1, 0.3),
#'    Y = rbinom(100, 1, 0.5)
#' )
#'
#' custom_priors <- NULL
#'
#' if (interactive()){
#' # Launch the wizard
#' custom_priors <- run_parms_wizard()
#' }
#'
#' # Use the resulting object in a model
#' fit <- buzzEBMcatMcatY(model = "Y ~ M | X",
#'                      dataset = toy_data,
#'                      my_prior = custom_priors)
#'
#' @export
#'
#'
run_parms_wizard <- function(verbose = TRUE) {
  .check_dist_lookup_coverage()
  parms <- .make_default_parms()

  # --- Step 1: Show current defaults ----------------------------------------
  if (verbose) {
  cat("\n=== Prior specification wizard ===\n")
  cat("Current default priors:\n")
  .print_parms_table(parms)
}
  # --- Step 2: Which priors to change ---------------------------------------

  raw_input <- readline(prompt = "Enter the numbers of the priors you want to change (comma-separated), or press Enter to accept all defaults: ")

  if (trimws(raw_input) == "") {
    message("\nNo changes made. Returning default parms.\n")
    return(parms[, c("priors", "distribution", "arguments")])
  }

  selected_idx <- suppressWarnings(
    as.integer(trimws(strsplit(raw_input, ",")[[1]]))
  )

  invalid_idx <- selected_idx[is.na(selected_idx) |
                                selected_idx < 1 |
                                selected_idx > nrow(parms)]
  if (length(invalid_idx) > 0) {
    stop(sprintf(
      "Invalid selection(s): %s. Please enter numbers between 1 and %d.",
      paste(invalid_idx, collapse = ", "), nrow(parms)
    ))
  }

  # --- Step 3: For each selected prior, ask for new distribution + arguments -

  dist_names <- names(.dist_lookup)  # JAGS names, e.g. "dnorm"

  for (idx in selected_idx) {
    prior_name        <- parms$priors[idx]
    current_dist_jags <- parms$distribution[idx]          # "dnorm" — never convert this
    current_args      <- parms$arguments[idx]

    cat(sprintf("\n--- Prior: %s ---\n", prior_name))
    cat(sprintf("  Current distribution : %s\n", .dist_label(current_dist_jags)))
    cat(sprintf("  Current arguments    : (%s)\n", current_args))

    # Show numbered distribution menu
    cat("\n  Available distributions:\n")
    for (d in seq_along(dist_names)) {
      entry <- .dist_lookup[[dist_names[d]]]
      cat(sprintf("    %-3s  %-25s  args: (%s)\n",
                  d,
                  entry$label,
                  paste(entry$args, collapse = ", ")))
    }

    # Distribution selection — keep JAGS name throughout
    dist_prompt <- sprintf("  Select distribution (press Enter to keep '%s'): ",
                           .dist_label(current_dist_jags))
    dist_input  <- trimws(readline(prompt = dist_prompt))

    if (dist_input == "") {
      new_dist <- current_dist_jags  # JAGS name, e.g. "dnorm"
    } else {
      dist_choice <- suppressWarnings(as.integer(dist_input))
      if (is.na(dist_choice) || dist_choice < 1 || dist_choice > length(dist_names)) {
        stop(sprintf(
          "Invalid distribution selection '%s'. Enter a number between 1 and %d.",
          dist_input, length(dist_names)
        ))
      }
      new_dist <- dist_names[dist_choice]  # JAGS name from lookup
    }

    # Guard: should never fire if .dist_lookup covers all defaults
    new_dist_entry <- .dist_lookup[[new_dist]]
    if (is.null(new_dist_entry)) {
      stop(sprintf(
        "Distribution '%s' was not found in .dist_lookup. Check that .dist_lookup covers all default distributions.",
        new_dist
      ))
    }

    # Argument prompts — fall back to current value if Enter is pressed
    current_arg_values <- trimws(strsplit(current_args, ",")[[1]])
    arg_values <- character(new_dist_entry$arity)

    for (a in seq_along(new_dist_entry$args)) {
      # If switching distribution, there may be fewer current args than new arity
      current_val <- if (a <= length(current_arg_values)) current_arg_values[a] else ""
      arg_prompt  <- if (current_val != "") {
        sprintf("    %s (press Enter to keep '%s'): ", new_dist_entry$args[a], current_val)
      } else {
        sprintf("    %s: ", new_dist_entry$args[a])
      }
      raw_arg <- trimws(readline(prompt = arg_prompt))
      arg_values[a] <- if (raw_arg == "" && current_val != "") current_val else raw_arg
    }

    new_args <- paste(arg_values, collapse = ",")

    # Write back — always JAGS name, never the label
    parms$distribution[idx] <- new_dist
    parms$arguments[idx]    <- new_args
  }

  # --- Step 4: Confirm -------------------------------------------------------

  if (verbose) {
  cat("\n=== Review your changes ===\n")
  .print_parms_table(parms)
  }
  confirm <- trimws(tolower(readline(prompt = "Confirm and return this dataframe? (Y/n): ")))

  if (confirm == "n") {
    message("\nWizard cancelled. No dataframe returned.\n")
    return(invisible(NULL))
  }

  # --- Step 5: Return --------------------------------------------------------

  message("\nDone!\n")
  parms[, c("priors", "distribution", "arguments")]
}
