test_that("bs4 base colors", {
  varnames <- c(
    "black",
    "white",
    paste0("gray-", 1:9 * 100),
    "body-bg",
    "body-color",
    "primary",
    "secondary"
  )

  theme <- bs_theme(
    4,
    bg = "white",
    fg = "black",
    primary = "blue",
    secondary = "silver"
  )
  colors <- bs_get_variables(theme, varnames)

  expect_identical(
    colors,
    c(
      black = "#000000",
      white = "#FFFFFF",
      `gray-100` = "#E6E6E6",
      `gray-200` = "#CCCCCC",
      `gray-300` = "#B2B2B2",
      `gray-400` = "#999999",
      `gray-500` = "#808080",
      `gray-600` = "#666666",
      `gray-700` = "#4D4D4D",
      `gray-800` = "#333333",
      `gray-900` = "#191919",
      `body-bg` = "#FFFFFF",
      `body-color` = "#191919",
      primary = "#0000FF",
      secondary = "#C0C0C0"
    )
  )

  theme <- bs_theme(
    "4",
    bg = "#112233",
    fg = "#FFEEDD",
    primary = "orange",
    secondary = "brown"
  )
  colors <- bs_get_variables(theme, varnames)

  expect_identical(
    colors,
    c(
      black = "#FFEEDD",
      white = "#112233",
      `gray-100` = "#293644",
      `gray-200` = "#414B55",
      `gray-300` = "#585F66",
      `gray-400` = "#707477",
      `gray-500` = "#888888",
      `gray-600` = "#A09C99",
      `gray-700` = "#B8B1AA",
      `gray-800` = "#CFC5BB",
      `gray-900` = "#E7DACC",
      `body-bg` = "#112233",
      `body-color` = "#E7DACC",
      primary = "#FFA500",
      secondary = "#A52A2A"
    )
  )

  # Can individual colors still be overridden?
  theme <- bs_add_variables(theme, "body-bg" = "white", black = "red")
  expect_identical(
    bs_get_variables(theme, c("body-bg", "black")),
    c("body-bg" = "white", black = "red")
  )
})

test_that("bs3 base colors", {
  varnames <- c(
    "gray-base",
    "white",
    paste0("gray", c("-darker", "-dark", "", "-light", "-lighter")),
    "body-bg",
    "text-color",
    "brand-primary"
  )

  theme <- bs_theme("3", bg = "white", fg = "black", primary = "blue")
  colors <- bs_get_variables(theme, varnames)

  expect_identical(
    colors,
    c(
      `gray-base` = "#000000",
      white = "#FFFFFF",
      `gray-darker` = "#222222",
      `gray-dark` = "#333333",
      gray = "#555555",
      `gray-light` = "#777777",
      `gray-lighter` = "#EEEEEE",
      `body-bg` = "#FFFFFF",
      `text-color` = "#333333",
      `brand-primary` = "#0000FF"
    )
  )

  expect_warning(
    theme <- bs_theme(
      "3",
      bg = "#112233",
      fg = "#FFEEDD",
      primary = "orange",
      secondary = "brown"
    ),
    "doesn't support.*ignored"
  )
  colors <- bs_get_variables(theme, varnames)

  expect_identical(
    colors,
    c(
      `gray-base` = "#FFEEDD",
      white = "#112233",
      `gray-darker` = "#DFD3C6",
      `gray-dark` = "#CFC5BB",
      gray = "#B0AAA4",
      `gray-light` = "#908F8E",
      `gray-lighter` = "#21303E",
      `body-bg` = "#112233",
      `text-color` = "#CFC5BB",
      `brand-primary` = "#FFA500"
    )
  )

  # Can individual colors still be overridden?
  theme <- bs_add_variables(theme, "body-bg" = "black")
  expect_identical(
    bs_get_variables(theme, c("body-bg", "gray-darker")),
    c("body-bg" = "black", "gray-darker" = "#DFD3C6")
  )
})

