////
/// @group menu-stack
////

@use "sass:meta";
@use "sass:map";
@use "sass:math";
@use "sass:selector" as sassSelector;

@use "../utils";
@use "../color";
@use "../element";
@use "../selector";
@use "../button";
@use "../typography";
@use "../cssvar";

// Used for function fallback
$-fallbacks: (
  "link-border-radius" : (
    "function" : meta.get-function("get", false, "button"),
    "property" : "border-radius"
  ),
  "label-line-height" : (
    "function" : meta.get-function("get", false, "typography"),
    "property" : "line-height-dense"
  ),
  "link-line-height" : (
    "function" : meta.get-function("get", false, "typography"),
    "property" : "line-height-dense"
  ),
  "stacked-link-border-radius" : (
    "function" : meta.get-function("get", false, "element"),
    "property" : "border-radius-small"
  )
);
    
/// Module Settings
/// @type Map
/// @prop {Dimension} nested-indent [0.5em] The indentation of child lists within the menu-stack.
/// @prop {Dimension} rule-margin [0.5em] Sets the padding and margin of the rule.
/// @prop {String} rule-style [default] Determines the styling of the rule. Uses the rule.scss component.
/// @prop {Number} toggle-icon-rotate [false] Set a value to rotate the collapsible item toggle icon rotation when open (ie. 90deg)
/// @prop {Color} label-color [null] The type color of the label.
/// @prop {Dimension} label-margin [0.5em] The margin of the label.
/// @prop {CssValue} label-text-transform [uppercase] Transforms the label text.
/// @prop {CssValue} label-type-size [false] Adjusts the type size of the label. Only uses font-size from type size.
/// @prop {CssValue} label-font-weight [bold] Adjust label font weight
/// @prop {CssValue} label-line-height [true] Adjust the label line-height, defaults to typography line-height-dense
/// @prop {list} link-active-selectors [(.is-active, '[aria-current=page]')] Selectors to apply active styling.
/// @prop {Color} link-background-color [transparent] The background color of the menu-stack toggle. 
/// @prop {Color} link-background-color-active [rgb(219, 219, 219)] The background color of the menu-stack toggle when active.
/// @prop {Color} link-background-color-hover [rgb(219, 219, 219)] The background color of the menu-stack toggle when hovered or focused.
/// @prop {Dimension} link-border-radius [true] The border radius of the menu-stack toggle. If set to true, will use the border radius from the button component.
/// @prop {String} link-color [link] The type color of the menu-stack toggle. This uses color.scss, so the value of this option should be a color variable from color.scss.
/// @prop {Color} link-color-active [black] The type color of the menu-stack toggle when active.
/// @prop {String} link-color-hover [link-hover] The type color of the menu-stack toggle when hovered or focused.  This uses color.scss, so the value of this option should be a color variable from color.scss.
/// @prop {CssValue} link-font-weight [null] The font weight of the menu-stack toggle.
/// @prop {CssValue} link-line-height [true] Adjust the link line-height, defaults to typography line-height-dense
/// @prop {Dimension} link-icon-margin [0.65em] Adds a right margin to the icon.
/// @prop {Dimension} link-icon-width [1em] The width of the icon.
/// @prop {Dimension} link-icon-font-size [null] Set the font-size for the icon (not set by default)
/// @prop {Dimension} link-margin [0.2em] Margin for the menu-stack toggle.
/// @prop {Dimension} link-padding-x [1em] Horizontal padding for menu-stack toggle.
/// @prop {Dimension} link-padding-y [0.35em] Vertical padding for menu-stack toggle.
/// @prop {Boolean} link-separated-margin [false] Enables a margin between the items in the menu-stack.
/// @prop {Boolean} link-separated-rule-style [false] Enables a rule between the items in the menu-stack.
/// @prop {Dimension} selectable-input-width [3em] The width of the checkbox/radio input
/// @prop {Dimension} selectable-input-top [0.73em] To fine tune the y/top value for absolutely positioned input, if you pass null/falsey it will use the padding which isn't always perfect since this is setup to not be centered when wrapping lines in label
/// @prop {Dimension} selectable-input-font-size [null] Optional to set a specific font-size on the input
/// @prop {Duration} link-transition-duration [200ms] The duration of the link state transition.
/// @prop {List} link-transition-properties [(border-color, background-color, color, box-shadow)] The properties to transition on link state change.
/// @prop {CssValue} title-color [null] Color to use for the title modifier
/// @prop {CssValue} title-font-weight [bold] The font weight for the title modifier.
/// @prop {Boolean} title-separator-enabled [true] Enables a separator rule below the title item.
/// @prop {Color} title-separator-color [rule] The color of the title separator rule.
/// @prop {String} title-rule-style [light] The rule style to use for the title separator.
/// @prop {Boolean} title-separated-margin [false] Use specific margin for title separated items.
/// @prop {Dimension} columns-gap [2rem] The gap between columns in a columns menu stack.
/// @prop {Dimension} columns-min-width [18rem] The minimum width of a column in a columns menu stack.
/// @prop {Dimension} compact-link-padding-x [0.75em] The links horizontal padding when using the compact option.
/// @prop {Dimension} compact-link-padding-y [0.25em] The links vertical padding when using the compact option.
/// @prop {Dimension} compact-link-margin [0.2em] Margin between items when compact
/// @prop {Dimension} compact-link-border-radius [null] Unless set will use the normal link border radius
/// @prop {Dimension} compact-selectable-input-width [2em] The width of the checkbox/radio input (when compact modifier)
/// @prop {Dimension} compact-selectable-input-font-size [null] Optional compact input font-size
/// @prop {Dimension} compact-selectable-input-top [null] Optional y/top for input
/// @prop {Dimension} stacked-link-padding-x [0.4em] The links horizontal padding when using the stacked option.
/// @prop {Dimension} stacked-link-padding-y [0.4em] The links vertical padding when using the stacked option.
/// @prop {Dimension} stacked-link-icon-margin [0.35em] Margin between icon and text when stacked.
/// @prop {Dimension} stacked-link-border-radius [true] Border radius for stacked style of links, defaults to element "border-radius-small"
/// @prop {Dimension} stacked-link-font-weight [true] Optional font-weight for stacked style

