#' @title Show a workflow graph as text in your terminal window.
#' `r lifecycle::badge("stable")`
#' @description This is a low-tech version of [vis_drake_graph()]
#'   and friends. It is designed for when you do not have access
#'   to the usual graphics devices for viewing visuals in an interactive
#'   R session: for example, if you are logged into a remote machine
#'   with SSH and you do not have access to X Window support.
#' @export
#' @seealso [render_text_drake_graph()], [vis_drake_graph()],
#'   [sankey_drake_graph()], [drake_ggraph()]
#' @return A `visNetwork` graph.
#' @inheritParams drake_graph_info
#' @inheritParams render_text_drake_graph
#' @examples
#' \dontrun{
#' isolate_example("Quarantine side effects.", {
#' if (suppressWarnings(require("knitr"))) {
#' load_mtcars_example() # Get the code with drake_example("mtcars").
#' # Plot the network graph representation of the workflow.
#' pkg <- requireNamespace("txtplot", quietly = TRUE) &&
#'   requireNamespace("visNetwork", quietly = TRUE)
#' if (pkg) {
#' text_drake_graph(my_plan)
#' make(my_plan) # Run the project, build the targets.
#' text_drake_graph(my_plan) # The black nodes from before are now green.
#' }
#' }
#' })
#' }
text_drake_graph <- function(
  ...,
  from = NULL,
  mode = c("out", "in", "all"),
  order = NULL,
  subset = NULL,
  targets_only = FALSE,
  make_imports = TRUE,
  from_scratch = FALSE,
  group = NULL,
  clusters = NULL,
  show_output_files = TRUE,
  nchar = 1L,
  print = TRUE,
  config = NULL
) {
}

#' @title Internal function with a drake_config() argument
#' @export
#' @keywords internal
#' @description Not a user-side function.
#' @inheritParams outdated
#' @param config A [drake_config()] object.
text_drake_graph_impl <- function(
  config,
  from = NULL,
  mode = c("out", "in", "all"),
  order = NULL,
  subset = NULL,
  targets_only = FALSE,
  make_imports = TRUE,
  from_scratch = FALSE,
  group = NULL,
  clusters = NULL,
  show_output_files = TRUE,
  nchar = 1L,
  print = TRUE
) {
  assert_pkg("visNetwork")
  graph_info <- drake_graph_info_impl(
    config = config,
    from = from,
    mode = mode,
    order = order,
    subset = subset,
    build_times = "none",
    digits = 0,
    targets_only = targets_only,
    font_size = 20,
    make_imports = make_imports,
    from_scratch = from_scratch,
    full_legend = FALSE,
    group = group,
    clusters = clusters,
    show_output_files = show_output_files,
    hover = FALSE
  )
  render_text_drake_graph(
    graph_info = graph_info,
    nchar = nchar,
    print = print
  )
}

body(text_drake_graph) <- config_util_body(text_drake_graph_impl)

#' @title Show a workflow graph as text in your terminal window
#'   using [drake_graph_info()] output.
#' `r lifecycle::badge("stable")`
#' @description This function is called inside
#' [text_drake_graph()], which typical users
#' call more often. See `?text_drake_graph` for details.
#' @export
#' @seealso [text_drake_graph()], [vis_drake_graph()],
#'   [sankey_drake_graph()], [drake_ggraph()]
#' @return The lines of text in the visualization.
#'
#' @param graph_info List of data frames generated by
#'   [drake_graph_info()].
#'   There should be 3 data frames: `nodes`, `edges`,
#'   and `legend_nodes`.
#'
#' @param nchar For each node, maximum number of characters of the node label
#'   to show. Can be 0, in which case each node is a colored box
#'   instead of a node label.
#'   Caution: `nchar` > 0 will mess with the layout.
#'
#' @param print Logical. If `TRUE`, the graph will print to the console
#'   via `message()`. If `FALSE`, nothing is printed. However, you still
#'   have the visualization because `text_drake_graph()` and
#'   `render_text_drake_graph()` still invisibly return a character string
#'   that you can print yourself with `message()`.
#'
#' @examples
#' \dontrun{
#' isolate_example("Quarantine side effects.", {
#' if (suppressWarnings(require("knitr"))) {
#' load_mtcars_example() # Get the code with drake_example("mtcars").
#' pkgs <- requireNamespace("txtplot", quietly = TRUE) &&
#'   requireNamespace("visNetwork", quietly = TRUE)
#' if (pkgs) {
#' # Instead of jumpting right to vis_drake_graph(), get the data frames
#' # of nodes, edges, and legend nodes.
#' text_drake_graph(my_plan) # Jump straight to the interactive graph.
#' # Get the node and edge info that vis_drake_graph() just plotted:
#' graph <- drake_graph_info(my_plan)
#' # You can pass the data frames right to render_text_drake_graph().
#' render_text_drake_graph(graph)
#' }
#' }
#' })
#' }
render_text_drake_graph <- function(graph_info, nchar = 1L, print = TRUE) {
  assert_pkg("txtplot")
  pch <- apply(
    X = graph_info$nodes,
    MARGIN = 1,
    FUN = function(node) {
      id <- redisplay_keys(node["id"])
      id <- substr(x = id, start = 0L, stop = nchar)
      id <- ifelse(nchar > 0, id, " ")
      if (requireNamespace("crayon", quietly = TRUE)) {
        cl <- gsub("000000", "666666", node["color"])
        id <- crayon::make_style(cl, bg = nchar < 1L)(id)
      }
      id
    }
  )
  x <- graph_info$nodes$x
  y <- graph_info$nodes$y
  txt <- utils::capture.output(
    txtplot::txtplot(x = x, y = y, pch = pch)
  )
  txt <- txt[-c(1L, length(txt) - 1L, length(txt))]
  txt <- gsub("\\+|\\|", "|", txt)
  txt <- gsub("^[^\\|]*\\|", "", txt)
  txt <- gsub("\\|", "", txt)
  txt <- paste(txt, collapse = "\n")
  if (print) {
    message(txt)
  }
  invisible(txt)
}
