@use 'sass:map';
@use '@mezzanine-ui/system/palette' as palette;
@use '@mezzanine-ui/system/spacing' as spacing;
@use '@mezzanine-ui/system/radius' as radius;
@use '@mezzanine-ui/system/effect' as effect;
@use '@mezzanine-ui/system/transition' as transition;
@use '@mezzanine-ui/system/typography' as typography;
@use '../icon';
@use './text-field' as *;

$state-default: (
  default: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, neutral-light),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: none,
  ),
  hover: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, brand),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: none,
  ),
  typing: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, brand),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: effect.variable(focus, primary),
  ),
  focus: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
     border-color: palette.semantic-variable(border, brand),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: effect.variable(focus, primary),
  ),
  disabled: (
    text-color: palette.semantic-variable(text, neutral-light),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, neutral-subtle),
    border-color: palette.semantic-variable(border, neutral-light),
    icon-color: palette.semantic-variable(icon, neutral-light),
    focus-color: none,
  ),
  readonly: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, neutral-subtle),
    border-color: palette.semantic-variable(border, neutral-light),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: none,
  ),
);

$state-error: (
  default: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, error-subtle),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: none,
  ),
  hover: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, error),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: none,
  ),
  typing: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, error),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: effect.variable(focus, error),
  ),
  focus: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, error),
    icon-color: palette.semantic-variable(icon, neutral),
    focus-color: effect.variable(focus, error),
  ),
);

$state-warning: (
  default: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, warning-subtle),
    focus-color: none,
  ),
  hover: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, warning),
    focus-color: none,
  ),
  typing: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, warning),
    focus-color: effect.variable(focus, warning),
  ),
  focus: (
    text-color: palette.semantic-variable(text, neutral-solid),
    placeholder-color: palette.semantic-variable(text, neutral-light),
    background-color: palette.semantic-variable(background, base),
    border-color: palette.semantic-variable(border, warning),
    focus-color: effect.variable(focus, warning),
  )
);

$state-hierarchy: (
  default: $state-default,
  error: $state-error,
  warning: $state-warning,
);

$size-configs: (
  main: (
    padding-y: spacing.semantic-variable(padding, vertical, calm),
    padding-x: spacing.semantic-variable(padding, horizontal, cozy),
    typography: input,
    icon-size: 16px,
  ),
  sub: (
    padding-y: spacing.semantic-variable(padding, vertical, tight),
    padding-x: spacing.semantic-variable(padding, horizontal, cozy),
    typography: input,
    icon-size: 16px,
  ),
);

@function _get-state-color($severity, $state, $property) {
  $severity-map: map.get($state-hierarchy, $severity);

  @if $severity-map {
    $state-map: map.get($severity-map, $state);

    @if $state-map {
      $value: map.get($state-map, $property);

      @if $value == none {
        @return null;
      } @else {
        @return $value;
      }
    }
  }

  @return null;
}

@mixin _apply-state-colors($severity, $state) {
  $text: _get-state-color($severity, $state, text-color);
  $placeholder: _get-state-color($severity, $state, placeholder-color);
  $bg: _get-state-color($severity, $state, background-color);
  $border: _get-state-color($severity, $state, border-color);
  $icon: _get-state-color($severity, $state, icon-color);
  $focus: _get-state-color($severity, $state, focus-color);

  @if $text {
    color: $text;
  }

  @if $placeholder {
    --#{$prefix}-placeholder-color: #{$placeholder};
  }

  @if $bg {
    background-color: $bg;
  }

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

  @if $icon {
    --#{$prefix}-icon-color: #{$icon};
  }

  @if $focus {
    box-shadow: $focus;
  }
}

@mixin _apply-severity-states($severity, $include-readonly-disabled: true) {
  @include _apply-state-colors($severity, default);

  &:hover:not(.#{$prefix}--disabled):not(.#{$prefix}--readonly):not(.#{$prefix}--typing) {
    @include _apply-state-colors($severity, hover);
  }

  &:has(*:focus-visible):not(.#{$prefix}--disabled):not(.#{$prefix}--readonly):not(.#{$prefix}--typing) {
    @include _apply-state-colors($severity, focus);
  }

  &.#{$prefix}--typing,
  &.#{$prefix}--active {
    @include _apply-state-colors($severity, typing);
  }

  @if $include-readonly-disabled {
    &.#{$prefix}--readonly {
      @include _apply-state-colors($severity, readonly);
    }

    &.#{$prefix}--disabled {
      @include _apply-state-colors($severity, disabled);
    }
  }
}

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

  @if $config {
    --#{$prefix}-icon-size: #{typography.px-to-rem(map.get($config, icon-size))};

    @include typography.semantic-variable(map.get($config, typography));

    padding: map.get($config, padding-y) map.get($config, padding-x);
  }
}

