@use 'sass:map';
@use '../utils/constants.scss';
@use '../utils/mixins.scss' as mixins;
@use '../utils/tokens.scss' as tokens;

@import '@viasat/beam-tokens/components/Panel';

$panelBaseClass: '#{constants.$prefix}panel';
$panelOffsetXVar: '--#{constants.$prefix}comp-panel-offset-x';
$panelOffsetYVar: '--#{constants.$prefix}comp-panel-offset-y';
$panelWidthVar: '--#{constants.$prefix}comp-panel-width';
$panelHeightVar: '--#{constants.$prefix}comp-panel-height';
$panel-transition-duration: 0.4s;
$panel-max-height: 90dvh;

$panel-widths: (
  'sm': tokens.$bm-comp-panel-size-sm,
  'md': tokens.$bm-comp-panel-size-md,
  'lg': tokens.$bm-comp-panel-size-lg,
);

.#{$panelBaseClass} {
  display: flex;
  flex-direction: column;

  background-color: tokens.$bm-comp-panel-color-bg;

  &--inline {
    position: relative;
    height: 100%;
    box-shadow: tokens.$bm-sem-shadow-none;
  }

  &--overlay {
    position: fixed;
    z-index: 999;
    box-shadow: tokens.$bm-comp-panel-shadow;
    overscroll-behavior: contain;
    overflow: auto;

    &.#{$panelBaseClass}--position-start {
      left: 0;
      top: 0;
      bottom: 0;
      // Cap to the viewport so the panel never bleeds off a screen narrower than its width.
      width: min(var(#{$panelWidthVar}, #{tokens.$bm-comp-panel-size-md}), 100dvw);
    }

    &.#{$panelBaseClass}--position-end {
      right: 0;
      top: 0;
      bottom: 0;
      // Cap to the viewport so the panel never bleeds off a screen narrower than its width.
      width: min(var(#{$panelWidthVar}, #{tokens.$bm-comp-panel-size-md}), 100dvw);
    }

    &.#{$panelBaseClass}--position-bottom {
      bottom: 0;
      left: 0;
      right: 0;
      height: var(#{$panelHeightVar}, auto);
      max-height: var(#{$panelHeightVar}, #{$panel-max-height});
    }

    &.#{$panelBaseClass}--contained {
      position: absolute;
    }

    &.#{$panelBaseClass}--floating {
      border-radius: tokens.$bm-comp-panel-radius;

      $floating-positions: (
        'start': (
          'x': (
            'left',
          ),
          'y': (
            'top',
            'bottom',
          ),
        ),
        'end': (
          'x': (
            'right',
          ),
          'y': (
            'top',
            'bottom',
          ),
        ),
        'bottom': (
          'x': (
            'left',
            'right',
          ),
          'y': (
            'bottom',
          ),
        ),
      );

      @each $position, $axes in $floating-positions {
        &.#{$panelBaseClass}--position-#{$position} {
          @each $edge in map.get($axes, 'x') {
            #{$edge}: var(#{$panelOffsetXVar}, 1rem);
          }

          @each $edge in map.get($axes, 'y') {
            #{$edge}: var(#{$panelOffsetYVar}, 1rem);
          }

          @if $position == 'bottom' {
            width: auto;
          } @else {
            // Floating start/end sit inset by the offset; cap to the viewport minus both
            // offsets so the panel still fits (with its gap) on screens narrower than its width.
            width: min(
              var(#{$panelWidthVar}, #{tokens.$bm-comp-panel-size-md}),
              100dvw - 2 * var(#{$panelOffsetXVar}, 1rem)
            );
          }
        }
      }
    }
  }

  @each $name, $value in $panel-widths {
    &--width-#{$name} {
      #{$panelWidthVar}: $value;
    }
  }

  // Applies to both inline and overlay bottom panels:
  &--position-bottom {
    width: 100%;
    height: auto;

    > .#{$panelBaseClass}__body {
      // Needed so the body can shrink and scroll within a capped height
      min-height: 0;
    }
  }

  &--padding-sm {
    .#{$panelBaseClass}__header {
      padding-left: tokens.$bm-comp-panel-space-x-sm;
      padding-right: tokens.$bm-comp-panel-space-x-sm;
    }

    .#{$panelBaseClass}__body {
      padding-left: tokens.$bm-comp-panel-space-x-sm;
      padding-right: tokens.$bm-comp-panel-space-x-sm;
    }

    .#{$panelBaseClass}__footer {
      padding-left: tokens.$bm-comp-panel-space-x-sm;
      padding-right: tokens.$bm-comp-panel-space-x-sm;
    }
  }

  &--padding-md {
    .#{$panelBaseClass}__header {
      padding-left: tokens.$bm-comp-panel-space-x-md;
      padding-right: tokens.$bm-comp-panel-space-x-md;
    }

    .#{$panelBaseClass}__body {
      padding-left: tokens.$bm-comp-panel-space-x-md;
      padding-right: tokens.$bm-comp-panel-space-x-md;
    }

    .#{$panelBaseClass}__footer {
      padding-left: tokens.$bm-comp-panel-space-x-md;
      padding-right: tokens.$bm-comp-panel-space-x-md;
    }
  }

  &__header {
    display: flex;
    flex-direction: column;
    gap: tokens.$bm-comp-panel-space-header-gap-y;

    padding-top: tokens.$bm-comp-panel-space-header-pad-top;
    padding-bottom: tokens.$bm-comp-panel-space-header-pad-bottom;

    &__row {
      display: flex;
      gap: tokens.$bm-comp-panel-space-header-gap-x;
      align-items: flex-start;
    }

    &__content-before {
      display: flex;
      flex-direction: row;
      gap: tokens.$bm-comp-panel-space-header-gap-x;
    }

    &__content-after {
      display: flex;
      gap: tokens.$bm-comp-panel-space-header-gap-x;
      align-items: flex-start;
    }

    &__heading {
      flex: 1;

      font: tokens.$bm-comp-panel-typo-heading;
      color: tokens.$bm-comp-panel-color-heading;
    }

    &__description {
      font: tokens.$bm-comp-panel-typo-description;
      color: tokens.$bm-comp-panel-color-description;
    }

    &__close-button {
      width: tokens.$bm-sem-size-icon-lg;
      height: tokens.$bm-sem-size-icon-lg;
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }

  &__body {
    flex: 1;
    overflow: auto;

    font: tokens.$bm-sem-typo-body-sm;
    color: tokens.$bm-sem-color-text-primary;
  }

  &__footer {
    display: flex;
    gap: tokens.$bm-comp-panel-space-footer-gap-actions;
    flex-direction: column;
    padding-top: tokens.$bm-comp-panel-space-footer-pad-top;
    padding-bottom: tokens.$bm-comp-panel-space-footer-pad-bottom;

    &__actions {
      display: flex;
      gap: tokens.$bm-comp-panel-space-footer-gap-actions;
      flex-shrink: 0;
      flex-wrap: wrap;
      align-items: center;
      align-content: center;

      &--start {
        justify-content: flex-start;
      }

      &--end {
        justify-content: flex-end;
      }

      &--spaceBetween {
        justify-content: space-between;
      }

      &--stacked {
        justify-content: center;
        flex-direction: column;
        gap: tokens.$bm-comp-panel-space-footer-gap-actions-stack;
      }
    }
  }

  &__overlay-divider {
    position: absolute;

    &--start {
      right: 0;
      top: 0;
      bottom: 0;
    }

    &--end {
      left: 0;
      top: 0;
      bottom: 0;
    }

    &--bottom {
      top: 0;
      left: 0;
      right: 0;
    }
  }

  &__resize-handle {
    position: absolute;
    opacity: 0;
    z-index: 100;
    transition: opacity 0.2s ease-in-out;

    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }

    &:hover,
    &:active {
      opacity: 1;
    }
  }

  // Inline resizable: aside fills animated wrapper width
  &--inline#{&}--resizable {
    width: 100%;
  }

  // Inline bottom: let --bm-comp-panel-height drive height (overrides shared height: auto).
  // No max-height cap here — inline panels are bounded by their flex container, not the viewport
  // (unlike overlay bottom which applies a 90dvh soft cap via $panel-max-height).
  &--inline#{&}--position-bottom {
    height: var(#{$panelHeightVar}, auto);
  }

  // Pin start/end inline content while the wrapper animates width.
  &--inline:not(#{&}--resizable):not(#{&}--position-bottom) {
    width: var(#{$panelWidthVar}, #{tokens.$bm-comp-panel-size-md});
  }
}

