////
/// @group color
////

@use "sass:map";
@use "sass:meta";
@use "sass:string";
@use "sass:color";

@use "utils";
@use "selector";

/// The color palette map, can be extended or modified with set() and accessed with get()
/// - Note do not use names that start with "var(" which are reserved for custom properties. Also do not use "inherit" or "transparent" as those are reserved.
/// - The default palette color names are used throughout the system
/// @type map  

$palette: (
  "black"                   : black,
  "white"                   : white,
  "type"                    : black,
  "type-secondary"          : rgb(82, 82, 82),
  "type-tertiary"           : rgb(157, 157, 157),
  "headline"                : inherit,
  "background"              : white,
  "background-gray"         : #fafafa,
  "focus"                   : blue,
  "accent"                  : orange,
  "info"                    : #00bde3,
  "success"                 : #00a91c,
  "warning"                 : #ffbe2e,  
  "danger"                  : #d54309,  
  "info-background"         : #e7f6f8,
  "success-background"      : #ecf3ec,
  "warning-background"      : #faf3d1,
  "danger-background"       : #f4e3db,
  "selected"                : green,
  "box-shadow"              : rgba(0, 0, 0, 0.349),
  "box-shadow-hover"        : rgba(0, 0, 0, 0.5),
  "rule"                    : gray,
  "rule-light"              : lightgray,
  "link"                    : blue,
  "link-hover"              : darkblue,
  "link-active"             : darkblue,
  "link-visited"            : purple,
  "bullet"                  : inherit,
  "control"                 : white,
  "control-hover"           : white,
  "control-active"          : white,
  "control-border"          : purple,
  "control-border-hover"    : blue,
  "control-border-active"   : orange,
  "control-background"      : purple,
  "control-background-hover": blue,
  "control-background-active": orange,
) !default;

/// Pairs of background-color and color definitions
/// @type map
/// @prop {Number|String} $contexts.name.background-color Color value or name of color in $palette
/// @prop {Number|String} $contexts.name.color Color value or name of color in $palette
/// @prop {Boolean} $contexts.name.base-class Print this value in the base module as a class (if base prints)

$contexts: (
  "dark" : (
    "background-color" : "black",
    "color" : "white",
    "base-class" : true
  ),
  "light" : (
    "background-color" : "white",
    "color" : "black",
    "base-class" : true
  ),
);

/// Palette entries that are output as classes when using all-color-class-styles
/// - Use set-color-classes mixin to alter this map
$color-classes: (
  "black" : true,
  "white" : true,
  "type": true
) !default;

/// Used to override or extend the color palette
/// @param {Map} $changes A map to merge into the color palette
/// @example scss Setting the error and type color
///   @include ulu.color-set((
///     "type" : #444,
///     "error" : orange,
///   ));

@mixin set($changes) {
  $palette: map.merge($palette, $changes) !global;
}

/// Get a color from the palette by name
/// @param {String} $name Name of color to get
/// @return {Color} Note if non-string value is passed it is sent back through, along with custom properties ("var(..." and keywords inherit and transparent. This is by design so that you can always pass a user's colors through this (without having to check if it's a color value or a string [color palette])

@function get($name) {
  // Allow non lookup if the value is already a color (helps with code flow)
  @if (meta.type-of($name) == "string") {
    $is-keyword: $name == "inherit" or $name == "transparent" or $name == "currentColor";
    $is-cssvar: string.index($name, "var(") == 1;
    $is-color-mix: string.index($name, "color-mix(") == 1;
    // Allow custom-properties and keyword inherit/transparent to pass through
    @if ($is-keyword or $is-cssvar or $is-color-mix) {
      @return $name;
    // Else look up the color from the palette
    } @else {
      @return utils.require-map-get($palette, $name, 'color');
    }
  }
  // Allow everything other than strings to pass through
  // - color, null, false, etc (so they can not output)
  @return $name;
}

/// Set output classes for all-color-class-styles
/// @param {Map} $changes Map of changes (you can disable defaults this way)

@mixin set-color-classes($changes) {
  $color-classes: map.merge($color-classes, $changes) !global;
}

/// Check if a color is set in the palette

@function exists($name) {
  $color: map.get($palette, $name);
  @return if($color != null, true, false);
}

