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

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

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

// Used for function fallback
$-fallbacks: (
  "description-line-height" : (
    "function" : meta.get-function("get", false, "typography"),
    "property" : "line-height-dense",
  ),
);

/// Module Settings
/// @type Map
/// @prop {CssValue} color [inherit] Color of the text of the form.
/// @prop {CssValue} color-placeholder ["type-tertiary"] Color for the placeholder text.
/// @prop {Boolean} drupal [false] Toggle if using drupal to include drupal specific styling.
/// @prop {Color} error-color ["danger"] Type color for errors.
/// @prop {Color} error-highlight-color [rgb(251, 242, 242)] Outline color of error container.
/// @prop {String} error-selector [".is-danger"] Class for error styling.
/// @prop {} file-button-style [true] @joe-check should this have a fallback
/// @prop {CssValue} font-weight-label [bold] Font weight of the labels.
/// @prop {CssValue} font-weight-legend [bold] Font weight of the legend.
/// @prop {CssValue} font-weight-placeholder [normal] Font weight of placeholder text.
/// @prop {CssValue} font-weight-input [null] Font weight of input text.
/// @prop {CssValue} font-weight-textarea [null] Font weight of textarea text.
/// @prop {CssValue} font-weight-select [null] Font weight of select text.
/// @prop {CssValue} input-border [element.get-rule-style()] Border of the input.
/// @prop {Dimension} input-border-radius [0] Border radius of the input.
/// @prop {Dimension} input-padding-x [0.5em] Horizontal padding of the input.
/// @prop {Dimension} input-padding-y [0.25em] Vertical padding of the input.
/// @prop {Dimension} input-min-width [10em] Min width of the input.
/// @prop {Color} input-background-color [white] Background color of the input.
/// @prop {Dimension} item-border-radius [null] Border radius for __item.
/// @prop {Dimension} item-highlight-width [6px] Width of the item box highlight.
/// @prop {Color} required-color ["danger"] Color for required text.
/// @prop {Dimension} text-input-margin-bottom [0.5em] Bottom margin for the label.
/// @prop {Dimension} text-input-margin-top [1em] Top margin for the label.
/// @prop {Color} warning-color ["warning"] The warning text color.
/// @prop {Color} warning-highlight-color [rgb(255, 249, 237)] Outline color of the warning.
/// @prop {String} warning-selector [".is-warning"] Selector for adding warning styles.
/// @prop {Color} check-input-color [currentColor] @joe-check unused
/// @prop {Dimension} check-input-size [1.15em] Size of input box.
/// @prop {Dimension} check-input-touch-size [2em] Touchable size of the input box.
/// @prop {Color} check-input-background-color [white] Background color for the check input.
/// @prop {Color} check-input-background-color-checked [white] Background color for the check input when checked.
/// @prop {Color} check-input-background-color-hover [white] Background color for the check input when hovered or focused.
/// @prop {Color} check-input-background-color-indeterminate [white] Background color for the indeterminate check input.
/// @prop {} check-input-border [null] @joe-check check how this is called with a fallback in the styles mixin
/// @prop {Color} check-input-border-color-hover [null] Check input border color.
/// @prop {Color} check-input-border-color-checked [null] Check input border color when checked.
/// @prop {Color} check-input-border-color-indeterminate [null] Indeterminate check input border color.
/// @prop {Color} check-input-border-color-focus [null] Check input border color when hovered or focused.
/// @prop {CssValue} check-input-outline [null] Check input outline.
/// @prop {CssValue} check-input-outline-hover [null] Check input outline when hovered.
/// @prop {CssValue} check-input-outline-checked [null] Check input outline when checked.
/// @prop {CssValue} check-input-outline-focus [1px solid white] Check input outline when focused.
/// @prop {Color} check-input-touch-color-hover [#e8e8e8] Check input background color when hovered.
/// @prop {Color} check-input-touch-color-focus [null] Check input background color when focused.
/// @prop {Dimension} check-input-radio-size [0.3em] Radio border size.
/// @prop {Dimension} check-input-checkmark-width [0.38em] Width of checkmark.
/// @prop {Dimension} check-input-checkmark-height [0.68em] Height of checkmark.
/// @prop {Dimension} check-input-checkmark-offset-y [-0.2em] vertical offset of checkmark.
/// @prop {Dimension} check-input-checkmark-stroke-size [0.18em] stroke size of checkmark.
/// @prop {Color} check-input-mark-color [currentColor] Check input color.
/// @prop {Color} check-input-mark-color-hover [null] Check input color when hovered.
/// @prop {Color} check-input-mark-color-focus [null] Check input color when focused.
/// @prop {Color} check-input-mark-color-checked [null] Check input color when checked.
/// @prop {Color} check-input-mark-color-indeterminate [null] Check input color when indeterminate.
/// @prop {Number} check-input-disabled-opacity [0.6] Opacity of the check input when disabled.
/// @prop {Dimension} check-input-border-radius [null] Checkbox input border radius.
/// @prop {Color} description-color [false] Color of help text.
/// @prop {CssValue} description-margin [(0.25em 0)] Margin for help text.
/// @prop {Dimension} description-max-width [25em] Max width of help text.
/// @prop {Number} description-line-height [true] Line height for description element, defaults to typography line-height-dense
/// @prop {Color} fieldset-background [transparent] Background color of fieldset element.
/// @prop {CssValue} fieldset-border [none] Border for fieldset
/// @prop {Dimension} fieldset-margin-bottom [1rem] Bottom margin for the fieldset element.
/// @prop {Dimension} fieldset-margin-top [1rem] Bottom margin for the fieldset element.
/// @prop {Dimension} fieldset-padding [0] Padding for the fieldset element.
/// @prop {Dimension} fieldset-margin-compact [0] @joe-check unused
/// @prop {Dimension} fieldset-border-radius [0] Border radius of the fieldset element.
/// @prop {Color} fieldset-legend-color [inherit] Text color for the fieldset's label.
/// @prop {Dimension} fieldset-legend-border-bottom [null] Bottom border color for the fieldset's label
/// @prop {Dimension} fieldset-legend-padding-bottom [null] Bottom padding for the fieldset's label
/// @prop {Dimension} select-border-radius [4px] Border radius for the select element.
/// @prop {Color} select-background-color [null] Background color for the select element.
/// @prop {CssValue} select-border [null] The border for the select element. Fallback to input border.
/// @prop {Dimension} select-padding-x [null] Horizontal padding for the select element. Fallback to input-padding-x.
/// @prop {Dimension} select-padding-y [null] Vertical padding for the select element. Fallback to input-padding-y.
/// @prop {CssValue} select-image [null] Url for select element's background image.
/// @prop {Dimension} select-image-size [0.9em] Background size for the select image.
/// @prop {Dimension} select-image-offset [0.7em] Offset for the select image.
/// @prop {Dimension} select-image-margin [0.65em] select image margin.
/// @prop {Dimension} inline-gap [1em] Gap between items that are inline like checkboxes