$panelResizeHandleSize: 0.75rem;

$resize-handle-positions: (
  'start': (
    cursor: col-resize,
    size-prop: width,
    stretch: inset-block,
    placement: inset-inline-end,
    border-side: inline-end,
  ),
  'end': (
    cursor: col-resize,
    size-prop: width,
    stretch: inset-block,
    placement: inset-inline-start,
    border-side: inline-start,
  ),
  'bottom': (
    cursor: row-resize,
    size-prop: height,
    stretch: inset-inline,
    placement: inset-block-start,
    border-side: block-start,
  ),
);

@each $pos, $cfg in $resize-handle-positions {
  .#{$panelBaseClass}--resizable.#{$panelBaseClass}--position-#{$pos} {
    .#{$panelBaseClass}__resize-handle {
      cursor: map.get($cfg, cursor);
      #{map.get($cfg, size-prop)}: $panelResizeHandleSize;
      #{map.get($cfg, stretch)}: 0;
      #{map.get($cfg, placement)}: 0;
      border-#{map.get($cfg, border-side)}-width: tokens.$bm-sem-border-width-md;
      border-#{map.get($cfg, border-side)}-style: solid;
      border-#{map.get($cfg, border-side)}-color: tokens.$bm-sem-color-border-selected;

      &:hover,
      &:active {
        border-#{map.get($cfg, border-side)}-width: tokens.$bm-sem-border-width-lg;
      }
    }
  }
}