/// Set color contexts
/// @param {Map} $changes A map to merge 
/// @param {Map} $deep Use deep merge
/// @param {Map} $overwrite Overwrite the completly (cannot be used with deep)
/// @example scss Overwriting contexts
///   @include ulu.color-set-contexts((
///     "dark" : (
///       "background-color" : red,
///       "color" : white,
///     )
///   ), false, true);

@mixin set-contexts($changes, $merge-mode: null) {
  $contexts: utils.map-merge($contexts, $changes, $merge-mode) !global;
}

/// Get a context by name
/// @param {String} $name Name of context
/// @return {Map}

@function get-context($name) {
  @return utils.require-map-get($contexts, $name, 'context');
}

/// Get a context's value'
/// @param {String} $name Name of context
/// @param {String} $prop The property to get
/// @return {Color}

@function get-context-value($name, $prop) {
  $context: get-context($name);
  $value: map.get($context, $prop);
  // Get from palette by name
  @if (meta.type-of($value) == "string") {
    $value: get($value);
  }
  @return $value;
}

/// Prints contexts styles
/// @param {String} $name Name of context

@mixin context-styles($name) {
  $context: get-context($name);
  background-color: get-context-value($name, "background-color");
  background: map.get($context, "background"); // Allow gradients/images
  background-image: map.get($context, "background-image"); // Allow gradients/images
  color: get-context-value($name, "color");
}

/// Tint (add white) a color using the default white by a percentage
/// @param {Color, String} $color Color/palette color name to apply to tint
/// @param {Number} $percentage Percentage
/// @return {Color}
/// @author 
/// @link https://css-tricks.com/snippets/sass/tint-shade-functions/ Modified from source (CSS Tricks, Kitty Giraudel)

@function tint($color, $percentage) {
  @return color.mix(get("white"), get($color), $percentage);
}

/// Tint (add white) a color using the default white by a percentage (Using color-mix)
/// - This only works in modern browsers (as of June 2025)
/// - These match ulu.color-tint() and are designed to accept the same arguments with the same results
/// @param {Color, String} $color Color or custom property to apply mix to
/// @param {Number} $percentage Percentage
/// @return {Color}

@function css-tint($color, $percentage) {
  @return color-mix(in srgb, get("white") $percentage, get($color) calc(100% - $percentage));
}

/// Shade (add black) a color with the default black by a percentage
/// @param {Color, String} $color Color/palette color name to shade
/// @param {Number} $percentage Percentage to shade
/// @return {Color}
/// @author Kitty Giraudel
/// @link https://css-tricks.com/snippets/sass/tint-shade-functions/ Modified from source (CSS Tricks, Kitty Giraudel)

@function shade($color, $percentage) {
  @return color.mix(get("black"), get($color), $percentage);
}

/// Shade (add black) a color using the default white by a percentage (Using color-mix)
/// - This only works in modern browsers (as of June 2025)
/// - These match ulu.color-shade() and are designed to accept the same arguments with the same results
/// @param {Color, String} $color Color or custom property to apply mix to
/// @param {Number} $percentage Percentage
/// @return {Color}

@function css-shade($color, $percentage) {
  @return color-mix(in srgb, get("black") $percentage, get($color) calc(100% - $percentage));
}

/// Prints all context styles 
/// @param {String} $with-prop Checks the specific context for a certain prop (has to be truthy)(used for output in helper/base color modules)
/// @example scss
///  @include ulu.all-context-styles();
/// @example html {preview} Example of a color-context
///  <div class="color-context-dark" style="padding: 1rem">
////   Some text in dark context
//// </div>

@mixin all-context-styles($with-prop: null) {
  $prefix: selector.class("color-context");
  @each $name, $context in $contexts {
    @if (not $with-prop or map.get($context, $with-prop)) {
      #{ $prefix }-#{ $name } {
        @include context-styles($name);
      }
    }
  }
}

/// Outputs all color classes
/// @example scss
///  @include ulu.all-color-class-styles();
/// @example html {preview} Example of a color-context
///  <span class="color-name">Some text</span>

@mixin all-color-class-styles() {
  $prefix: selector.class("color");
  @each $name, $output in $color-classes {
    @if ($output) {
      #{ $prefix }-#{ $name } {
        color: get($name);
      }
    }
  }
}