//
// Copyright 2021 Google LLC
// SPDX-License-Identifier: Apache-2.0
//

// go/keep-sorted start
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
// go/keep-sorted end
// go/keep-sorted start
@use '../../tokens';
// go/keep-sorted end

$_md-sys-motion: tokens.md-sys-motion-values();

@mixin theme($tokens) {
  $supported-tokens: list.join(
    tokens.$md-comp-filled-field-supported-tokens,
    (
      'container-shape-start-start',
      'container-shape-start-end',
      'container-shape-end-end',
      'container-shape-end-start'
    )
  );

  @each $token, $value in $tokens {
    @if list.index($supported-tokens, $token) == null {
      @error 'Token `#{$token}` is not a supported token.';
    }

    @if $token == 'container-shape' and meta.type-of($value) == 'list' {
      @error 'Filled field `container-shape` may not be specified as a list. Use logical (`*-start-start`) tokens instead.';
    }

    @if $value {
      --md-filled-field-#{$token}: #{$value};
    }
  }
}

@mixin styles() {
  $tokens: tokens.md-comp-filled-field-values();

  @layer styles {
    :host {
      // Only use the logical properties.
      $tokens: map.remove($tokens, 'container-shape');
      @each $token, $value in $tokens {
        --_#{$token}: #{$value};
      }
    }

    .background,
    .state-layer {
      border-radius: inherit;
      inset: 0;
      pointer-events: none;
      position: absolute;
    }

    .background {
      background: var(--_container-color);
    }

    .state-layer {
      visibility: hidden;
    }

    .field:not(.disabled):hover .state-layer {
      visibility: visible;
    }

    .label.floating {
      position: absolute;
      top: var(--_with-label-top-space);
    }

    .field:not(.with-start) .label-wrapper {
      margin-inline-start: var(--_leading-space);
    }

    .field:not(.with-end) .label-wrapper {
      margin-inline-end: var(--_trailing-space);
    }

    .active-indicator {
      inset: auto 0 0 0;
      // Prevent click events on the indicator element since it has no width and
      // causes bugs when handled by the foundation for updating transform-origin.
      pointer-events: none;
      position: absolute;
      width: 100%;
      z-index: 1;

      &::before,
      &::after {
        border-bottom: var(--_active-indicator-height) solid
          var(--_active-indicator-color);
        inset: auto 0 0 0;
        content: '';
        position: absolute;
        width: 100%;
      }

      // focused indicator
      &::after {
        opacity: 0;
        transition: opacity map.get($_md-sys-motion, 'duration-short3')
          map.get($_md-sys-motion, 'easing-emphasized');
      }
    }

    .focused .active-indicator::after {
      opacity: 1;
    }

    .field:not(.with-start) .content ::slotted(*) {
      padding-inline-start: var(--_leading-space);
    }

    .field:not(.with-end) .content ::slotted(*) {
      padding-inline-end: var(--_trailing-space);
    }

    .field:not(.no-label) .content ::slotted(:not(textarea)) {
      padding-bottom: var(--_with-label-bottom-space);
      padding-top: calc(
        var(--_with-label-top-space) + var(--_label-text-populated-line-height)
      );
    }

    .field:not(.no-label) .content ::slotted(textarea) {
      // Use margin for textareas since they will scroll over the label if not.
      margin-bottom: var(--_with-label-bottom-space);
      margin-top: calc(
        var(--_with-label-top-space) + var(--_label-text-populated-line-height)
      );
    }

    :hover .active-indicator::before {
      border-bottom-color: var(--_hover-active-indicator-color);
      border-bottom-width: var(--_hover-active-indicator-height);
    }

    // Focus is on a separate element and does not need a focus selector
    .active-indicator::after {
      border-bottom-color: var(--_focus-active-indicator-color);
      border-bottom-width: var(--_focus-active-indicator-height);
    }

    :hover .state-layer {
      background: var(--_hover-state-layer-color);
      opacity: var(--_hover-state-layer-opacity);
    }

    .disabled .active-indicator::before {
      border-bottom-color: var(--_disabled-active-indicator-color);
      border-bottom-width: var(--_disabled-active-indicator-height);
      opacity: var(--_disabled-active-indicator-opacity);
    }

    .disabled .background {
      background: var(--_disabled-container-color);
      opacity: var(--_disabled-container-opacity);
    }

    .error .active-indicator::before {
      border-bottom-color: var(--_error-active-indicator-color);
    }

    .error:hover .active-indicator::before {
      border-bottom-color: var(--_error-hover-active-indicator-color);
    }

    .error:hover .state-layer {
      background: var(--_error-hover-state-layer-color);
      opacity: var(--_error-hover-state-layer-opacity);
    }

    // Focus is on a separate element and does not need a focus selector
    .error .active-indicator::after {
      border-bottom-color: var(--_error-focus-active-indicator-color);
    }

    // Move the container up so that the resize handle doesn't overlap the focus
    // indicator. Content is moved back the opposite direction.
    .resizable .container {
      bottom: var(--_focus-active-indicator-height);
      // Ensures the container doesn't create an overhang that can be clicked on.
      clip-path: inset(var(--_focus-active-indicator-height) 0 0 0);
    }

    .resizable .container > * {
      top: var(--_focus-active-indicator-height);
    }
  }

  @layer hcm {
    @media (forced-colors: active) {
      .disabled .active-indicator::before {
        border-color: GrayText;
        opacity: 1;
      }
    }
  }
}
