<template>
  <button
    :aria-disabled="disabled"
    :aria-pressed="isSelected"
    class="cpSelectableButton"
    :class="dynamicClasses"
    :disabled="disabled"
    type="button"
    @click="emit('click', $event)"
  >
    <div class="cpSelectableButton__body">
      <span v-if="showLeadingIcon" class="cpSelectableButton__icon cpSelectableButton__icon--isBefore">
        <slot name="leading-icon" />
      </span>
      <span v-if="showText" class="cpSelectableButton__label">
        <slot>
          {{ label }}
        </slot>
      </span>
      <span v-if="showTrailingIcon" class="cpSelectableButton__icon cpSelectableButton__icon--isAfter">
        <slot name="trailing-icon" />
      </span>
    </div>
  </button>
</template>

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

import { capitalizeFirstLetter } from '@/helpers'

type SelectableButtonAppearance = 'primary' | 'secondary' | 'tertiary' | 'quaternary' | 'inverse'
type SelectableButtonSize = 'xs' | '2xs' | '3xs' | 'sm' | 'md'

interface Props {
  appearance?: SelectableButtonAppearance
  disabled?: boolean
  isExpanded?: boolean
  isSelected?: boolean
  label?: string
  size?: SelectableButtonSize
}

const props = withDefaults(defineProps<Props>(), {
  size: 'md',
  appearance: 'primary',
  label: '',
  disabled: false,
  isSelected: false,
  isExpanded: false,
})

const emit = defineEmits<{
  click: [event: MouseEvent]
}>()

const slots = useSlots()

const showLeadingIcon = computed(() => !!slots['leading-icon'])
const showText = computed(() => !!props.label || !!slots.default)
const showTrailingIcon = computed(() => !!slots['trailing-icon'])
const isIconOnly = computed(() => !props.label && !slots.default)

const dynamicClasses = computed(() => {
  return [
    `cpSelectableButton--${props.size}`,
    `cpSelectableButton--is${capitalizeFirstLetter(props.appearance)}`,
    {
      'cpSelectableButton--isSelected': props.isSelected,
      'cpSelectableButton--isExpanded': props.isExpanded,
      'cpSelectableButton--isDisabled': props.disabled,
      'cpSelectableButton--isIconOnly': isIconOnly.value,
    },
  ]
})
</script>