$config: (
  "color"                                     : inherit,
  "color-placeholder"                         : "type-tertiary",
  "drupal"                                    : false,
  "error-color"                               : "danger",
  "error-highlight-color"                     : rgb(251, 242, 242),
  "error-selector"                            : ".is-danger",
  "file-button-style"                         : true,
  "font-weight-label"                         : bold,
  "font-weight-legend"                        : bold,
  "font-weight-placeholder"                   : normal,
  "font-weight-input"                         : null,
  "font-weight-textarea"                      : null,
  "font-weight-select"                        : null,
  "input-border"                              : element.get-rule-style(),
  "input-border-radius"                       : 0,
  "item-margin-y"                            : 0.75em,
  "input-padding-x"                           : 0.5em,
  "input-padding-y"                           : 0.25em,
  "input-min-width"                           : 10em,
  "input-background-color"                    : white,
  "item-border-radius"                        : null,
  "item-highlight-width"                      : 6px,
  "required-color"                            : "danger",
  "text-input-margin-bottom"                  : 0.5em,
  "text-input-margin-top"                     : 1em,
  "warning-color"                             : "warning",
  "warning-highlight-color"                   : rgb(255, 249, 237),
  "warning-selector"                          : ".is-warning",
  "check-input-color"                         : currentColor,
  "check-input-size"                          : 1.15em,
  "check-input-touch-size"                    : 2em,
  "check-input-background-color"              : white,
  "check-input-background-color-checked"      : white,
  "check-input-background-color-hover"        : white,
  "check-input-background-color-indeterminate": white,
  "check-input-border"                        : null,
  "check-input-border-color-hover"            : null,
  "check-input-border-color-checked"          : null,
  "check-input-border-color-indeterminate"    : null,
  "check-input-border-color-focus"            : null,
  "check-input-outline"                       : null,
  "check-input-outline-hover"                 : null,
  "check-input-outline-checked"               : null,
  "check-input-outline-focus"                 : 1px solid white,
  "check-input-touch-color-hover"             : #e8e8e8,
  "check-input-touch-color-focus"             : null,
  "check-input-radio-size"                    : 0.3em,
  "check-input-checkmark-width"               : 0.38em,
  "check-input-checkmark-height"              : 0.68em,
  "check-input-checkmark-offset-y"            : -0.2em,
  "check-input-checkmark-stroke-size"         : 0.18em,
  "check-input-mark-color"                    : currentColor,
  "check-input-mark-color-hover"              : null,
  "check-input-mark-color-focus"              : null,
  "check-input-mark-color-checked"            : null,
  "check-input-mark-color-indeterminate"      : null,
  "check-input-disabled-opacity"              : 0.6,
  "check-input-border-radius"                 : null,
  "description-color"                         : false,
  "description-margin"                        : (0.25em 0),
  "description-max-width"                     : 25em,
  "description-line-height"                   : true,
  "fieldset-background"                       : transparent,
  "fieldset-border"                           : none,
  "fieldset-margin-bottom"                    : 1rem,
  "fieldset-margin-top"                       : 1rem,
  "fieldset-padding"                          : 0,
  "fieldset-margin-compact"                   : 0,
  "fieldset-border-radius"                    : 0,
  "fieldset-legend-color"                     : inherit,
  "fieldset-legend-border-bottom"             : null,
  "fieldset-legend-padding-bottom"            : 0,
  "fieldset-legend-margin-bottom"             : 0.5em,
  "select-border-radius"                      : 4px,
  "select-background-color"                   : null,
  "select-border"                             : null,
  "select-padding-x"                          : null,
  "select-padding-y"                          : null,
  "select-image"                              : null,
  "select-image-size"                         : 0.9em,
  "select-image-offset"                       : 0.7em,
  "select-image-margin"                       : 0.65em,
  "inline-gap"                                : 1em
) !default;

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

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

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

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

