// Dims a color (either making it more white or more black)
@function theme-dim($baseColor, $amount) {
  @if (tone($baseColor) == "dark") {
    @return lighten($baseColor, $amount);
  } @else {
    @return darken($baseColor, $amount);
  }
}

// Provides a contrast color for a given color
// The color is the starting color that will used to form a contrasting color
// The bgColor is the color that will be used to test contrast (e.g. the color
// will be shifted until its contrast against the bgColor is acceptable)
@function theme-contrast($color, $bgColor, $level: "AAA") {
  // These will be defined in bootstrap, but creating values here
  // That will make this function accessible to callers prior to bootstrap variables
  // being set
  $black: rgb(0, 0, 0) !default;
  $white: rgb(255, 255, 255) !default;

  @if tone($bgColor) == "light" {
    @return accessibleContrast($color, $black, $bgColor, $level);
  } @else {
    @return accessibleContrast($color, $white, $bgColor, $level);
  }
}

@function accessibleContrast($startColor, $mixColor, $bgColor, $level: "AAA") {
  // A: 3:1
  // AA: 4.5:1
  // AAA: 7:1
  $goalContrastRatio: 3;
  @if $level == "AA" {
    $goalContrastRatio: 4.5;
  } @else {
    $goalContrastRatio: 7;
  }

  $percentMix: 100;
  $contrastRatio: 0;
  $contrastColor: null;
  @while ($contrastRatio < $goalContrastRatio and $percentMix > 0) {
    $contrastColor: mix(
      $startColor,
      $mixColor,
      percentage(quarto-math.div($percentMix, 100))
    );
    $contrastRatio: contrast($contrastColor, $bgColor);
    $percentMix: $percentMix - 1;
  }

  @return $contrastColor;
}

// Fades a color towards the background color
@function theme-fade($baseColor, $backgroundColor, $amount) {
  @if (tone($backgroundColor) == "dark") {
    @return darken($baseColor, $amount);
  } @else {
    @return lighten($baseColor, $amount);
  }
}

@function theme-highlight($baseColor, $backgroundColor, $amount) {
  @if (tone($backgroundColor) == "dark") {
    @return lighten($baseColor, $amount);
  } @else {
    @return darken($baseColor, $amount);
  }
}

