////
/// @group callout
/// A container for content that highlights important information, provides context, or guides user attention within an interface
////

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

@use "../utils";
@use "../selector";
@use "../element";
@use "../color";

// Used for function fallback
$-fallbacks: (
  "border-radius" : (
    "function" : meta.get-function("get", false, "element"),
    "property" : "border-radius"
  )
);

/// Module Settings
/// @type Map
/// @prop {Color} background-color [rgb(240, 240, 240)] The background color of the Callout.
/// @prop {Color} border-color ["rule-light"] The border color of the Callout.
/// @prop {Boolean} border-radius [true] The border radius of the Callout.
/// @prop {Dimension} border-width [1px] The border width of the Callout.
/// @prop {CssValue} box-shadow [none] The box-shadow of the Callout.
/// @prop {Boolean} caps-disabled [false] If set will not output any cap styles for both base and styles
/// @prop {Boolean} cap [false] Toggles the use of caps on default callout
/// @prop {Boolean} cap-side ["left"] The side that gets the cap
/// @prop {Number} cap-match-radius [true] The cap should have be rounded to match the parent's border radius
/// @prop {Map} cap-options The options for cap (see element.cap for options)
/// @prop {Dimension} margin [2rem] Bottom margin of the Callout.
/// @prop {Dimension} padding [1.5rem] Padding of the Callout.

$config: (
  "background-color" : rgb(240, 240, 240),
  "border-color" : "rule-light",
  "border-radius" :  6px,
  "border-width" : 1px,
  "box-shadow" : none,
  "caps-disabled" : false,
  "cap" : false,
  "cap-side" : "left",
  "cap-match-radius" : false,
  "cap-options" : (
    "color" : rgb(160, 160, 160),
    "size" : 0.5rem,
  ),
  "margin" : 2rem,
  "padding" : 1.5rem,
) !default;

/// Styles Map (for unique variations/modifiers)
/// - Adjust this with set-styles
/// @type Map

$styles: (
  "outline" : (
    "background-color": transparent
  ),
  "info" : (
    "background-color" : "info-background",
  ),
  "warning" : (
    "background-color" : "warning-background",
  ),
  "success" : (
    "background-color" : "success-background",
  ),
  "danger" : (
    "background-color" : "danger-background",
  ),
) !default;

/// Change modules $config
/// @param {Map} $changes Map of changes
/// @example scss
///   @include ulu.component-callout-set(( "property" : value ));

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

/// Get a config option
/// @param {Map} $name Name of property
/// @example scss
///   @include ulu.component-callout-get("property");

@function get($name) {
  $value: utils.require-map-get($config, $name, "callout [config]");
  @return utils.function-fallback($name, $value, $-fallbacks);
}

/// Set callout style variations
/// - Styles that modify padding when using mix-match caps on/off should be included last
/// @param {Map} $changes Map of changes (options for style include [background-color, color, border-color, border-radius, border-width, box-shadow, padding, cap, cap-options]
/// @param {String} $merge-mode Merge mode see utils.map-merge() [null|"deep"|"overwrite"]

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

/// Output component stylesheet
/// @example scss
///  @include ulu.component-callout-styles();

@mixin styles {
  $prefix: selector.class("callout");  
  $padding: get("padding");
  $padding-info: utils.get-spacing($padding);
  $cap-options: get("cap-options");
  $cap-size: map.get($cap-options, "size");
  $cap-side: get("cap-side");

  #{ $prefix } {
    position: relative; // For cap
    background-color: color.get(get("background-color"));
    padding: $padding;
    border: get("border-width") solid color.get(get("border-color"));
    margin-bottom: get("margin");
    box-shadow: get("box-shadow");
    border-radius: get("border-radius");
    & >:first-child {
      margin-top: 0;
    }

    // If we have left cap on default we reuse this for all
    // Else we will print it out manually for each unique style
    @if (not get("caps-disabled")) {   
      $cap-defaults: (
        "offset" : get("border-width"),
        "border-radius" : utils.when(get("cap-match-radius"), get("border-radius"), null),
        // "padding-adjust" : map.get($padding-info, $cap-side)
      );
      @include element.cap(
        $side: $cap-side,
        $options: map.merge($cap-defaults, $cap-options)
      );
    }
      
    // If the left cap is disabled we still include it's CSS but we hide it
    // so that other styles of callouts can use it
    @if (not get("cap")) {
      &::before {
        content: none;
      }
    // Since this is hidden and reused we need to not use padding adjust unless it
    // was visible
    } @else if ($cap-size) {
      padding-#{ $cap-side }: calc(map.get($padding-info, $cap-side) + $cap-size);
    }
  }

  @include -output-style-modifiers();
}

// Output Each Style Modifier
// - Note if cap is not disabled this will just update appearance values of cap styling
@mixin -output-style-modifiers() {
  $prefix: selector.class("callout");  
  $caps-enabled: not get("caps-disabled");
  $cap-side: get("cap-side");

  @each $name, $style in $styles {
    $cap: map.get($style, "cap");
    $padding: map.get($style, "padding");
    $border-radius: map.get($style, "border-radius");
    $background-color: map.get($style, "background-color");
    $color: map.get($style, "color");
    $border-color: map.get($style, "border-color");
    $border-width: map.get($style, "border-width");
    $box-shadow: map.get($style, "box-shadow");
    $cap-match-radius: map.get($style, "cap-match-radius");

    #{ $prefix }--#{ $name } {
      background-color: color.get($background-color); 
      color: color.get($color); 
      border-radius: $border-radius; 
      border-color: color.get($border-color); 
      border-width: $border-width; 
      box-shadow: $box-shadow; 
      padding: $padding; 

      @if ($cap and $caps-enabled) {
        $match-radius: utils.if-type("bool", $cap-match-radius, get("cap-match-radius"));
        // Padding adjust always has to be set (since size could change or padding)
        $padding-info: utils.get-spacing(utils.fallback($padding, get("padding")));
        $cap-radius: utils.if-type("number", $border-radius, get("border-radius"));
        $cap-options: utils.ensure-map(map.get($style, "cap-options"));
        $cap-defaults: (
          "size" : map.get(get("cap-options"), "size"),
          "padding-adjust" : map.get($padding-info, $cap-side),
          "offset" : $border-width,
          "border-radius" : utils.when($match-radius, $cap-radius, null)
        );

        @include element.cap-appearance(
          $side: $cap-side,
          $options: map.merge($cap-defaults, $cap-options),
          $before: true
        );

        // Because the main callout's cap may not be visible
        &::before {
          content: "";
        }
      // If set to false remove the cap (if enabled) and reset default cap padding adjust
      } @else if ($cap == false and $caps-enabled) {
        // if this style doesn't set padding
        @if (not $padding) {
          $padding-info: utils.get-spacing(get("padding"));
          padding-#{ $cap-side }: map.get($padding-info, $cap-side);
        }
        &::before {
          content: none;
        }
      }
    }
  }
}