<template>
  <div class="cpBadge" :class="componentDynamicClasses">
    <slot name="leading-icon">
      <cp-icon v-if="leadingIcon" class="cpBadge__icon" :type="leadingIcon" />
    </slot>
    <span v-if="hasLabel" class="cpBadge__label">
      <slot>{{ label }}</slot>
    </span>
    <button v-if="isClearable" class="cpBadge__clear" :disabled="disabled" type="button" @click="emit('onClear')">
      <cp-icon class="cpBadge__clearIcon" type="x" />
    </button>
    <slot v-else name="trailing-icon">
      <cp-icon v-if="trailingIcon" class="cpBadge__icon" :type="trailingIcon" />
    </slot>
  </div>
</template>

<script setup lang="ts">
import { computed, useSlots } from 'vue'

import { capitalizeFirstLetter } from '@/helpers'

interface Props {
  color?: 'neutral' | 'accent' | 'error' | 'warning' | 'success' | 'blue' | 'pink' | 'magenta' | 'yellow' | 'white'
  disabled?: boolean
  isClearable?: boolean
  isSquare?: boolean
  label?: string
  leadingIcon?: string
  size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg'
  trailingIcon?: string
  variant?: 'outline' | 'soft' | 'solid'
}

const props = withDefaults(defineProps<Props>(), {
  isClearable: false,
  color: 'neutral',
  size: 'md',
  variant: 'soft',
  label: '',
  leadingIcon: '',
  trailingIcon: '',
})

const emit = defineEmits<{ onClear: [] }>()

const slots = useSlots()

const hasLabel = computed(() => !!props.label || !!slots.default)

const componentDynamicClasses = computed(() => [
  `cpBadge--${props.size}`,
  `cpBadge--is${capitalizeFirstLetter(props.color)}`,
  `cpBadge--is${capitalizeFirstLetter(props.variant)}`,
  { 'cpBadge--isSquare': props.isSquare },
  { 'cpBadge--isDisabled': props.disabled },
])
</script>

<style lang="scss">
@mixin cp-badge-sized(
  $size,
  $font-size,
  $line-height,
  $padding,
  $label-padding,
  $square-radius,
  $no-label-padding,
  $icon-width,
  $clear-icon-width
) {
  &--#{$size} {
    padding: $padding;
    font-size: $font-size;
    font-weight: 400;
    line-height: $line-height;

    &.cpBadge--isSquare {
      border-radius: $square-radius;
    }

    .cpBadge__label {
      padding-inline: $label-padding;
    }

    &:not(:has(.cpBadge__label)) {
      padding: $no-label-padding;
    }

    & .cpBadge__icon {
      width: $icon-width;
      aspect-ratio: 1/1;
    }

    & .cpBadge__clearIcon {
      width: $clear-icon-width;
      aspect-ratio: 1/1;
    }
  }
}

@mixin cp-badge-themed($className, $color, $bg-color, $solid-color, $solid-bg-color, $outline-color) {
  &--is#{$className} {
    background-color: $bg-color;
    color: $color;
    outline-color: $outline-color;

    &.cpBadge--isSolid {
      background-color: $solid-bg-color;
      color: $solid-color;
    }

    &.cpBadge--isOutline {
      box-shadow: 0 0 0 1px $outline-color;
    }

    .cpBadge__clear:not(:disabled):hover,
    .cpBadge__clear:not(:disabled):focus-visible {
      background-color: $color;
    }
  }
}