<style lang="scss">
.cpSelectableButton {
  display: inline-flex;
  padding: var(--cp-selectable-border-padding);
  border-radius: var(--cp-selectable-border-radius);
  background-color: var(--cp-selectable-background-color);
  box-shadow:
    var(--cp-selectable-box-shadow),
    0 0 0 var(--cp-dimensions-0_25) var(--cp-selectable-border-color);
  color: var(--cp-selectable-text-color);
  font-size: var(--cp-selectable-font-size);
  font-weight: 500;
  line-height: var(--cp-selectable-line-height);
  transition:
    background-color 0.1s ease-out,
    box-shadow 0.1s ease-out,
    color 0.1s ease-out,
    transform 0.15s ease-out;

  &:focus-visible {
    outline: var(--cp-dimensions-0_5) solid var(--cp-background-accent-solid);
    outline-offset: var(--cp-dimensions-0_25);
  }

  &__body {
    display: inline-flex;
    width: 100%;
    align-items: center;
    justify-content: center;
    padding: var(--cp-selectable-body-padding);
    border-radius: var(--cp-selectable-body-border-radius);
    background-color: var(--cp-selectable-body-background-color);
    gap: var(--cp-selectable-body-gap);
    transition:
      background-color 0.1s ease-out,
      box-shadow 0.1s ease-out,
      color 0.1s ease-out;
  }

  &--isDisabled {
    background-color: var(--cp-background-disabled);
    box-shadow: var(--cp-shadows-3xs);
    color: var(--cp-text-disabled);
    cursor: not-allowed;
    transform: none;

    & > .cpSelectableButton__body {
      background-color: var(--cp-background-disabled);
      color: var(--cp-text-disabled);
      cursor: not-allowed;
    }
  }

  &:hover:not(.cpSelectableButton--isDisabled) {
    background-color: var(--cp-selectable-background-color-hover);
    box-shadow:
      var(--cp-selectable-box-shadow),
      0 0 0 var(--cp-dimensions-0_25) var(--cp-selectable-border-color-hover);
    color: var(--cp-selectable-text-color-hover);

    & > .cpSelectableButton__body {
      background-color: var(--cp-selectable-body-background-color-hover);
    }
  }

  &:active:not(.cpSelectableButton--isDisabled) {
    transform: scale3d(0.97, 0.97, 1);
  }

  &__icon i,
  &__icon svg {
    width: var(--cp-selectable-icon-size);
    height: var(--cp-selectable-icon-size);
    flex-shrink: 0;
    aspect-ratio: 1 / 1;
  }

  --cp-selectable-border-padding: var(--cp-spacing-sm);
  --cp-selectable-border-radius: var(--cp-radius-md);
  --cp-selectable-font-size: var(--cp-text-size-md);
  --cp-selectable-line-height: var(--cp-line-height-md);
  --cp-selectable-body-padding: var(--cp-spacing-sm) var(--cp-spacing-sm-md);
  --cp-selectable-body-gap: var(--cp-spacing-sm-md);
  --cp-selectable-body-border-radius: var(--cp-radius-sm);
  --cp-selectable-icon-size: var(--cp-dimensions-5);
  --cp-selectable-border-color: transparent;
  --cp-selectable-border-color-hover: transparent;
  --cp-selectable-text-color: var(--cp-foreground-white);
  --cp-selectable-text-color-hover: var(--cp-foreground-white);
  --cp-selectable-background-color: var(--cp-background-accent-solid);
  --cp-selectable-background-color-hover: var(--cp-background-accent-solid-hover);
  --cp-selectable-body-background-color: var(--cp-background-accent-solid);
  --cp-selectable-body-background-color-hover: var(--cp-background-accent-solid-hover);
  --cp-selectable-box-shadow: var(--cp-shadows-3xs-inset);

  &.cpSelectableButton--isIconOnly {
    --cp-selectable-body-padding: var(--cp-spacing-sm-md);
  }

  &--sm {
    --cp-selectable-border-padding: var(--cp-spacing-sm);
    --cp-selectable-border-radius: var(--cp-radius-md);
    --cp-selectable-font-size: var(--cp-text-size-sm);
    --cp-selectable-line-height: var(--cp-line-height-sm);
    --cp-selectable-body-padding: var(--cp-spacing-xs) var(--cp-spacing-sm);
    --cp-selectable-body-gap: var(--cp-spacing-sm);
    --cp-selectable-body-border-radius: var(--cp-radius-sm);
    --cp-selectable-icon-size: var(--cp-dimensions-4);
  }

  &--sm.cpSelectableButton--isIconOnly {
    --cp-selectable-body-padding: var(--cp-spacing-sm);
  }

  &--xs {
    $radius: fn.px-to-rem(5);

    --cp-selectable-border-padding: var(--cp-spacing-xs);
    --cp-selectable-border-radius: var(--cp-radius-md);
    --cp-selectable-font-size: var(--cp-text-size-sm);
    --cp-selectable-line-height: var(--cp-line-height-sm);
    --cp-selectable-body-padding: var(--cp-spacing-xs) var(--cp-spacing-sm);
    --cp-selectable-body-gap: var(--cp-spacing-sm);
    --cp-selectable-body-border-radius: #{$radius};
    --cp-selectable-icon-size: var(--cp-dimensions-4);
  }

  &--xs.cpSelectableButton--isIconOnly {
    --cp-selectable-body-padding: var(--cp-spacing-sm);
  }

  &--2xs {
    --cp-selectable-border-padding: var(--cp-spacing-xs);
    --cp-selectable-border-radius: var(--cp-radius-sm-md);
    --cp-selectable-font-size: var(--cp-text-size-xs);
    --cp-selectable-line-height: var(--cp-line-height-xs);
    --cp-selectable-body-padding: var(--cp-spacing-xs) var(--cp-spacing-sm);
    --cp-selectable-body-gap: var(--cp-spacing-sm);
    --cp-selectable-body-border-radius: var(--cp-radius-sm);
    --cp-selectable-icon-size: var(--cp-dimensions-3_5);
  }

  &--2xs.cpSelectableButton--isIconOnly {
    --cp-selectable-body-padding: var(--cp-spacing-sm);
  }

  &--3xs {
    --cp-selectable-border-padding: var(--cp-spacing-none);
    --cp-selectable-border-radius: var(--cp-radius-sm);
    --cp-selectable-font-size: var(--cp-text-size-xs);
    --cp-selectable-line-height: var(--cp-line-height-xs);
    --cp-selectable-body-padding: var(--cp-spacing-xs) var(--cp-spacing-sm);
    --cp-selectable-body-gap: var(--cp-spacing-sm);
    --cp-selectable-body-border-radius: var(--cp-radius-sm);
    --cp-selectable-icon-size: var(--cp-dimensions-3);
  }

  &--3xs.cpSelectableButton--isIconOnly {
    --cp-selectable-body-padding: var(--cp-spacing-sm);
  }

  &--isSelected {
    --cp-selectable-border-color: transparent;
    --cp-selectable-border-color-hover: transparent;
    --cp-selectable-text-color: var(--cp-foreground-white);
    --cp-selectable-text-color-hover: var(--cp-foreground-white);
    --cp-selectable-background-color: var(--cp-background-accent-solid);
    --cp-selectable-background-color-hover: var(--cp-background-accent-solid-hover);
    --cp-selectable-body-background-color: var(--cp-utility-accent-600);
    --cp-selectable-body-background-color-hover: var(--cp-utility-accent-700);
  }

  &--isExpanded {
    --cp-selectable-border-color: transparent;
    --cp-selectable-border-color-hover: transparent;
    --cp-selectable-text-color: var(--cp-foreground-white);
    --cp-selectable-text-color-hover: var(--cp-foreground-white);
    --cp-selectable-background-color: var(--cp-utility-accent-600);
    --cp-selectable-background-color-hover: var(--cp-utility-accent-700);
    --cp-selectable-body-background-color: transparent;
    --cp-selectable-body-background-color-hover: transparent;
  }

  &--isSecondary {
    --cp-selectable-border-color: var(--cp-border-soft);
    --cp-selectable-border-color-hover: var(--cp-border-soft-hover);
    --cp-selectable-text-color: var(--cp-foreground-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-primary);
    --cp-selectable-background-color: var(--cp-background-primary);
    --cp-selectable-background-color-hover: var(--cp-background-primary-hover);
    --cp-selectable-body-background-color: transparent;
    --cp-selectable-body-background-color-hover: transparent;
    --cp-selectable-box-shadow: var(--cp-shadows-3xs-inset);
  }

  &--isSecondary:is(&--isSelected) {
    --cp-selectable-border-color: var(--cp-border-soft);
    --cp-selectable-border-color-hover: var(--cp-border-soft);
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: var(--cp-background-primary);
    --cp-selectable-background-color-hover: var(--cp-background-primary);
    --cp-selectable-body-background-color: var(--cp-background-accent-secondary);
    --cp-selectable-body-background-color-hover: var(--cp-background-accent-secondary-hover);

    &.cpSelectableButton--3xs {
      --cp-selectable-border-color: var(--cp-border-accent-primary);
      --cp-selectable-border-color-hover: var(--cp-border-accent-primary-hover);
    }
  }

  &--isSecondary:is(&--isExpanded) {
    --cp-selectable-border-color: var(--cp-border-accent-solid);
    --cp-selectable-border-color-hover: var(--cp-border-accent-solid);
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: var(--cp-background-primary);
    --cp-selectable-background-color-hover: var(--cp-background-primary);
    --cp-selectable-body-background-color: var(--cp-background-accent-secondary);
    --cp-selectable-body-background-color-hover: var(--cp-background-accent-secondary-hover);
  }

  &--isTertiary {
    --cp-selectable-border-color: transparent;
    --cp-selectable-border-color-hover: transparent;
    --cp-selectable-text-color: var(--cp-foreground-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-primary);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: var(--cp-background-primary-hover);
    --cp-selectable-body-background-color: transparent;
    --cp-selectable-body-background-color-hover: transparent;
    --cp-selectable-box-shadow: transparent;
  }

  &--isTertiary:is(&--isSelected) {
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: transparent;
  }

  &--isTertiary:is(&--isExpanded) {
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: var(--cp-background-accent-secondary);
    --cp-selectable-background-color-hover: var(--cp-background-accent-secondary-hover);
  }

  &--isQuaternary {
    --cp-selectable-border-color: transparent;
    --cp-selectable-border-color-hover: transparent;
    --cp-selectable-text-color: var(--cp-foreground-secondary);
    --cp-selectable-text-color-hover: var(--cp-foreground-primary);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: var(--cp-background-primary-hover);
    --cp-selectable-body-background-color: transparent;
    --cp-selectable-body-background-color-hover: transparent;
    --cp-selectable-box-shadow: transparent;
  }

  &--isQuaternary:is(&--isSelected) {
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: transparent;
  }

  &--isQuaternary:is(&--isExpanded) {
    --cp-selectable-text-color: var(--cp-foreground-accent-primary);
    --cp-selectable-text-color-hover: var(--cp-foreground-accent-primary-hover);
    --cp-selectable-background-color: var(--cp-background-accent-secondary);
    --cp-selectable-background-color-hover: var(--cp-background-accent-secondary-hover);
  }

  &--isInverse {
    --cp-selectable-border-color: transparent;
    --cp-selectable-border-color-hover: transparent;
    --cp-selectable-text-color: var(--cp-foreground-white);
    --cp-selectable-text-color-hover: var(--cp-foreground-white);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: color-mix(in sRGB, var(--cp-background-white) 10%, transparent);
    --cp-selectable-body-background-color: transparent;
    --cp-selectable-body-background-color-hover: transparent;
    --cp-selectable-box-shadow: var(--cp-shadows-3xs-inset);
  }

  &--isInverse:is(&--isSelected) {
    --cp-selectable-border-color: color-mix(in sRGB, var(--cp-background-white) 20%, transparent);
    --cp-selectable-border-color-hover: color-mix(in sRGB, var(--cp-background-white) 20%, transparent);
    --cp-selectable-text-color: var(--cp-foreground-white);
    --cp-selectable-text-color-hover: var(--cp-foreground-white);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: transparent;
    --cp-selectable-body-background-color: color-mix(in sRGB, var(--cp-background-white) 20%, transparent);
    --cp-selectable-body-background-color-hover: color-mix(in sRGB, var(--cp-background-white) 30%, transparent);
  }

  &--isInverse:is(&--isExpanded) {
    --cp-selectable-border-color: var(--cp-border-white);
    --cp-selectable-border-color-hover: var(--cp-border-white);
    --cp-selectable-text-color: var(--cp-foreground-white);
    --cp-selectable-text-color-hover: var(--cp-foreground-white);
    --cp-selectable-background-color: transparent;
    --cp-selectable-background-color-hover: transparent;
    --cp-selectable-body-background-color: color-mix(in sRGB, var(--cp-background-white) 20%, transparent);
    --cp-selectable-body-background-color-hover: color-mix(in sRGB, var(--cp-background-white) 30%, transparent);
  }

  &__icon {
    display: flex;
    align-items: center;

    &:empty {
      display: none;
    }
  }

  &__label {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    padding: var(--cp-spacing-none) var(--cp-spacing-xs);
  }
}
</style>