$config: (
  "nested-indent" : 0.5em,
  "rule-style" : "light",
  "rule-margin" : 0.5em,
  "toggle-icon-rotate" : false,
  "label-color" : "type-secondary",
  "label-margin" : 0.5em,
  "label-text-transform" : null,
  "label-type-size" : false,
  "label-font-weight" : bold,
  "label-line-height" : true,
  "link-separated-margin" : false,
  "link-separated-rule-style" : false,
  "link-active-selectors" : (".is-active",),
  "link-background-color" : transparent,
  "link-background-color-active" : "control-background-active",
  "link-background-color-hover" : rgba(0,0,0,0.2),
  "link-border-radius" : true,
  "link-color" : "type-secondary",
  "link-color-active" : "control-active",
  "link-color-hover" : "type",
  "link-font-weight" : null,
  "link-line-height" : true,
  "link-icon-margin" : 0.65em,
  "link-icon-width" : 1em,
  "link-icon-font-size" : null,
  "link-margin" : 0.2em,
  "link-padding-x": 0.85em,
  "link-padding-y": 0.4em,
  "link-transition-duration": 200ms,
  "link-transition-properties": (border-color, background-color, color, box-shadow),
  "compact-link-padding-x": 0.75em,
  "compact-link-padding-y": 0.25em,
  "compact-link-margin" : 0.2em,
  "compact-link-border-radius" : null,
  "compact-selectable-input-width": 2.2em,
  "compact-selectable-input-top" : 0.5em,
  "compact-selectable-input-font-size": 0.8em,
  "stacked-link-padding-x": 0.4em,
  "stacked-link-padding-y": 0.8em,
  "stacked-link-margin": 0.4em,
  "stacked-link-icon-margin": 0.35em,
  "stacked-link-border-radius": true,
  "stacked-link-font-weight" : null,
  "selectable-input-width" : 3em,
  "selectable-input-top" : 0.73em,
  "selectable-input-font-size" : null,
  "title-color" : null,
  "title-font-weight" : bold,
  "title-separator-enabled": true,
  "title-separator-color" : "rule",
  "title-rule-style" : "light",
  "title-separated-margin" : false,
  "columns-gap" : 2rem,
  "columns-min-width" : 18rem,
) !default;

/// Change modules $config
/// @param {Map} $changes Map of changes
/// @example scss
///   @include ulu.component-menu-stack-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-menu-stack-get("property");

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

// Internal fallback helper
@function -fallback($op1, $op2) {
  @return utils.map-fallback($config, $op1, $op2);
}

/// Prints component styles
/// @example scss
///  @include ulu.component-menu-stack-styles();
/// @todo Colors stuff
/// @todo Selector prefix