@function theme-override-value($theme, $varname, $default) {
  // These will be defined in bootstrap, but creating values here
  // That will make this function accessible to callers prior to bootstrap variables
  // being set
  $black: rgb(0, 0, 0) !default;
  $white: rgb(255, 255, 255) !default;
  $gray-500: #adb5bd !default;
  $gray-300: #dee2e6 !default;
  $blue: #0d6efd !default;

  $simplex-border-mix: mix($white, $black, 93.5%) !default;

  $theme-overrides: (
    cerulean: (
      navbar-fg: $white,
      valuebox-bg-primary: #2fa4e7,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #67a34d,
      valuebox-bg-warning: #aa9208,
      valuebox-bg-danger: #c48282,
    ),
    cosmo: (
      navbar-bg:
        if(
          $default == #2780e3,
          if(variable-exists(light), $light, $gray-500),
          $default
        ),
      link-color: #2761e3,
      valuebox-bg-primary: #5397e9,
      valuebox-bg-info: #9954bbb3,
      valuebox-bg-success: #3aa716,
      valuebox-bg-warning: #fa6400,
      valuebox-bg-danger: #ff0039b3,
    ),
    cyborg: (
      navbar-bg:
        if(
          $default == #2a9fd6,
          if(variable-exists(secondary), $secondary, $black),
          $default
        ),
      navbar-hl: $white,
    ),
    darkly: (
      navbar-fg: $gray-300,
      navbar-hl: $white,
      input-border-color: $gray-500,
    ),
    flatly: (
      navbar-hl: $white,
      valuebox-bg-primary: rgba(39, 128, 227, 0.7),
      valuebox-bg-info: rgba(153, 84, 187, 0.7),
      valuebox-bg-success: rgba(63, 182, 24, 0.7),
      valuebox-bg-warning: rgba(255, 117, 24, 0.7),
      valuebox-bg-danger: rgba(255, 0, 57, 0.7),
    ),
    journal: (
      navbar-fg: rgba($white, 0.7),
      navbar-hl: $white,
      valuebox-bg-primary: #f0938f,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #65a244,
      valuebox-bg-warning: #ad9310,
      valuebox-bg-danger: #c77f7f,
    ),
    litera: (
      navbar-bg: if($default == #4582ec, $white, $default),
    ),
    lumen: (
      navbar-fg: rgba($white, 0.7),
      navbar-hl: $white,
      valuebox-bg-primary: #67abcc,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #5ea343,
      valuebox-bg-warning: #a79011,
      valuebox-bg-danger: #ca8181,
    ),
    lux: (),
    materia: (
      navbar-fg: rgba($white, 0.7),
      navbar-hl: $white,
    ),
    minty: (
      navbar-fg: $white,
    ),
    morph: (
      navbar-bg:
        if(
          $default == #378dfc,
          if(variable-exists(body-bg), $body-bg, $black),
          $default
        ),
      navbar-fg: rgba($black, 0.5),
    ),
    paper: (
      valuebox-bg-primary: #4396ea,
      valuebox-bg-info: #c277cf,
      valuebox-bg-success: #59a343,
      valuebox-bg-warning: #d68100,
      valuebox-bg-danger: #f46762,
    ),
    pulse: (
      navbar-fg: rgba($white, 0.7),
      navbar-hl: $white,
    ),
    quartz: (
      navbar-fg: rgba($white, 0.8),
      navbar-hl: $white,
    ),
    sandstone: (
      navbar-bg:
        if(
          $default == #325d88,
          if(variable-exists(dark), $dark, $black),
          $default
        ),
      navbar-fg: rgba($white, 0.7),
      navbar-hl: $white,
      valuebox-bg-primary: #7b98ad,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #60a545,
      valuebox-bg-warning: #af8e08,
      valuebox-bg-danger: #ca8181,
    ),
    simplex: (
      navbar-bg: if($default == #d9230f, $white, $default),
      navbar-fg: rgba($black, 0.6),
      navbar-hl: $black,
      nav-tabs-link-active-border-color: $simplex-border-mix $simplex-border-mix
        transparent,
      valuebox-bg-primary: #db766b,
      valuebox-bg-info: #359ed0,
      valuebox-bg-success: #59a343,
      valuebox-bg-warning: #a59212,
      valuebox-bg-danger: #c48282,
    ),
    sketchy: (
      navbar-fg: $white,
    ),
    slate: (),
    solar: (
      navbar-bg:
        if(
          $default == #b58900,
          if(variable-exists(dark), $dark, $black),
          $default
        ),
      navbar-hl: $white,
    ),
    spacelab: (
      navbar-bg:
        if(
          $default == #446e9b,
          if(variable-exists(light), $light, #bbb),
          $default
        ),
      navbar-hl: if(variable-exists(link-color), $link-color, $blue),
      valuebox-bg-primary: #7e97ae,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #62a540,
      valuebox-bg-warning: #a59212,
      valuebox-bg-danger: #c97e7e,
    ),
    superhero: (
      navbar-bg:
        if(
          $default == #df6919,
          if(variable-exists(dark), $dark, $black),
          $default
        ),
      navbar-hl: $white,
    ),
    united: (
      navbar-fg: rgba($white, 0.8),
      navbar-hl: $white,
      valuebox-bg-primary: #5c9bbc,
      valuebox-bg-info: #3d9dd1,
      valuebox-bg-success: #60a545,
      valuebox-bg-warning: #9a9623,
      valuebox-bg-danger: #c48282,
    ),
    vapor: (
      navbar-fg: rgba($white, 0.8),
      navbar-hl: $white,
    ),
    yeti: (),
    zephyr: (),
  );

  $val: null;
  @if ($theme != null) {
    $theme-vals: quarto-map.get($theme-overrides, $theme);
    @if ($theme-vals != null) {
      $val: quarto-map.get($theme-vals, $varname);
    }
  }

  @if ($val != null) {
    @return $val;
  } @else {
    @return $default;
  }
}

@function theme-navbar-bg($theme, $primary) {
  $white: rgb(255, 255, 255) !default;

  // These will be defined in bootstrap, but creating values here
  // That will make this function accessible to callers prior to bootstrap variables
  // being set
  $theme-bgs: (
    litera: $white,
    cyborg: if(variable-exists(body-bg), $body-bg, #000),
  );

  $bg: quarto-map.get($theme-bgs, $theme);
  @if ($bg != null) {
    @return $bg;
  } @else {
    @return if(variable-exists(primary), $primary, #fff);
  }
}

@function theme-navbar-fg($theme, $primary) {
  $white: rgb(255, 255, 255) !default;

  // These will be defined in bootstrap, but creating values here
  // That will make this function accessible to callers prior to bootstrap variables
  // being set
  $theme-fgs: (
    cerulean: $white,
  );

  $bg: quarto-map.get($theme-bgs, $theme);
  @if ($bg != null) {
    @return $bg;
  } @else {
    @return if(variable-exists(primary), $primary, #fff);
  }
}

@function repeat-chars($chars, $n) {
  $final: "";
  @for $i from 1 through $n {
    $final: $final + $chars;
  }
  @return $final;
}

@function _linear-channel-value($channel-value) {
  $normalized-channel-value: quarto-math.div($channel-value, 255);
  @if $normalized-channel-value < 0.03928 {
    @return quarto-math.div($normalized-channel-value, 12.92);
  }

  @return quarto-math.pow(
    quarto-math.div(($normalized-channel-value + 0.055), 1.055),
    2.4
  );
}

// Calculate the luminance for a color.
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
@function luminance($color) {
  $red: _linear-channel-value(quarto-color.red($color));
  $green: _linear-channel-value(quarto-color.green($color));
  $blue: _linear-channel-value(quarto-color.blue($color));

  @return 0.2126 * $red + 0.7152 * $green + 0.0722 * $blue;
}

// Calculate the contrast ratio between two colors.
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
@function contrast($back, $front) {
  $backLum: luminance($back) + 0.05;
  $foreLum: luminance($front) + 0.05;

  @return quarto-math.div(
    quarto-math.max($backLum, $foreLum),
    quarto-math.min($backLum, $foreLum)
  );
}

// Determine whether the color is 'light' or 'dark'.
@function tone($color) {
  @if $color == "dark" or $color == "light" {
    @return $color;
  }

  $minimumContrast: 3.1;

  $lightContrast: contrast($color, white);
  $darkContrast: contrast($color, rgba(black, 0.87));

  @if ($lightContrast < $minimumContrast) and ($darkContrast > $lightContrast) {
    @return "light";
  } @else {
    @return "dark";
  }
}

// Determine whether to use dark or light text on top of given color to meet accessibility standards for contrast.
// Returns 'dark' if the given color is light and 'light' if the given color is dark.
@function contrast-tone($color) {
  @return if(tone($color) == "dark", "light", "dark");
}
