<template>
  <div class="cpMenuItem">
    <button
      class="cpMenuItem__button"
      :class="dynamicClass"
      :disabled="disabled"
      type="button"
      @click.stop="handleItemClick"
    >
      <transition :duration="100" mode="out-in" name="fade">
        <span v-if="isLoading" class="cpMenuItem__loaderWrapper">
          <cp-loader class="cpMenuItem__loader" color="accent" size="2xs" />
        </span>
        <slot v-else-if="hasLeadingIcon" name="leading-icon">
          <cp-icon :aria-label="ariaLabel" class="cpMenuItem__icon" size="16" :type="leadingIcon" />
        </slot>
      </transition>
      <span v-if="hasLabel" v-tooltip="tooltip" class="cpMenuItem__label">{{ label }}</span>
      <slot v-if="hasTrailingIcon" name="trailing-icon">
        <cp-icon :aria-label="ariaLabel" class="cpMenuItem__icon" size="16" :type="trailingIcon" />
      </slot>
    </button>
  </div>
</template>

<script setup lang="ts">
import type { MenuItem } from 'primevue/menuitem'
import { computed, useSlots } from 'vue'

interface Props {
  hideLabel?: boolean
  isAsync?: boolean
  isCritical?: boolean
  isLoading?: boolean
  isSelected?: boolean
  leadingIcon?: string
  tooltip?: string
  trailingIcon?: string
}

const props = withDefaults(defineProps<Props & Omit<MenuItem, 'class' | 'key' | 'icon'>>(), {
  label: '',
  tooltip: '',
  command: undefined,
  leadingIcon: undefined,
  trailingIcon: undefined,
  isSelected: false,
  hideLabel: false,
})

const emit = defineEmits(['click', 'asyncComplete'])

const slots = useSlots()

const dynamicClass = computed(() => ({
  'cpMenuItem__button--isCritical': props.isCritical,
  'cpMenuItem__button--isSelected': props.isSelected,
}))

const disabled = computed(() => props.isLoading || props.disabled)
const hasLeadingIcon = computed(() => !!props.leadingIcon || !!slots['leading-icon'])
const hasTrailingIcon = computed(() => !!props.trailingIcon || !!slots['trailing-icon'])
const hasLabel = computed(() => (!!props.label || !!slots.label) && !props.hideLabel)
const ariaLabel = computed(() => (props.hideLabel ? props.label : undefined))

const handleItemClick = async (event: Event) => {
  if (props.command) {
    if (props.isAsync) {
      await props.command(event)
      emit('asyncComplete')
    } else {
      props.command(event)
    }
  }

  emit('click')
}
</script>

<style lang="scss">
.cpMenuItem {
  padding: 0 var(--cp-spacing-sm);

  &__button {
    @extend %u-focus-outline;
    @extend %u-text-ellipsis;

    --cp-menu-item-background-color: var(--cp-background-primary);
    --cp-menu-item-background-color-hover: var(--cp-background-primary-hover);
    --cp-menu-item-color: var(--cp-text-primary);
    --cp-menu-item-color-hover: var(--cp-text-primary);

    position: relative;
    display: flex;
    width: 100%;
    align-items: center;
    padding: var(--cp-spacing-sm-md) var(--cp-spacing-md);
    background-color: var(--cp-menu-item-background-color);
    color: var(--cp-menu-item-color);
    font-size: var(--cp-text-size-sm);
    gap: var(--cp-spacing-lg);
    line-height: var(--cp-line-height-sm);
    text-align: start;
    transition:
      background-color 100ms ease-in-out,
      color 100ms ease-in-out;

    &:hover,
    &:focus-visible {
      background-color: var(--cp-menu-item-background-color-hover);
      color: var(--cp-menu-item-color-hover);
    }

    &:disabled {
      --cp-menu-item-background-color-hover: var(--cp-background-primary);
      --cp-menu-item-color: var(--cp-text-disabled);
      --cp-menu-item-color-hover: var(--cp-text-disabled);

      cursor: not-allowed;
    }

    &--isCritical:not(:disabled) {
      --cp-menu-item-background-color-hover: var(--cp-background-error-primary-hover);
      --cp-menu-item-color: var(--cp-foreground-error-primary);
      --cp-menu-item-color-hover: var(--cp-foreground-error-primary-hover);
    }

    &--isSelected:not(:disabled) {
      --cp-menu-item-background-color: var(--cp-background-accent-primary);
      --cp-menu-item-background-color-hover: var(--cp-background-accent-primary);
      --cp-menu-item-color: var(--cp-text-accent-primary);
      --cp-menu-item-color-hover: var(--cp-text-accent-primary-hover);
    }
  }

  &__label {
    flex: 1;
  }

  // Useful not to shift the layout on loading
  &__loaderWrapper {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  &__icon {
    padding: var(--cp-spacing-xs);
  }
}
</style>