@mixin styles() {
  $prefix: selector.class("form-theme");

  // Shared element styles
  #{ $prefix } {
    @include form-element-styles();
  }

  // Print styles differently for standard vs Drupal
  // - Has different elements (ie. .form-item)
  @if (get("drupal")) {
    @include drupal-layout-element-styles();
  } @else {
    @include layout-element-styles();
  }

  // Modifiers
  #{ $prefix }--full-width {
    [type="text"],
    [type="email"],
    [type="password"] {
      width: 100%;
    }
    textarea {
      width: 100%;
    }
  }
  #{ $prefix }--full-width-select {
    select {
      width: 100%;
    }
  }
  #{ $prefix }--hide-labels {
    label {
      @include element.hidden-visually();
    }
  }
}

@mixin form-element-styles() {
  $errorColor: color.get(get("error-color"));
  $selectError: get("error-selector");
  $warningColor: color.get(get("warning-color"));
  $selectWarning: get("warning-selector");
  $input-touch-size: get("check-input-touch-size");
  $input-size: get("check-input-size");
  $input-touch-margin: math.div($input-touch-size - $input-size, 2);
  $input-touch-margin-neg: -($input-touch-margin);
  $file-button-style: get("file-button-style");

  input:not([type="submit"]),
  select,
  textarea,
  label,
  legend {
    color: color.get(get("color"));
    font-size: 1em;
    max-width: 100%;
    line-height: typography.get("line-height-dense");
    box-sizing: border-box;
    flex-shrink: 0;
    &::placeholder {
      color: color.get(get("color-placeholder"));
      font-weight: get("font-weight-placeholder");
    }
  }
  input:not([type="submit"]) {
    font-weight: get("font-weight-input");
  }
  textarea {
    font-weight: get("font-weight-textarea");
  }
  select,
  textarea,
  [type="text"],
  [type="tel"],
  [type="time"],
  [type="url"],
  [type="date"],
  [type="email"],
  [type="month"],
  [type="week"],
  [type="number"],
  [type="search"],
  [type="datetime-local"],
  [type="password"],
  [type="file"] {
    padding: get("input-padding-y") get("input-padding-x");
    background-color: color.get(get("input-background-color"));
    border-radius: get("input-border-radius");
    transition: border linear 0.2s;
    border: get("input-border");
    min-width: get("input-min-width");
    margin: 0;
    // &:focus {
      // outline: none;
      // border: 1px solid color-get("focus");
      // box-shadow: element-get("box-shadow");
    // }
  }
  select {
    font-weight: get("font-weight-select");
    border-radius: get("select-border-radius");
    background-color: color.get(get("select-background-color"));
    padding: -fallback("select-padding-y", "input-padding-y") -fallback("select-padding-x", "input-padding-x");
    border: -fallback("select-border", "input-border");
    @if get("select-image") {
      // Hide default arrow and extend padding so text doesn't overlap the icon
      appearance: none; 
      background-image: url(get("select-image"));
      background-repeat: no-repeat;
      background-position: center right get("select-image-offset");
      background-size: get("select-image-size");
      padding-right: get("select-image-offset") + get("select-image-size") + get("select-image-margin"); 
    }
  }
  // Replace Native Inputs with CSS styled one
  [type="checkbox"],
  [type="radio"] {
    appearance: none;
    margin: 0;
    display: inline-block;
    width: $input-touch-size; // Touchable surface
    height: $input-touch-size;
    margin: $input-touch-margin-neg 0 $input-touch-margin-neg $input-touch-margin-neg; // Optical alignment
    padding: 0.5em;
    background-color: transparent;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: relative;
    transition: background-color 220ms ease-in-out;
    flex: 0 0 $input-touch-size; // When used in flex container
    // Box / Circle (centered absolute)
    &::before {
      content: '';
      display: block;
      position: absolute;
      width: $input-size;
      height: $input-size;
      outline: get("check-input-outline");
      border: -fallback("check-input-border", "input-border");
      border-radius: 50%;
      transition-timing-function: ease-out;
      transition-duration: 150ms;
      transition-property: background-color, border-color;
      background-color: -fallback("check-input-background-color", "input-background-color");
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    // Checkmark/ radio
    &::after {
      content: '';
      display: block;
      position: relative;
      z-index: 2;
      opacity: 0;
      transform: rotate(45deg);
      transition: opacity ease-out 150ms;
      border: get("check-input-radio-size") solid color.get(get("check-input-mark-color"));
      border-radius: 50%;
    }
    &:focus {
      background-color: color.get(get("check-input-touch-color-focus"));
      &::before {
        border-color: color.get(get("check-input-border-color-focus"));
        outline: get("check-input-outline-focus");
      }
      &::after {
        border-color: color.get(get("check-input-mark-color-focus"));
      }
    }
    &:hover {
      background-color: color.get(get("check-input-touch-color-hover"));
      &::before {
        outline: get("check-input-outline-hover");
        background-color: color.get(get("check-input-background-color-hover"));
        border-color: color.get(get("check-input-border-color-hover"));
      }
      &::after {
        border-color: color.get(get("check-input-mark-color-hover"));
      }
    }
    &:checked {
      &::before {
        background-color: color.get(get("check-input-background-color-checked"));
        border-color: color.get(get("check-input-border-color-checked"));
        outline: get("check-input-outline-checked");
      }
      &::after {
        opacity: 1;
        border-color: color.get(get("check-input-mark-color-checked"));
      }
    }
    
    &:disabled,
    &[aria-disabled="true"],
    &[disabled] {
      &,
      & + label  {
        opacity: get("check-input-disabled-opacity");
      }
    }
  }
  [type="checkbox"] {
    &::before {
      border-radius: -fallback("check-input-border-radius", "input-border-radius");
    }
    &::after {
      border-radius: 0;
      width: get("check-input-checkmark-width");
      height: get("check-input-checkmark-height");
      transform: rotate(45deg);
      margin-top: get("check-input-checkmark-offset-y");
      border-top: none;
      border-left: none;
      border-bottom-width: get("check-input-checkmark-stroke-size");
      border-right-width: get("check-input-checkmark-stroke-size");
    }
    &:indeterminate,
    &[aria-checked=mixed] {
      &::before {
        background-color: color.get(get("check-input-background-color-indeterminate"));
        border-color: color.get(get("check-input-border-color-indeterminate"));
      }
      &::after {
        border-right: none;
        transform: translatey(50%);
        opacity: 1;
        height: get("check-input-checkmark-stroke-size");
        border-color: color.get(get("check-input-mark-color-indeterminate"));
      }
    }
  }

  fieldset {
    display: block;
    width: 0;
    min-width: 100%;
    box-sizing: border-box;
    margin-top: get("fieldset-margin-top");
    margin-bottom: get("fieldset-margin-bottom");
    border: get("fieldset-border");
    background-color: color.get(get("fieldset-background"));
    border-radius: get("fieldset-border-radius");
    padding: get("fieldset-padding");
    
    > legend {
      font-weight: get("font-weight-legend");
      display: block;
      margin: 0 0 get("fieldset-legend-margin-bottom") 0;
      border: 0;
      padding: 0 0 get("fieldset-legend-padding-bottom") 0;
      width: 100%;
      float: left;
      border-bottom: get("fieldset-legend-border-bottom");
      color: color.get(get("fieldset-legend-color"));
      & ~ * {
        clear: left;
      }
    }
    &#{ $selectError } {
      > legend {
        color: color.get($errorColor);
      }
    }
    &#{ $selectWarning } {
      > legend {
        color: color.get($warningColor);
      }
    }
  }
}