@mixin panel-slide($prop, $hidden, $visible, $duration: $panel-transition-duration) {
  #{$prop}: $hidden;
  &[data-status='open'] {
    transition: $prop $duration ease-out, box-shadow $duration ease-out;
    #{$prop}: $visible;
    box-shadow: tokens.$bm-comp-panel-shadow;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }
  // Fade the shadow out in sync with the slide-out so it doesn't snap off instantly
  // while the panel is still animating away. The box-shadow must live in this same
  // (higher-specificity) rule as the transform transition, otherwise the transform
  // shorthand resets transition-property and the shadow stops animating.
  &[data-status='close'] {
    transition: $prop $duration ease-in, box-shadow $duration ease-in;
    box-shadow: tokens.$bm-sem-shadow-none;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }
}

.#{$panelBaseClass}--overlay[data-position='start'] {
  @include panel-slide(transform, translateX(-100%), translateX(0));
}

.#{$panelBaseClass}--overlay[data-position='end'] {
  @include panel-slide(transform, translateX(100%), translateX(0));
}

.#{$panelBaseClass}--overlay[data-position='bottom'] {
  @include panel-slide(transform, translateY(100%), translateY(0));
}

.#{$panelBaseClass}__inline-wrapper {
  overflow: hidden;
  flex-shrink: 0;

  @each $name, $value in $panel-widths {
    &--width-#{$name} {
      #{$panelWidthVar}: $value;
    }
  }

  &[data-status] {
    width: 0;
    transition: width $panel-transition-duration ease-in;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }

  &[data-status='open'] {
    width: var(#{$panelWidthVar}, #{tokens.$bm-comp-panel-size-md});
    transition: width $panel-transition-duration ease-out;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }

  &[data-position='bottom'][data-status] {
    width: 100%;
    transition: none; // bottom animates via translateY on the content, not width
  }

  &[data-position='bottom'][data-status]
    .#{$panelBaseClass}__inline-wrapper-content {
    transform: translateY(100%);
    transition: transform $panel-transition-duration ease-in;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }

  &[data-position='bottom'][data-status='open']
    .#{$panelBaseClass}__inline-wrapper-content {
    transform: translateY(0);
    transition: transform $panel-transition-duration ease-out;
    @media (prefers-reduced-motion: reduce) {
      transition: none;
    }
  }
}

.#{$panelBaseClass}__inline-wrapper-content {
  height: 100%;
}