test_that("bs4 accent colors", {
  varnames <- c("primary", "secondary", "success", "info", "warning", "danger")

  # Baseline
  theme <- bs_theme(4)
  expect_identical(
    bs_get_variables(theme, varnames),
    c(
      primary = "#007bff",
      secondary = "#6c757d",
      success = "#28a745",
      info = "#17a2b8",
      warning = "#ffc107",
      danger = "#dc3545"
    )
  )

  theme <- bs_theme(
    4,
    primary = "#123",
    secondary = "#234",
    success = "#345",
    info = "#456",
    warning = "#567",
    danger = "#678"
  )
  expect_identical(
    bs_get_variables(theme, varnames),
    c(
      primary = "#112233",
      secondary = "#223344",
      success = "#334455",
      info = "#445566",
      warning = "#556677",
      danger = "#667788"
    )
  )

  theme <- bs_theme(
    4,
    primary = "#123",
    secondary = "#234",
    success = "#345",
    info = "#456",
    warning = "#567",
    danger = "#678"
  )
  expect_identical(
    bs_get_variables(theme, varnames),
    c(
      primary = "#112233",
      secondary = "#223344",
      success = "#334455",
      info = "#445566",
      warning = "#556677",
      danger = "#667788"
    )
  )
})

test_that("bs3 accent colors", {
  varnames <- c(
    "primary",
    "secondary",
    "default",
    "success",
    "info",
    "warning",
    "danger"
  )
  varnames <- paste0("brand-", varnames)

  # Baseline
  theme <- bs_theme("3")
  expect_identical(
    bs_get_variables(theme, varnames),
    c(
      `brand-primary` = "#337ab7",
      `brand-secondary` = NA,
      `brand-default` = NA,
      `brand-success` = "#5cb85c",
      `brand-info` = "#5bc0de",
      `brand-warning` = "#f0ad4e",
      `brand-danger` = "#d9534f"
    )
  )

  expect_warning(
    theme <- bs_theme(
      "3",
      primary = "#123",
      secondary = "#234",
      success = "#345",
      info = "#456",
      warning = "#567",
      danger = "#678"
    ),
    "doesn't support"
  )
  expect_identical(
    bs_get_variables(theme, varnames),
    c(
      `brand-primary` = "#112233",
      `brand-secondary` = NA,
      `brand-default` = NA,
      `brand-success` = "#334455",
      `brand-info` = "#445566",
      `brand-warning` = "#556677",
      `brand-danger` = "#667788"
    )
  )
})

test_that("bs_theme_fonts", {
  expected_result <- "\"Source Sans Pro\", \"Open Sans\", Helvetica, sans-serif"
  candidates <- list(
    # All separate
    c("Source Sans Pro", "Open Sans", "Helvetica", "sans-serif"),
    # All together
    c("'Source Sans Pro'", "Open Sans", "Helvetica, sans-serif"),
    # Mixed
    c("'Source Sans Pro', \"Open Sans\", Helvetica, sans-serif")
  )

  lapply(versions(), function(version) {
    for (candidate in candidates) {
      theme <- bs_theme(version, base_font = candidate)
      expect_identical(
        bs_get_variables(theme, "font-family-base"),
        c(`font-family-base` = expected_result)
      )
    }
    expect_error(bs_fonts(theme, ""))
    expect_error(bs_fonts(theme, code = NA_character_))
    expect_error(bs_fonts(theme, heading = TRUE))
    expect_error(bs_fonts(theme, 10L))

    # NOT an error
    expect_error(bs_fonts(theme, NULL), NA)

    theme <- bs_fonts(bs_theme(), base = "a", code = "b", heading = "c")
    expect_identical(
      bs_get_variables(
        theme,
        c("font-family-base", "font-family-monospace", "headings-font-family")
      ),
      c(
        `font-family-base` = "a",
        `font-family-monospace` = "b",
        `headings-font-family` = "c"
      )
    )
  })
})

test_that("format_varnames", {
  expect_identical(format_varnames("a"), "`a`")
  expect_identical(format_varnames(c("a", "b")), "`a`, `b`")
  expect_identical(
    format_varnames(c("foo bar", "baz qux"), quot = "'", delim = "/"),
    "'foo bar'/'baz qux'"
  )
})

