#' Convert List of Plots to officer-Compatible Format
#'
#' @description
#' Prepares a named list of mschart objects for insertion into a Word document
#' using officer. Typically used with plots generated by [makeme()] with
#' `crowd` parameter and `type = "cat_plot_docx"`.
#'
#' @param plot_list A named list of mschart objects. Names become section labels.
#'   Typically created with:
#'   `makeme(crowd = c("target", "others"), type = "cat_plot_docx", docx_return_object = TRUE)`.
#' @param extract_metadata Logical. If `TRUE` (default), extracts and includes
#'   metadata (like `dep_label_prefix`) from each plot object.
#'
#' @return A list with class `"saros_officer_plots"` containing:
#'   - `plots`: Named list of mschart objects ready for officer insertion
#'   - `metadata`: List of metadata for each plot (if `extract_metadata = TRUE`),
#'     including plot names, dep_label_prefix, and other attributes; `NULL` if
#'     `extract_metadata = FALSE`
#'   - `n_plots`: Integer count of valid mschart objects after filtering
#'
#' @details
#' This function validates and structures plot objects for Word document assembly.
#' Unlike [crowd_plots_as_tabset()] which generates Quarto markdown directly,
#' this function returns a structured R object that can be used programmatically
#' with officer to build Word documents.
#'
#' **Typical Workflow:**
#' 1. Generate mschart objects with `makeme(..., type = "cat_plot_docx",
#'    docx_return_object = TRUE, crowd = ...)`
#' 2. Pass the list to `crowd_plots_as_officer()` for validation and structuring
#' 3. Use the returned object to insert plots into a Word document via officer
#'
#' **Metadata Extraction:**
#' When `extract_metadata = TRUE`, the function extracts:
#' - `dep_label_prefix`: Main question text (from [get_dep_label_prefix()])
#' - `name`: Plot name from the list
#' - Additional attributes attached to the plot object
#'
#' @seealso
#' - [crowd_plots_as_tabset()] for the Quarto/HTML equivalent
#' - [makeme()] for creating plots with crowd parameter
#' - [get_dep_label_prefix()] for retrieving main question metadata
#' - [mschart::body_add_chart()] for inserting charts into Word documents
#'
#' @export
#'
#' @examples
#' \dontrun{
#' # Generate mschart objects for Word
#' plots <- makeme(
#'   data = ex_survey,
#'   dep = b_1:b_3,
#'   crowd = c("target", "others"),
#'   mesos_var = "f_uni",
#'   mesos_group = "Uni of A",
#'   type = "cat_plot_docx",
#'   docx_return_object = TRUE
#' )
#'
#' # Prepare for officer assembly
#' officer_plots <- crowd_plots_as_officer(plots)
#'
#' # Use in officer workflow
#' library(officer)
#' doc <- read_docx()
#' for (plot_name in names(officer_plots$plots)) {
#'   doc <- doc |>
#'     body_add_par(plot_name, style = "heading 2") |>
#'     body_add_par(officer_plots$metadata[[plot_name]]$dep_label_prefix) |>
#'     mschart::body_add_chart(officer_plots$plots[[plot_name]])
#' }
#' print(doc, target = "output.docx")
#' }
crowd_plots_as_officer <- function(
  plot_list,
  extract_metadata = TRUE
) {
  # Validate inputs
  if (!is.list(plot_list)) {
    cli::cli_abort(
      "{.arg plot_list} must be a list, not {.cls {class(plot_list)}}."
    )
  }

  # Validate extract_metadata is boolean
  if (!rlang::is_bool(extract_metadata)) {
    cli::cli_abort(
      "{.arg extract_metadata} must be a single logical value (TRUE or FALSE), not {.obj_type_friendly {extract_metadata}}."
    )
  }

  # Handle empty list early (before name validation)
  if (length(plot_list) == 0) {
    cli::cli_warn("{.arg plot_list} is empty. Returning empty structure.")
    return(structure(
      list(
        plots = list(),
        metadata = if (extract_metadata) list() else NULL,
        n_plots = 0L
      ),
      class = "saros_officer_plots"
    ))
  }

  # Validate plot_list has names
  if (is.null(names(plot_list))) {
    cli::cli_abort(
      "{.arg plot_list} must be a named list. Use meaningful names for plots."
    )
  }

  # Check for missing or empty names
  if (any(is.na(names(plot_list))) || any(names(plot_list) == "")) {
    cli::cli_abort(
      "{.arg plot_list} contains missing or empty names. All plots must have non-empty names."
    )
  }

  # Filter out NULL plots and validate
  valid_plots <- list()
  metadata_list <- list()

  for (i in seq_along(plot_list)) {
    plot <- plot_list[[i]]
    plot_name <- names(plot_list)[i]

    # Skip NULL plots
    if (is.null(plot)) {
      next
    }

    # Validate that each plot is an mschart object
    if (!inherits(plot, "ms_chart")) {
      cli::cli_warn(c(
        "Plot {.val {plot_name}} is not a valid mschart object (class: {.cls {class(plot)}}).",
        "i" = "Skipping this plot.",
        "i" = "Ensure plots are created with {.code type = 'cat_plot_docx'} and {.code docx_return_object = TRUE}."
      ))
      next
    }

    # Store valid plot
    valid_plots[[plot_name]] <- plot

    # Extract metadata if requested
    if (extract_metadata) {
      metadata_list[[plot_name]] <- list(
        name = plot_name,
        dep_label_prefix = get_dep_label_prefix(plot),
        # Include any other attributes
        attributes = attributes(plot)
      )
    }
  }

  # Check if any valid plots remain
  if (length(valid_plots) == 0) {
    cli::cli_warn(
      "No valid mschart objects found in {.arg plot_list}. Returning empty structure."
    )
  }

  # Return structured object
  result <- structure(
    list(
      plots = valid_plots,
      metadata = if (extract_metadata) metadata_list else NULL,
      n_plots = length(valid_plots)
    ),
    class = "saros_officer_plots"
  )

  result
}

#' Print method for saros_officer_plots
#'
#' @param x A saros_officer_plots object
#' @param ... Additional arguments (unused)
#'
#' @return Invisibly returns `x`
#' @keywords internal
#' @export
print.saros_officer_plots <- function(x, ...) {
  cli::cli_h1("saros officer plots")
  cli::cli_text("{.strong Number of plots:} {x$n_plots}")

  if (x$n_plots > 0) {
    cli::cli_h2("Plot names:")
    cli::cli_ul(names(x$plots))

    if (!is.null(x$metadata)) {
      cli::cli_h2("Metadata available:")
      cli::cli_text("Each plot includes: name, dep_label_prefix, attributes")
    }
  } else {
    cli::cli_alert_info("No plots available")
  }

  invisible(x)
}
