#' @export
#' @title Set 'Microsoft Word' Document Settings
#' @description
#' Set various settings of a 'Microsoft Word' document generated with 'officer'.
#' Options include:
#' - zoom factor (default view in Word),
#' - default tab stop,
#' - hyphenation zone,
#' - decimal symbol,
#' - list separator (see details below),
#' - compatibility mode,
#' - even and odd headers management (see details below),
#' - and auto hyphenation activation.
#'
#' @details
#' - `even_and_odd_headers`: If TRUE, 'Microsoft Word' will use different
#' headers for odd and even pages ("Different Odd & Even Pages" feature in Word).
#' This is useful for professional documents or reports that require alternating
#' page layouts.
#'
#' - `list_separator`: Sets the character used by 'Microsoft Word' to separate
#' items in lists (for example, when inserting tables or lists in Word). This
#' parameter affects how 'Microsoft Word' handles data import/export (CSV, etc.) and can be
#' adapted to language or local conventions (e.g., ";" for French, "," for English).
#'
#' @seealso [read_docx()]
#' @param x an rdocx object
#' @param zoom zoom factor, default is 1 (100%)
#' @param default_tab_stop default tab stop in inches, default is 0.5
#' @param hyphenation_zone hyphenation zone in inches, default is 0.25
#' @param decimal_symbol decimal symbol, default is "."
#' @param list_separator list separator, default is ";". Sets the separator
#' used by Word for lists (see details).
#' @param compatibility_mode compatibility mode, default is "15"
#' @param even_and_odd_headers whether to use different headers for even and
#' odd pages, default is FALSE. Enables the "Different Odd and Even Pages"
#' feature in 'Microsoft Word'.
#' @param auto_hyphenation whether to enable auto hyphenation, default is FALSE.
#' @param unit unit for `default_tab_stop` and `hyphenation_zone`, one of "in", "cm", "mm".
#' @example inst/examples/example_docx_set_settings.R
docx_set_settings <- function(
  x,
  zoom = 1,
  default_tab_stop = 0.5,
  hyphenation_zone = 0.25,
  decimal_symbol = ".",
  list_separator = ";",
  compatibility_mode = "15",
  even_and_odd_headers = FALSE,
  auto_hyphenation = FALSE,
  unit = "in"
) {
  settings <- docx_settings(
    zoom = zoom,
    default_tab_stop = convin(unit = unit, x = default_tab_stop),
    hyphenation_zone = convin(unit = unit, x = hyphenation_zone),
    decimal_symbol = decimal_symbol,
    list_separator = list_separator,
    even_and_odd_headers = even_and_odd_headers,
    auto_hyphenation = auto_hyphenation,
    compatibility_mode = compatibility_mode
  )
  x$settings <- settings
  x
}

docx_settings <- function(
  zoom = 1,
  default_tab_stop = 0.5,
  hyphenation_zone = 0.25,
  decimal_symbol = ".",
  list_separator = ";",
  compatibility_mode = "15",
  even_and_odd_headers = FALSE,
  auto_hyphenation = FALSE
) {
  x <- list(
    zoom = zoom,
    default_tab_stop = default_tab_stop,
    hyphenation_zone = hyphenation_zone,
    decimal_symbol = decimal_symbol,
    list_separator = list_separator,
    even_and_odd_headers = even_and_odd_headers,
    auto_hyphenation = auto_hyphenation,
    compatibility_mode = compatibility_mode
  )
  class(x) <- "docx_settings"
  x
}