.cpBadge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--cp-radius-full);
  background-color: var(--cp-background-tertiary);
  gap: var(--cp-spacing-xs);

  &__label {
    white-space: nowrap;
  }

  @include cp-badge-sized(
    'lg',
    var(--cp-text-size-md),
    var(--cp-line-height-md),
    var(--cp-spacing-sm) var(--cp-spacing-md),
    var(--cp-spacing-sm),
    var(--cp-radius-md),
    var(--cp-spacing-sm-md),
    var(--cp-dimensions-5),
    var(--cp-dimensions-4_5)
  );
  @include cp-badge-sized(
    'md',
    var(--cp-text-size-sm),
    var(--cp-line-height-sm),
    var(--cp-spacing-sm) var(--cp-spacing-md),
    var(--cp-spacing-sm),
    var(--cp-radius-md),
    var(--cp-spacing-sm-md),
    var(--cp-dimensions-4),
    var(--cp-dimensions-3_5)
  );
  @include cp-badge-sized(
    'sm',
    var(--cp-text-size-xs),
    var(--cp-line-height-xs),
    var(--cp-spacing-sm) var(--cp-spacing-md),
    var(--cp-spacing-xs),
    var(--cp-radius-sm-md),
    var(--cp-spacing-sm),
    var(--cp-dimensions-4),
    var(--cp-dimensions-3_5)
  );
  @include cp-badge-sized(
    'xs',
    var(--cp-text-size-xs),
    var(--cp-line-height-xs),
    var(--cp-spacing-xs) var(--cp-spacing-sm-md),
    var(--cp-spacing-xs),
    var(--cp-radius-sm),
    var(--cp-spacing-sm),
    var(--cp-dimensions-3),
    var(--cp-dimensions-2_5)
  );
  @include cp-badge-sized(
    '2xs',
    var(--cp-text-size-xs),
    var(--cp-line-height-xs),
    var(--cp-spacing-none) var(--cp-spacing-sm),
    var(--cp-spacing-xs),
    var(--cp-radius-sm),
    var(--cp-spacing-xs),
    var(--cp-dimensions-3),
    var(--cp-dimensions-2_5)
  );
  @include cp-badge-themed(
    'Neutral',
    var(--cp-foreground-primary),
    var(--cp-background-tertiary),
    var(--cp-text-white),
    var(--cp-background-solid),
    var(--cp-border-strong)
  );
  @include cp-badge-themed(
    'Accent',
    var(--cp-foreground-accent-primary),
    var(--cp-background-accent-secondary),
    var(--cp-text-white),
    var(--cp-background-accent-solid),
    var(--cp-border-accent-primary)
  );
  @include cp-badge-themed(
    'Error',
    var(--cp-foreground-error-primary),
    var(--cp-background-error-secondary),
    var(--cp-text-white),
    var(--cp-background-error-solid),
    var(--cp-border-error-primary)
  );
  @include cp-badge-themed(
    'Warning',
    var(--cp-foreground-warning-primary),
    var(--cp-background-warning-secondary),
    var(--cp-text-white),
    var(--cp-background-warning-solid),
    var(--cp-border-warning-primary)
  );
  @include cp-badge-themed(
    'Success',
    var(--cp-foreground-success-primary),
    var(--cp-background-success-secondary),
    var(--cp-text-white),
    var(--cp-background-success-solid),
    var(--cp-border-success-primary)
  );
  @include cp-badge-themed(
    'Blue',
    var(--cp-foreground-blue-primary),
    var(--cp-background-blue-secondary),
    var(--cp-text-white),
    var(--cp-background-blue-solid),
    var(--cp-border-blue-primary)
  );
  @include cp-badge-themed(
    'Pink',
    var(--cp-foreground-pink-primary),
    var(--cp-background-pink-secondary),
    var(--cp-text-white),
    var(--cp-background-pink-solid),
    var(--cp-border-pink-primary)
  );
  @include cp-badge-themed(
    'Magenta',
    var(--cp-foreground-magenta-primary),
    var(--cp-background-magenta-secondary),
    var(--cp-text-white),
    var(--cp-background-magenta-solid),
    var(--cp-border-magenta-primary)
  );
  @include cp-badge-themed(
    'Yellow',
    var(--cp-foreground-yellow-primary),
    var(--cp-background-yellow-secondary),
    var(--cp-text-white),
    var(--cp-background-yellow-solid),
    var(--cp-border-yellow-primary)
  );
  @include cp-badge-themed(
    'White',
    var(--cp-foreground-primary),
    var(--cp-background-primary),
    var(--cp-text-primary),
    var(--cp-background-primary),
    var(--cp-border-soft)
  );
  @include cp-badge-themed(
    'Disabled',
    var(--cp-text-disabled),
    var(--cp-background-disabled),
    var(--cp-text-disabled),
    var(--cp-background-disabled),
    var(--cp-border-disabled)
  );

  &--isDisabled,
  &--isDisabled * {
    cursor: not-allowed;
  }

  &__clear {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--cp-dimensions-0_25);
    border-radius: var(--cp-radius-full);
    color: inherit;

    &:not(:disabled):hover,
    &:not(:disabled):focus-visible {
      color: var(--cp-foreground-white);
    }
  }
}
</style>