@mixin styles {
  $prefix: selector.class("menu-stack");
  $prefix-name-only: selector.class("menu-stack", $name-only: true);
  $prefix-popover: selector.class("popover");
  $selectable-y: (get("link-padding-y") + get("link-margin"));

  #{ $prefix } {
    @include cssvar.declare-ulu("menu-stack-link-padding-x", get("link-padding-x"));
  }

  #{ $prefix }--separated {
    border-top: element.get-rule-style(get("rule-style"));
    padding-top: get("rule-margin");
    margin-top: get("rule-margin");
  }
  #{ $prefix }__label {
    text-transform: get("label-text-transform");
    padding-bottom: get("label-margin");
    color: color.get(get("label-color"));
    font-weight: get("label-font-weight");
    line-height: get("label-line-height");
    @if (get("label-type-size")) {
      @include typography.size(get("label-type-size"), $only-font-size: true);
    }
  }
  #{ $prefix }__item--separator-before {
    border-top: element.get-rule-style(-fallback("link-separated-rule-style", "rule-style"));
    margin-top: -fallback("link-separated-margin", "link-padding-y");
    padding-top: -fallback("link-separated-margin", "link-padding-y");
  }
  #{ $prefix }__item--separator-after {
    border-bottom: element.get-rule-style(-fallback("link-separated-rule-style", "rule-style"));
    margin-bottom: -fallback("link-separated-margin", "link-padding-y");
    padding-bottom: -fallback("link-separated-margin", "link-padding-y");
  }
  #{ $prefix }__list {
    & & {
      padding-left: get("nested-indent");
    }
  }

  // Special modifier for item to style as a title
  // - Used in columns menus where first level isn't in a <ul> but is just above 
  //   the <ul> and being styled as though it was to match the styling of the menu 
  //   of children
  // - Note: This is output above the link styling for specificity, so it will 
  //   fallback to link colors for hover/active
  #{ $prefix }__item--title {
    @if get("title-separator-enabled") {
      border-bottom: element.get-rule-style(-fallback("title-rule-style", "rule-style"));
      margin-bottom: -fallback("title-separated-margin", "link-padding-y");
      padding-bottom: -fallback("title-separated-margin", "link-padding-y");
    }
    &,
    > #{ $prefix }__link {
      color: color.get(get("title-color"));
      font-weight: get("title-font-weight");
    }
  }
  

  // By default the link hangs outside the container so that 
  // the icons/text align to the text (above/below)
  // - Use the modifier "site-menu--contained" to keep the links within 
  //   the parent container (no optical alignment), should be within something that contains it

  #{ $prefix }__link,
  #{ $prefix }__selectable,
  #{ $prefix }__toggle {
    position: relative;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    width: 100%;
    padding: get("link-padding-y") cssvar.use-ulu("menu-stack-link-padding-x");
    margin: get("link-margin") 0;
    border-radius: get("link-border-radius");
    font-weight: get("link-font-weight");
    line-height: get("link-line-height");
    color: color.get(get("link-color"));
    background-color: color.get(get("link-background-color"));
    transition-duration: get("link-transition-duration");
    transition-property: get("link-transition-properties");
    &:hover,
    &:focus {
      z-index: 2;
      color: color.get(get("link-color-hover"));
      background-color: color.get(get("link-background-color-hover"));
    }
  }
  #{ $prefix }__selectable {
    padding: 0;
  }

  // Combine all active selectors using sass:selector functions
  $base-selectors: #{ $prefix }__link, #{ $prefix }__toggle;
  $active-from-config: get("link-active-selectors");
  $traditional-active: sassSelector.append($base-selectors, $active-from-config);

  $checked-active: sassSelector.parse("#{ $prefix }__selectable:has(> [type='checkbox']:checked), #{ $prefix }__selectable:has(> [type='radio']:checked)");

  #{ $traditional-active, $checked-active },
  #{ $prefix }__link[aria-current="page"] {
    &,
    &:hover {
      color: color.get(get("link-color-active"));
      background-color: color.get(get("link-background-color-active"));
    }
  }
  #{ $prefix }__selectable [type="checkbox"],
  #{ $prefix }__selectable [type="radio"],
  #{ $prefix }__selectable-input {
    position: absolute;
    top: utils.fallback(get("selectable-input-top"), $selectable-y);
    left: cssvar.use-ulu("menu-stack-link-padding-x");
    font-size: get("selectable-input-font-size");
  }
  #{ $prefix }__selectable label,
  #{ $prefix }__selectable-label {
    width: 100%;
    padding: $selectable-y cssvar.use-ulu("menu-stack-link-padding-x") $selectable-y get("selectable-input-width");
  }
  #{ $prefix }__link-text {
    display: block;
    flex-grow: 1;
  }
  #{ $prefix }__link-icon {
    margin-right: get("link-icon-margin");
    flex: 0 0 get("link-icon-width");
    font-size: get("link-icon-font-size");
  }
  #{ $prefix }__collapsible {
    margin: 0;
    @if (get("toggle-icon-rotate")) {
      &[open] {
        #{ $prefix }__toggle-icon {
          transform: rotate(get("toggle-icon-rotate"));
        }
      }
    }
  }
  #{ $prefix }__toggle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
    @include element.summary-remove-marker();  
  }

  // Modifiers

  // Link buttons hang outside in margin so that text optically aligns
  #{ $prefix }--hanging {
    &:not(#{ $prefix }--columns, #{ $prefix }--columns-fluid) > #{ $prefix }__list > #{ $prefix }__item,
    &[class*="#{ $prefix-name-only }--columns"] > #{ $prefix }__list > #{ $prefix }__item > #{ $prefix }__list > #{ $prefix }__item {
      > #{ $prefix }__link, 
      > #{ $prefix }__collapsible {
        margin-left: calc(cssvar.use-ulu("menu-stack-link-padding-x") * -1);
        margin-right: calc(cssvar.use-ulu("menu-stack-link-padding-x") * -1);
        width: calc(100% + (cssvar.use-ulu("menu-stack-link-padding-x") * 2));
      }
    }
  }

  #{ $prefix }--compact {
    $compact-y: get("compact-link-padding-y");
    $compact-x: get("compact-link-padding-x");
    
    @include cssvar.declare-ulu("menu-stack-link-padding-x", $compact-x);

    #{ $prefix }__selectable,
    #{ $prefix }__toggle,
    #{ $prefix }__link {
      border-radius: get("compact-link-border-radius");
      margin: get("compact-link-margin") 0;
    }
    #{ $prefix }__toggle,
    #{ $prefix }__link {
      padding-top: $compact-y;
      padding-bottom: $compact-y;
    }
    #{ $prefix }__selectable label,
    #{ $prefix }__selectable-label {
      padding-top: $compact-y;
      padding-bottom: $compact-y;
      padding-right: get("compact-selectable-input-width");
    }
    #{ $prefix }__selectable [type="checkbox"],
    #{ $prefix }__selectable [type="radio"],
    #{ $prefix }__selectable-input {
      top: utils.fallback(get("compact-selectable-input-top"), $compact-y);
      font-size: get("compact-selectable-input-font-size");
    }
  }

  #{ $prefix }--hide-inputs {
    #{ $prefix }__selectable-input,
    #{ $prefix }__selectable [type="checkbox"],
    #{ $prefix }__selectable [type="radio"] {
      @include element.hidden-visually();
    }

    #{ $prefix }__selectable label,
    #{ $prefix }__selectable-label {
      padding-left: get("link-padding-x");
    }
  }

  #{ $prefix }--stacked {
    @include cssvar.declare-ulu("menu-stack-link-padding-x", get("stacked-link-padding-x"));

    #{ $prefix }__link,
    #{ $prefix }__toggle {
      flex-direction: column;
      justify-content: center;
      text-align: center;
      border-radius: get("stacked-link-border-radius");
      padding-top: get("stacked-link-padding-y");
      padding-bottom: get("stacked-link-padding-y");
      margin: get("stacked-link-margin") 0;
      font-weight: get("stacked-link-font-weight");
    }
    #{ $prefix }__link-icon {
      margin-right: 0;
      margin-bottom: get("stacked-link-icon-margin");

      &:last-child {
        margin-bottom: 0;
      }
    }
  }

  #{ $prefix }--columns {
    > #{ $prefix }__list {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(get("columns-min-width"), 1fr));
      gap: get("columns-gap");
    }
  }
  #{ $prefix }--columns-fluid {
    > #{ $prefix }__list {
      display: flex;
      flex-wrap: wrap;
      max-width: 100%;
      gap: get("columns-gap");
      > #{ $prefix }__item {
        flex: 0 0 0;
        min-width: get("columns-min-width");
      }
    }
  }
  // No indenting if we're using columns
  [class*="#{ $prefix-name-only }--columns"] {
    > #{ $prefix }__list > #{ $prefix }__item > #{ $prefix }__list {
      padding-left: 0;
    }
  }
}
