////
/// @group cssvar
////
/// Provides support for custom-properties implementations

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

@use "utils";
@use "breakpoint";

/// Module Settings
/// @type Map
/// @prop {String} prefix [""] Default prefix, will be added to all custom properties when using mixin or functions, unless overridden, set to empty quotes to disable

$config: (
  "prefix" : ""
) !default;

/// Change modules $config
/// @example scss Setting the prefix to 'ulu'
///   @include ulu.cssvar-set(( "prefix" : "ulu" ));
/// @param {Map} $changes Map of changes

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

/// Get a config option
/// @example scss Getting the config value for prefix
///   $prefix: ulu.cssvar-get("prefix");
/// @param {String} $name Name of property
/// @return {*} Map property value

@function get($name) {
  @return utils.require-map-get($config, $name, "css-vars [config]");
}

/// Get a custom property name (with optional prefix)
/// @example scss Getting a custom property name
///   #{ ulu.cssvar-name("base-color") } { ... }
/// @param {String} $name Name of custom property 
/// @param {String} $prefix [$config.prefix] Override default prefix
/// @return {String} The formatted property name (unquoted string)

@function name($name, $prefix: get("prefix")) {
  @if (string.length($prefix) > 0) {
    @return string.unquote("--#{ $prefix }-#{ $name }");
  } @else {
    @return string.unquote("--#{ $name }");
  }
}

/// Function to use a custom property within a declaration value 
/// @example scss Print an custom property as a value
///   .test {
///     color: ulu.cssvar-use("base-color");
///   }
/// @param {String} $name Name of custom property 
/// @param {String} $default-value [null] Provide a default value for var()
/// @param {String} $prefix [$config.prefix] Override default prefix
/// @return {String} Formatted custom property for use in property value (ie. var(...))

@function use($name, $default-value: null, $prefix: get("prefix")) {
  @if ($default-value) {
    @return var(name($name, $prefix), $default-value);
  } @else {
    @return var(name($name, $prefix));
  }
}

/// Outputs a single custom property declaration
/// @example scss Declare a custom property
///   :root {
///     @include ulu.cssvar-declare("base-color", red);
///   }
/// @param {String} $name Name of property
/// @param {*} $value The properties value to declare
/// @param {String} $prefix [$config.prefix] Override default prefix

@mixin declare($name, $value, $prefix: get("prefix")) {
  #{ name($name, $prefix) } : #{ $value };
}

/// Outputs a map as custom properties
/// @example scss Declare each property in a map as a custom property
///   :root {
///     @include ulu.cssvar-declare($colors);
///   }
/// @param {Map} $props Properties to declare
/// @param {String} $prefix [$config.prefix] Override default prefix

@mixin declare-all($props, $prefix: get("prefix")) {
  @each $name, $value in $props {
    @include declare($name, $value, $prefix);
  }
}

/// Declare a custom property for current breakpoint
/// @example scss Declare each property in a map as a custom property
///   :root {
///     @include ulu.cssvar-declare-breakpoint();
///   }
/// @param {Map} $breakpoints [breakpoint.get-sizes()] Breakpoints to declare
/// @param {String} $name ["breakpoint"] Name to use for custom property
/// @param {Map} $initial [breakpoint.get("null-name")] The value for the custom property when not within breakpoint
/// @param {String} $prefix [$config.prefix] Override default prefix

@mixin declare-breakpoint(
  $breakpoints: breakpoint.get-sizes(), 
  $name: "breakpoint",
  $initial: breakpoint.get("null-name"),
  $prefix: get("prefix")
) {
  @include declare($name, $initial, $prefix);
  @each $size, $value in $breakpoints {
    @include breakpoint.min($size) {
      @include declare($name, $size, $prefix);
    }
  }
}

/// Declare a custom property for each breakpoint size
/// @example scss Declare each property in a map as a custom property
///   :root {
///     @include ulu.cssvar-declare-breakpoint-sizes();
///   }
/// @param {Map} $breakpoints [breakpoint.get-sizes()] Breakpoints to declare
/// @param {String} $name ["breakpoint-size-"] Name to use for custom property (prefixes size name)
/// @param {String} $prefix [$config.prefix] Override default prefix

@mixin declare-breakpoint-sizes(
  $breakpoints: breakpoint.get-sizes(), 
  $name: "breakpoint",
  $prefix: get("prefix"),
) {
  @each $size, $value in $breakpoints {
    $min: breakpoint.get-size-value($size);
    $max: breakpoint.get-size-value($size, true);
    @include declare("#{ $name }-#{ $size }-min", $min, $prefix);
    @include declare("#{ $name }-#{ $size }-max", $max, $prefix);
  }
}

/// Outputs css vars for a specific type from a theme map
/// @param {Map} $theme The map containing the values. Example (
/// @param {String} $key The key used to retrieve values from the map.
/// @param {String} $prefix The optional prefix for CSS variables.
/// @example scss - Example of theme map and usage
///   // Defining a map to hold my color theme values
///   $color-themes: (
///     "color-button" : (
///       "light" : blue,
///       "dark" : red
///     ), ...
///   );
/// 
///   // Declaring default theme
///   :root {
///     @include ulu.cssvar-declare-theme-values($color-themes, "light");
///   }
///   
///   // Creating class to use on body/other elements to switch to dark theme
///   .theme-dark {
///     @include ulu.cssvar-declare-theme-values($color-themes, "dark");
///   }

@mixin declare-theme-values($theme, $key, $prefix: get("prefix")) {
  @each $name, $definition in $theme {
    $value: map.get($definition, $key);
    @if ($value) {
      @include declare($name, $value, $prefix);
    }
  }
}

/// Joins a list of cssvar names
/// - Use to "+", "-" and then use in calc
/// @param {List} $names list of names (string), like if using use
/// @param {String} $separator Separator to use when joining custom property var statements
/// @return {String} For example if separator was "+" would result in "var(--some-prop) + var(--another-prop)"

@function join($names, $separator) {
  $values: ();
  @each $name in $names {
    $values: append($values, use($name));
  }
  @return utils.list-join($values, $separator);
}

/// For any names passed will join them with "+" and wrap in calc
/// @param {String} $name Name string (pass multiple comma separated)
/// @return {String} A string like "calc(var(--some-prop) + var(--another-prop))"

@function add($names...) {
  @return calc(join($names, "+"));
}

/// For any names passed will join them with "-" and wrap in calc
/// @param {String} $name Name string (pass multiple comma separated)
/// @return {String} A string like "calc(var(--some-prop) - var(--another-prop))"

@function subtract($names...) {
  @return calc(join($names, "-"));
}