test_that("validate_and_normalize_colors", {
  expect_null(validate_and_normalize_colors(NULL))

  # Bad
  expect_error(
    validate_and_normalize_colors(list(mycolor = "")),
    "Invalid.*mycolor"
  )
  expect_error(validate_and_normalize_colors(list(foo = "bar")), "Invalid")
  expect_error(
    validate_and_normalize_colors(
      list(valid = "black", notvalid1 = "#00", notvalid2 = "#11111")
    ),
    "Invalid.*notvalid.*notvalid2"
  )
  expect_error(
    validate_and_normalize_colors(list(toomany = c("red", "blue"))),
    "Invalid.*toomany"
  )

  expect_identical(
    validate_and_normalize_colors(
      list(a = "#000", b = "white", c = "rgb(16, 32, 64)")
    ),
    list(a = "#000000", b = "#FFFFFF", c = "#102040")
  )
})

test_that("bs_get_variables is fg/bg aware", {
  expect_equal(
    bs_get_variables(bs_theme(), c("bg", "fg")),
    c(bg = "#ffffff", fg = "#000")
  )
  expect_equal(
    bs_get_variables(bs_theme(version = 3), c("bg", "fg")),
    c(bg = "#fff", fg = "#000")
  )
  expect_equal(
    bs_get_variables(
      bs_theme(version = 4, bootswatch = "darkly"),
      c("bg", "fg")
    ),
    c(bg = "#222", fg = "#fff")
  )
  expect_equal(
    bs_get_variables(
      bs_theme(version = 3, bootswatch = "darkly"),
      c("bg", "fg")
    ),
    c(bg = "#222222", fg = "#fff")
  )
})

test_that("theme-color('default') works as expected", {
  # default theme color derives defaults from $gray-300
  css <- sass::sass_partial(
    ".foo{color:theme-color('default')}",
    bs_theme(version = 4)
  )
  expect_css(css, ".foo{color:#dee2e6;}")
  # but can be customized via secondary
  css <- sass::sass_partial(
    ".foo{color:theme-color('default')}",
    bs_theme(version = 4, secondary = "red")
  )
  expect_css(css, ".foo{color:#FF0000;}")
  expect_error(
    sass::sass(
      list(bs_theme(), ".foo { @extend .bg-default; }")
    ),
    NA
  )
})

test_that("bs_get_contrast() works as expected", {
  for (version in versions()) {
    base <- bs_theme(version)
    expect_equal(
      bs_get_contrast(base, "body-bg"),
      c("body-bg" = "#000000")
    )
    primary <- if ("3" %in% version) "brand-primary" else "primary"
    expect_equal(
      bs_get_contrast(base, c("body-bg", primary)),
      setNames(c("#000000", "#FFFFFF"), c("body-bg", primary))
    )
    inverted <- bs_theme_update(base, bg = "black", fg = "white")
    expect_equal(
      bs_get_contrast(inverted, "body-bg"),
      c("body-bg" = "#FFFFFF")
    )
    yb <- bs_theme(4, bg = "yellow", fg = "#0000FF")
    expect_equal(
      bs_get_contrast(yb, "input-bg"),
      c("input-bg" = "#0000FF")
    )
    yb <- bs_theme_update(
      yb,
      bg = "black",
      fg = "white",
      "color-contrast-light" = "#0000FF",
      "color-contrast-dark" = "yellow"
    )
    expect_equal(
      bs_get_contrast(yb, "input-bg"),
      c("input-bg" = "#FFFF00")
    )
    expect_error(
      bs_get_contrast(base, "font"),
      "Undefined variable"
    )
    expect_error(
      bs_get_contrast(base, "font-family-base"),
      "must be a color"
    )
    if ("3" %in% version) {
      next
    }
    light_success <- bs_theme_update(inverted, success = "#E5FFE5")
    expect_equal(
      bs_get_contrast(light_success, "success"),
      c("success" = "#000000")
    )
    expect_equal(
      bs_get_contrast(
        bs_theme_update(
          light_success,
          "color-contrast-light" = "#222",
          "min-contrast-ratio" = 1
        ),
        "success"
      ),
      c("success" = "#222222")
    )
    dark_success <- bs_theme_update(inverted, success = "#193319")
    expect_equal(
      bs_get_contrast(dark_success, "success"),
      c("success" = "#FFFFFF")
    )
    expect_equal(
      bs_get_contrast(
        bs_theme_update(dark_success, "color-contrast-light" = "#F8F9FA"),
        "success"
      ),
      c("success" = "#F8F9FA")
    )
  }
})