update_docx_settings_from_file <- function(x, file) {
  if (is.null(file)) {
    cli::cli_abort(
      "File settings for Word document is null."
    )
  }
  if (!file.exists(file)) {
    cli::cli_abort(
      "File settings for Word document does not exists {.file {file}}."
    )
  }

  node_doc <- read_xml(file)

  node_zoom <- xml_child(node_doc, "w:zoom")
  if (!inherits(node_zoom, "xml_missing")) {
    x$zoom <- as.integer(xml_attr(node_zoom, "percent")) / 100
  }

  node_tab_stop <- xml_child(node_doc, "w:defaultTabStop")
  if (!inherits(node_tab_stop, "xml_missing")) {
    x$default_tab_stop <- as.integer(xml_attr(node_tab_stop, "val")) /
      1440
  }

  node_hyphenation_zone <- xml_child(node_doc, "w:hyphenationZone")
  if (!inherits(node_hyphenation_zone, "xml_missing")) {
    x$hyphenation_zone <- as.integer(xml_attr(
      node_hyphenation_zone,
      "val"
    )) /
      1440
  }

  node_auto_hyphenation <- xml_child(node_doc, "w:autoHyphenation")
  if (!inherits(node_auto_hyphenation, "xml_missing")) {
    x$auto_hyphenation <- TRUE
  }

  node_decimal_symbol <- xml_child(node_doc, "w:decimalSymbol")
  if (!inherits(node_decimal_symbol, "xml_missing")) {
    x$decimal_symbol <- xml_attr(node_decimal_symbol, "val")
  }

  node_list_separator <- xml_child(node_doc, "w:listSeparator")
  if (!inherits(node_list_separator, "xml_missing")) {
    x$list_separator <- xml_attr(node_list_separator, "val")
  }

  node_evenodd_headers <- xml_child(node_doc, "w:evenAndOddHeaders")
  if (!inherits(node_evenodd_headers, "xml_missing")) {
    x$even_and_odd_headers <- TRUE
  } else {
    x$even_and_odd_headers <- FALSE
  }

  x
}

write_docx_settings <- function(x) {
  settings <- x$settings
  file <- file.path(x$package_dir, "word", "settings.xml")
  doc <- read_xml(file)
  ns <- "http://schemas.openxmlformats.org/wordprocessingml/2006/main"

  upsert_simple <- function(doc, tag, attr, value) {
    node <- xml_child(doc, tag)
    new_xml <- sprintf(
      "<%s xmlns:w=\"%s\" w:%s=\"%s\"/>",
      tag,
      ns,
      attr,
      value
    )
    if (inherits(node, "xml_missing")) {
      xml_add_child(doc, read_xml(new_xml))
    } else {
      xml_replace(node, read_xml(new_xml))
    }
  }

  upsert_simple(
    doc,
    "w:zoom",
    "percent",
    sprintf("%.0f", settings$zoom * 100)
  )
  upsert_simple(
    doc,
    "w:defaultTabStop",
    "val",
    sprintf("%.0f", settings$default_tab_stop * 1440)
  )
  upsert_simple(
    doc,
    "w:hyphenationZone",
    "val",
    sprintf("%.0f", settings$hyphenation_zone * 1440)
  )
  upsert_simple(doc, "w:decimalSymbol", "val", settings$decimal_symbol)
  upsert_simple(doc, "w:listSeparator", "val", settings$list_separator)

  # autoHyphenation: add if TRUE, remove if FALSE
  node <- xml_child(doc, "w:autoHyphenation")
  if (settings$auto_hyphenation && inherits(node, "xml_missing")) {
    new_xml <- sprintf(
      "<w:autoHyphenation xmlns:w=\"%s\"/>",
      ns
    )
    xml_add_child(doc, read_xml(new_xml))
  } else if (!settings$auto_hyphenation && !inherits(node, "xml_missing")) {
    xml_remove(node)
  }

  # evenAndOddHeaders
  eoh_val <- if (settings$even_and_odd_headers) "1" else "0"
  upsert_simple(doc, "w:evenAndOddHeaders", "val", eoh_val)

  # compat / compatSetting
  compat_node <- xml_child(doc, "w:compat")
  compat_xml <- sprintf(
    paste0(
      "<w:compat xmlns:w=\"%s\">",
      "<w:compatSetting w:name=\"compatibilityMode\"",
      " w:uri=\"http://schemas.microsoft.com/office/word\"",
      " w:val=\"%s\"/></w:compat>"
    ),
    ns,
    settings$compatibility_mode
  )
  if (inherits(compat_node, "xml_missing")) {
    xml_add_child(doc, read_xml(compat_xml))
  } else {
    xml_replace(compat_node, read_xml(compat_xml))
  }

  # embedTrueTypeFonts: add if TRUE, leave existing if not set
  if (isTRUE(settings$embed_true_type_fonts)) {
    node <- xml_child(doc, "w:embedTrueTypeFonts")
    if (inherits(node, "xml_missing")) {
      new_xml <- sprintf(
        "<w:embedTrueTypeFonts xmlns:w=\"%s\"/>",
        ns
      )
      xml_add_child(doc, read_xml(new_xml))
    }
  }

  write_xml(doc, file)
  TRUE
}