.#{$prefix} {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: spacing.semantic-variable(gap, base);
  width: auto;
  border: 1px solid transparent;
  border-radius: radius.variable(base);
  caret-color: palette.semantic-variable(text, brand);
  transition:
    transition.standard(background-color, fast),
    transition.standard(border-color, fast),
    transition.standard(color, fast),
    transition.standard(box-shadow, fast);
  will-change: background-color, border-color, color, box-shadow;
  box-sizing: border-box;

  &--slim-gap {
    gap: spacing.semantic-variable(gap, slim);
  }

  &--full-width {
    width: 100%;
  }

  input,
  textarea {
    flex: 1;
    font: inherit;
    margin: 0;
    background-color: transparent;
    border: none;
    color: inherit;
    outline: none;
    box-sizing: border-box;
    caret-color: palette.semantic-variable(text, neutral-solid);
  }

  @each $size-name, $size-config in $size-configs {
    &__input-padding--#{$size-name} {
      padding: map.get($size-config, padding-y) map.get($size-config, padding-x);
    }
  }

  *::placeholder,
  &__placeholder {
    color: var(--#{$prefix}-placeholder-color);
  }

  &__prefix,
  &__suffix {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: spacing.semantic-variable(gap, tiny);
    color: palette.semantic-variable(text, neutral);

    @include typography.semantic-variable(input);

    .#{icon.$prefix} {
      font-size: var(--#{$prefix}-icon-size);
      color: var(--#{$prefix}-icon-color);
      transition: transition.standard(color, fast);
      will-change: color;
    }
  }

  &:has(.#{$prefix}__prefix) {
    padding-left: spacing.semantic-variable(padding, horizontal, cozy);
  }

  &:has(.#{$prefix}__suffix) {
    padding-right: spacing.semantic-variable(padding, horizontal, cozy);
  }

  &--mono-input {
    input,
    textarea {
      @include typography.semantic-variable(input-mono);
    }
  }

  &--tiny-gap {
    gap: spacing.semantic-variable(padding, horizontal, tiny);

    &:has(.#{$prefix}__suffix) {
      padding-right: spacing.semantic-variable(padding, horizontal, micro);
    }
  }

  &__clear-icon {
    opacity: 0;
    pointer-events: none;
    transition: transition.standard(opacity, fast);

    .#{icon.$prefix} {
      font-size: var(--#{$prefix}-icon-size);
    }
  }

  &--clearing {
    & > .#{$prefix}__clear-icon {
      opacity: 1;
      pointer-events: auto;
    }

    .#{$prefix}__suffix--overlay {
      .#{$prefix}__suffix-content {
        opacity: 0;
        pointer-events: none;
      }

      .#{$prefix}__clear-icon {
        opacity: 1;
        pointer-events: auto;
      }
    }
  }

  &__suffix--overlay {
    display: grid;

    .#{$prefix}__suffix-content,
    .#{$prefix}__clear-icon {
      grid-area: 1 / 1;
    }
  }

  &__suffix-content {
    line-height: 0;
    transition: transition.standard(opacity, fast);
  }

  &--disabled {
    cursor: not-allowed;
    pointer-events: none;
  }

  &--readonly {
    cursor: default;

    input,
    textarea {
      cursor: default;
    }
  }

  @each $size-name, $size-config in $size-configs {
    &--#{$size-name} {
      @include _apply-size($size-name);
    }
  }

  @include _apply-severity-states(default);

  &--error {
    @include _apply-severity-states(error, $include-readonly-disabled: false);
  }

  &--warning:not(&--error) {
    @include _apply-severity-states(warning, $include-readonly-disabled: false);
  }

  &--no-padding {
    padding: 0;
  }
}
