is_facet <- function (o) !is.null(o$facets$facets)

is_grid <- function (o) !is.null(o$grid$rows) | !is.null(o$grid$cols)

plot_variants <- list(
    list(
        condition = function(datasets, options) length(datasets) == 1,
        variant = plot_single_dataset
    ),
    list(
        condition = function(datasets, options) {
            !is_facet(options) && !is_grid(options)
        },
        variant = plot_multiple_datasets
    ),
    list(
        condition = function(datasets, options) is_facet(options),
        variant = plot_multiple_faceted_datasets
    ),
    list(
        condition = function(datasets, options) is_grid(options),
        variant = plot_multiple_gridded_datasets
    )
)

#' Selects and executes the appropriate plot variant
#'
#' Determines which plotting variant is applicable for the given datasets and
#' plotting options, then executes the first matching variant. Plot variants
#' are evaluated in order, and the first whose condition evaluates to `TRUE`
#' is used to generate the plot.
#'
#' @param datasets A `list` of data frames, each representing a dataset to be
#' visualised.
#' @param obj An instance of class `lcmsPlotClass`.
#' @return A `patchwork` plot object generated by the selected plot variant.
#' @keywords internal
run_matching_plot_variant <- function(datasets, obj) {
    if (length(datasets) == 0) {
        warning("No data to plot: all requested datasets are empty.")
        return(
            patchwork::wrap_plots(
                ggplot() +
                    annotate(
                        "text", x = 0.5, y = 0.5,
                        label = "No data to display",
                        size = 5, color = "grey40"
                    ) +
                    theme_void()
            )
        )
    }

    # When isolation_window is active, use the annotated spectrum renderer
    spectra_fn <- if (isTRUE(obj@options$isolation_window$show)) {
        plot_isolation_window
    } else {
        plot_spectrum
    }

    plot_config <- list(
        chromatograms = plot_chromatogram,
        mass_traces = plot_mass_trace,
        spectra = spectra_fn,
        peak_density = plot_peak_density,
        total_ion_current = plot_total_ion_current,
        intensity_maps = plot_intensity_map,
        rt_diff = plot_rt_diff,
        purity_timeline = plot_purity_timeline,
        purity_distribution = plot_purity_distribution
    )

    for (variant in plot_variants) {
        if (variant$condition(datasets, obj@options)) {
            return(variant$variant(datasets, obj, plot_config))
        }
    }

    stop("No plot variant applicable")
}

#' Plot the specified LC-MS data
#'
#' @param datasets A `list` of data frames, each representing a dataset to be
#' visualised.
#' @param obj An instance of class `lcmsPlotClass`.
#' @param obj The lcmsPlot object.
#' @return A `patchwork` plot object representing the final plot.
#' @keywords internal
plot_data <- function(datasets, obj) {
    result_plot <- run_matching_plot_variant(datasets, obj)

    result_plot <- result_plot +
        patchwork::plot_annotation(title = obj@options$labels$title) +
        patchwork::plot_layout(axes = "collect", guides = "collect") &
        theme(legend.position = obj@options$legend$position)

    return(result_plot)
}
