@use 'sass:map';
@use '@mezzanine-ui/system/typography' as typography;
@use '@mezzanine-ui/system/spacing' as spacing;
@use '@mezzanine-ui/system/palette' as palette;
@use '@mezzanine-ui/system/motion' as motion;
@use '@mezzanine-ui/system/radius' as radius;
@use '@mezzanine-ui/system/z-index' as z-index;
@use './spin' as *;

$size-configs: (
  main: (
    typography: body-highlight,
    ring-size: spacing.semantic-variable(size, element, extra),
    stroke-width: 4px,
    padding-x: spacing.semantic-variable(padding, horizontal, none),
    padding-y: spacing.semantic-variable(padding, vertical, none),
    gap: spacing.semantic-variable(gap, comfort),
    radius: radius.variable(none),
  ),
  sub: (
    typography: body-highlight,
    ring-size: spacing.semantic-variable(size, element, airy),
    stroke-width: 3px,
    padding-x: spacing.semantic-variable(padding, horizontal, none),
    padding-y: spacing.semantic-variable(padding, vertical, none),
    gap: spacing.semantic-variable(gap, calm),
    radius: radius.variable(none),
  ),
  minor: (
    typography: label-primary,
    ring-size: spacing.semantic-variable(size, element, base-fixed),
    stroke-width: 2px,
    padding-x: spacing.semantic-variable(padding, horizontal, none),
    padding-y: spacing.semantic-variable(padding, vertical, none),
    gap: spacing.semantic-variable(gap, tight-fixed),
    radius: radius.variable(none),
  ),
);

@mixin _apply-size($size, $variant: null) {
  $config: map.get($size-configs, $size);

  @if $config {
    $typography: map.get($config, typography);
    $ring-size: map.get($config, ring-size);
    $stroke-width: map.get($config, stroke-width);
    $padding-x: map.get($config, padding-x);
    $padding-y: map.get($config, padding-y);
    $gap: map.get($config, gap);
    $radius: map.get($config, radius);

    @if $typography {
      .#{$prefix}__spin__description {
        @include typography.semantic-variable($typography);

        color: palette.semantic-variable(text, neutral);
      }
    }

    @if $ring-size {
      .#{$prefix}__spin__ring {
        --mzn-spin--stroke-width: #{$stroke-width};

        width: $ring-size;
        height: $ring-size;
      }
    }

    @if $padding-x != null and $padding-y != null {
      padding: $padding-y $padding-x;
    }

    @if $gap {
      gap: $gap;
    }

    @if $radius {
      border-radius: $radius;
    }
  }
}

@mixin _full-container() {
  width: 100%;
  height: 100%;
}

@keyframes mzn-spin-ring {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes mzn-spin-tail {
  0%   { transform: rotate(-135deg); }
  50%  { transform: rotate(0deg); }
  100% { transform: rotate(225deg); }
}

@keyframes mzn-spin-tail-before {
  0%   { transform: rotate(0deg); }
  50%  { transform: rotate(105deg); }
  100% { transform: rotate(0deg); }
}

@keyframes mzn-spin-tail-after {
  0%   { transform: rotate(0deg); }
  50%  { transform: rotate(225deg); }
  100% { transform: rotate(0deg); }
}

.#{$prefix} {
  position: relative;
  overflow: hidden;

  &--stretch {
    @include _full-container();
  }

  div.#{$prefix}__spin {
    position: relative;
    // z-index must larger than overlay
    z-index: z-index.get(popover);

    @include _full-container();
  }
}

.#{$prefix}__spin {
  box-sizing: border-box;
  display: flex;
  flex-flow: column;
  align-items: center;
  justify-content: center;

  @each $size in $sizes {
    &--#{$size} {
      @include _apply-size($size);
    }
  }

  &--minor {
    flex-flow: row;
  }

  &__ring {
    --mzn-spin--stroke-width: 3px;

    position: relative;
    flex-shrink: 0;
    border-radius: 50%;
    mask-image: radial-gradient(
      closest-side,
      transparent calc(100% - var(--mzn-spin--stroke-width) - 1px),
      white       calc(100% - var(--mzn-spin--stroke-width)) calc(100% - 1px),
      transparent 100%
    );
    // Use fallback values so ancestor elements can override via CSS cascade.
    // --mzn-spin--color controls the animated arc; --mzn-spin--track-color controls the ring background.
    background-color: var(--mzn-spin--track-color, transparent);
    color: var(--mzn-spin--color, #{palette.semantic-variable(icon, brand)});
    animation: mzn-spin-ring motion.duration(loop) linear infinite;
  }

  &__tail {
    position: absolute;
    display: block;
    width: 100%;
    height: 100%;
    mask-image: conic-gradient(transparent 105deg, white 105deg);
    animation: mzn-spin-tail motion.duration(loop) motion.easing(entrance) infinite;

    &::before,
    &::after {
      content: '';
      position: absolute;
      display: block;
      width: 100%;
      height: 100%;
      animation: inherit;
      background-image: conic-gradient(currentcolor 135deg, transparent 135deg);
    }

    &::before {
      animation-name: mzn-spin-tail-before;
    }

    &::after {
      animation-name: mzn-spin-tail-after;
    }
  }
}