/// Required Character styles (ie. "*")
@mixin element-required-char() {
  color: color.get(get("required-color"));
  font-size: 110%;
  font-weight: bold;
  &:last-child {
    margin-left: 0.15em;
  }
}

/// Help text / Description
@mixin element-help-text() {
  margin: get("description-margin");
  font-style: italic;
  @include typography.size("small", null, true);
  line-height: get("description-line-height");
  max-width: get("description-max-width");
  color: color.get(get("description-color"));
}

/// Styles for form item that should have label as block and text input
@mixin element-form-item-block() {
  display: block;
  label {
    font-weight: get("font-weight-label");
    display: block;
    margin-bottom: get("text-input-margin-bottom");
    margin-top: get("text-input-margin-top");
  }
  input {
    border-radius: get("input-border-radius");
  }
}

/// Footer of form (with button for example)
@mixin element-form-actions() {
  display: flex;
  margin: 1rem 0;
}

/// Footer of form (with button for example)
@mixin element-form-actions-right() {
  justify-content: flex-end;
}

/// Layout styling for static/app sites
@mixin layout-element-styles() {
  $prefix: selector.class("form-theme");
  $errorColor: color.get(get("error-color"));
  $selectError: get("error-selector");
  $warningColor: color.get(get("warning-color"));
  $selectWarning: get("warning-selector");

  #{ $prefix }__required-char {
    @include element-required-char();
  }
  #{ $prefix }__description {
    @include element-help-text();
  }
  #{ $prefix }__item {
    display: flex;
    align-items: center;
    margin-bottom: get("item-margin-y");
    border-radius: get("item-border-radius");
    flex-shrink: 0; // Cannot be smaller than content within
    @include -form-item-state($selectError, $errorColor, color.get(get("error-highlight-color")));
    @include -form-item-state($selectWarning, $warningColor, color.get(get("warning-highlight-color")));
  }
  #{ $prefix }__item--align-top {
    align-items: flex-start;
  }
  #{ $prefix }__item--text,
  #{ $prefix }__item--file,
  #{ $prefix }__item--select,
  #{ $prefix }__item--textarea {
    @include element-form-item-block();
  }
  #{ $prefix }__items-inline {
    display: flex;
    flex-wrap: wrap;
    gap: get("inline-gap");
    > #{ $prefix }__item {
      margin: 0;
    }
  }
  #{ $prefix }__actions {
    @include element-form-actions();
  }
  #{ $prefix }--actions-right {
    #{ $prefix }__actions {
      @include element-form-actions-right();
    }
  }
  #{ $prefix }__error {
    color: color.get($errorColor);
  }
  #{ $prefix }__warning {
    color: color.get($warningColor);
  }
}

/// Layout styles but using drupal form structures
@mixin drupal-layout-element-styles() {
  $prefix: selector.class("form-theme");
  #{ $prefix } {
    .form-required-character {
      @include element-required-char();
    }
    .description {
      @include element-help-text();
    }
    .form-item:not(fieldset) {
      margin-bottom: 1rem;
    }
    [class*="form-type-textarea"],
    [class*="form-type-password"],
    [class*="form-type-email"],
    [class*="form-type-tel"],
    [class*="form-type-number"],
    [class*="form-type-select"],
    [class*="form-type-textfield"] {
      @include element-form-item-block();
    }
    .form-actions {
      @include element-form-actions();
    }
  }
  #{ $prefix }--actions-right .form-actions {
    @include element-form-actions-right();
  }
} 

@mixin -form-item-state($selector, $color, $highlightColor) {
  &#{ $selector } {
    background-color: $highlightColor;
    // outline: get("item-outline-width") solid $highlightColor;
    box-shadow: 0 0 0 get("item-highlight-width") $highlightColor;
    label {
      color: color.get($color);
    }
    select,
    textarea,
    input:not([type="checkbox"]):not([type="radio"]) {
      border-color: color.get($color);
    }
  }
}