@use 'sass:map';
@use '../utils/animation.scss' as animation;
@use '../utils/constants.scss';
@use '../utils/mixins.scss' as mixins;
@use '../utils/tokens.scss' as tokens;
@use './badge.vars.scss' as vars;
@import '@viasat/beam-tokens/components/Badge';
@import '@viasat/beam-tokens/components/BadgeIndicator';

$badgeIndicatorBaseClass: '#{constants.$prefix}badge-indicator';
$ring-color: var(--#{constants.$prefix}comp-badge-indicator-ring-color, transparent);

$motion-duration: animation.duration('fast');

// `all 0s $snap-delay` snaps every box property at once; the entries after it win
// for transform and opacity (last match wins). Using `all` covers any property a
// future --hide-zero zeroes without editing this list.
@mixin collapse-transition($snap-delay) {
  transition: all 0s $snap-delay, transform $motion-duration ease,
    opacity $motion-duration ease;
}

$sizes: (
  'sm': (
    'size': tokens.$bm-comp-badge-indicator-size-sm,
    'font': tokens.$bm-comp-badge-indicator-typo-sm,
    'icon': tokens.$bm-comp-badge-indicator-size-icon-sm,
    'marker': tokens.$bm-comp-badge-indicator-size-marker-sm,
  ),
  'md': (
    'size': tokens.$bm-comp-badge-indicator-size-md,
    'font': tokens.$bm-comp-badge-indicator-typo-md,
    'icon': tokens.$bm-comp-badge-indicator-size-icon-md,
    'marker': tokens.$bm-comp-badge-indicator-size-marker-md,
  ),
);

// Marker medium uses mute-ramp tokens; strong falls through to the shared color loop below.
$markerMediumBg: (
  'positive': tokens.$bm-comp-badge-indicator-color-marker-positive-medium-bg,
  'warning': tokens.$bm-comp-badge-indicator-color-marker-warning-medium-bg,
  'negative': tokens.$bm-comp-badge-indicator-color-marker-negative-medium-bg,
  'infoPrimary': tokens.$bm-comp-badge-indicator-color-marker-info-primary-medium-bg,
  'infoSecondary':
    tokens.$bm-comp-badge-indicator-color-marker-info-secondary-medium-bg,
  'accent': tokens.$bm-comp-badge-indicator-color-marker-accent-medium-bg,
);

.#{$badgeIndicatorBaseClass} {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: tokens.$bm-comp-badge-indicator-radius;
  border-style: solid;
  border-width: tokens.$bm-comp-badge-border-width;
  padding-inline: tokens.$bm-comp-badge-indicator-space-x;
  overflow: hidden;
  white-space: nowrap;
  outline: tokens.$bm-sem-border-width-lg solid $ring-color;
  outline-offset: 0;

  // min-width equals height so single-digit counts remain circular (not oval).
  @each $size-name, $size in $sizes {
    &--#{$size-name} {
      height: map.get($size, 'size');
      min-width: map.get($size, 'size');
      font: map.get($size, 'font');

      .#{$badgeIndicatorBaseClass}__icon {
        width: map.get($size, 'icon');
        height: map.get($size, 'icon');
      }

      &.#{$badgeIndicatorBaseClass}--marker {
        width: map.get($size, 'marker');
        height: map.get($size, 'marker');
        min-width: unset;
      }

      &.#{$badgeIndicatorBaseClass}--icon {
        width: map.get($size, 'size');
        min-width: unset;
      }
    }
  }

  &--marker,
  &--icon {
    padding: 0;
  }

  &--marker {
    font: unset;
    overflow: visible;

    @each $appearance, $bg in $markerMediumBg {
      &.#{$badgeIndicatorBaseClass}--#{$appearance}.#{$badgeIndicatorBaseClass}--medium {
        background-color: $bg;
        border-color: transparent;
      }
    }
  }

  // Sizes the icon: Beam SVGs have no intrinsic width/height and fill this
  // wrapper. Width/height per size are set in the size modifiers above.
  &__icon {
    display: inline-flex;
  }

  &__label {
    @include mixins.visually-hidden;
  }

  // Transition lives on --collapsible, not the base class, so marker, icon, and
  // plain count carry none. No `transform: scale(1)` at rest: an identity
  // transform creates a stacking context and can blur text; CSS already reads a
  // missing transform as scale(1) when interpolating.
  &--collapsible {
    @include collapse-transition(0s);

    // Delayed so the badge finishes animating out before the box snaps to 0.
    &.#{$badgeIndicatorBaseClass}--hide-zero {
      @include collapse-transition($motion-duration);
    }
  }

  // opacity (not visibility/display) is intentional: it keeps the element in
  // layout as a zero-size box and keeps the role="status" region in the
  // accessibility tree, so screen readers still announce the drop to 0 and the return.
  &--hide-zero {
    transform: scale(0);
    opacity: 0;
    width: 0;
    min-width: 0;
    height: 0;
    min-height: 0;
    padding: 0;
    border-width: 0;
  }

  // Both selectors are needed: --collapsible (0,1,0) can't override the
  // --collapsible.--hide-zero (0,2,0) rule declared outside this query.
  @media (prefers-reduced-motion: reduce) {
    &--collapsible,
    &--collapsible.#{$badgeIndicatorBaseClass}--hide-zero {
      transition: none;
    }
  }

  // Color data (6 appearances × 3 emphases) is sourced from the shared
  // badge.vars.scss map so Badge and BadgeIndicator stay in sync.
  // Applies to all kinds (count, icon, marker-strong); marker-medium is overridden above.
  @each $appearance-name, $emphases in vars.$badgeColors {
    &--#{$appearance-name} {
      @each $emphasis-name, $c in $emphases {
        &.#{$badgeIndicatorBaseClass}--#{$emphasis-name} {
          background-color: map.get($c, bg);
          color: map.get($c, fg);
          border-color: map.get($c, border);
        }
      }
    }
  }
}
