# Publication-ready theming and palettes for diffHTS figures -------------------

# Okabe-Ito colourblind-safe qualitative palette (8 hues).
.hts_okabe_ito <- c(
  blue = "#0072B2", vermillion = "#D55E00", green = "#009E73",
  purple = "#CC79A7", orange = "#E69F00", skyblue = "#56B4E9",
  yellow = "#F0E442", grey = "#999999"
)

# Semantic colours shared across diffHTS plots: low-saturation and
# colourblind-safe, never pure primaries or rainbow.
.hts_semantic <- c(
  pass = "#0072B2", fail = "#D55E00",
  NC = "#0072B2", PC = "#D55E00", compound = "#3C3C3C", Blank = "#E1B000",
  hit = "#D55E00", nonhit = "#B4B4B4",
  Weak = "#B4B4B4", Moderate = "#E69F00", Strong = "#D55E00",
  accent = "#0072B2", reference = "#666666", neutral = "#4C72B0"
)

# Look up one or more semantic colours by name.
.hts_col <- function(...) {
  keys <- c(...)
  unname(.hts_semantic[keys])
}

# Compact numeric labels for direct on-plot annotation.
.fmt_qc <- function(x) {
  x <- .as_numeric(x)
  out <- ifelse(abs(x) >= 100, formatC(x, format = "d"),
    formatC(signif(x, 3), format = "g"))
  out[!is.finite(x)] <- ""
  out
}

#' Colourblind-safe qualitative palette for diffHTS
#'
#' Returns the package's low-saturation, colourblind-safe qualitative palette
#' (an Okabe-Ito ordering). Use it whenever a plot maps a discrete variable to
#' colour so that figures stay consistent and accessible.
#'
#' @param n Number of colours to return (recycled if `n` exceeds the eight
#'   base hues). If `NULL` (default) the full palette is returned.
#'
#' @return A character vector of hex colours.
#'
#' @examples
#' hts_pal(3)
#'
#' @seealso [theme_hts()]
#' @export
hts_pal <- function(n = NULL) {
  pal <- unname(.hts_okabe_ito)
  if (is.null(n)) {
    return(pal)
  }
  rep(pal, length.out = n)
}

#' Modern academic ggplot2 theme for diffHTS figures
#'
#' A minimal, publication-ready theme: pure-white background, an L-shaped axis
#' (left and bottom only), light dashed horizontal major grid lines with no
#' minor grid, restrained dark-grey typography and generous margins. Pair it
#' with [hts_pal()] for discrete colours or a `viridis`/muted-blue gradient for
#' continuous ones.
#'
#' @param base_size Base font size in points. Default `12`.
#' @param base_family Base font family; defaults to the device sans-serif.
#' @param legend Legend position passed to `ggplot2::theme()`. Default
#'   `"bottom"`.
#' @param grid Which major grid lines to keep: `"y"` (default), `"x"`, `"both"`
#'   or `"none"`.
#'
#' @return A [ggplot2::theme] object that can be added to any ggplot.
#'
#' @examples
#' library(ggplot2)
#' ggplot(mtcars, aes(factor(cyl), mpg)) +
#'   geom_boxplot() +
#'   theme_hts()
#'
#' @seealso [hts_pal()], [plot_plate_qc()]
#' @export
theme_hts <- function(base_size = 12, base_family = "", legend = "bottom",
                      grid = c("y", "x", "both", "none")) {
  grid <- match.arg(grid)
  half <- base_size / 2
  grid_line <- ggplot2::element_line(color = "#E5E5E5", linewidth = 0.3,
    linetype = "dashed")
  th <- ggplot2::theme_minimal(base_size = base_size,
    base_family = base_family) +
    ggplot2::theme(
      text = ggplot2::element_text(color = "#333333", lineheight = 1.2),
      plot.background = ggplot2::element_rect(fill = "#FFFFFF", color = NA),
      panel.background = ggplot2::element_rect(fill = "#FFFFFF", color = NA),
      panel.grid.major = ggplot2::element_blank(),
      panel.grid.minor = ggplot2::element_blank(),
      axis.line = ggplot2::element_line(color = "#888888", linewidth = 0.6,
        lineend = "round"),
      axis.ticks = ggplot2::element_line(color = "#888888", linewidth = 0.4),
      plot.title = ggplot2::element_text(size = ggplot2::rel(1.25),
        face = "bold", color = "#222222",
        margin = ggplot2::margin(b = half)),
      plot.subtitle = ggplot2::element_text(size = ggplot2::rel(1),
        color = "#555555", margin = ggplot2::margin(b = half)),
      plot.caption = ggplot2::element_text(size = ggplot2::rel(0.8),
        color = "#777777"),
      axis.title = ggplot2::element_text(size = ggplot2::rel(1.02),
        color = "#333333"),
      axis.title.x = ggplot2::element_text(margin = ggplot2::margin(t = half)),
      axis.title.y = ggplot2::element_text(margin = ggplot2::margin(r = half)),
      axis.text = ggplot2::element_text(size = ggplot2::rel(0.88),
        color = "#555555"),
      legend.position = legend,
      legend.title = ggplot2::element_text(size = ggplot2::rel(0.88),
        color = "#333333"),
      legend.text = ggplot2::element_text(size = ggplot2::rel(0.88),
        color = "#555555"),
      legend.key = ggplot2::element_blank(),
      legend.background = ggplot2::element_blank(),
      plot.margin = ggplot2::margin(16, 16, 16, 16)
    )
  if (grid %in% c("y", "both")) {
    th <- th + ggplot2::theme(panel.grid.major.y = grid_line)
  }
  if (grid %in% c("x", "both")) {
    th <- th + ggplot2::theme(panel.grid.major.x = grid_line)
  }
  th
}
