<template>
  <div class="cpSelect" :class="dynamicClasses">
    <base-input-label
      v-if="label"
      class="cpSelect__label"
      :for="selectReferenceId"
      :is-invalid="isInvalid"
      :required="required"
      :tooltip="tooltip"
    >
      {{ capitalizedLabel }}
    </base-input-label>
    <div class="cpSelect__container">
      <select
        :id="selectReferenceId"
        v-model="selectModel"
        :autocomplete="autocomplete"
        class="cpSelect__inner"
        :disabled="disabled"
        :name="name"
        :required="required"
      >
        <option :disabled="hideDefaultValue" value="">{{ defaultValue }}</option>
        <option v-for="(option, index) in options" :key="index" :value="option.value">{{ option.label }}</option>
      </select>
    </div>
    <cp-transition-expand mode="out-in">
      <p v-if="displayErrorMessage" :id="errorMessageId" class="cpSelect__error">
        {{ errorMessage }}
      </p>
      <p v-else-if="displayHelp" :id="helpMessageId" class="cpSelect__help">
        {{ help }}
      </p>
    </cp-transition-expand>
  </div>
</template>

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

import type { Sizes } from '@/constants'

import BaseInputLabel from '@/components/BaseInputLabel.vue'
import CpTransitionExpand from '@/components/CpTransitionExpand.vue'

import { capitalizeFirstLetter } from '@/helpers'

interface SelectOption {
  label: string
  value: string | number
}

interface Props {
  autocomplete?: string
  defaultValue?: string
  disabled?: boolean
  errorMessage?: string
  help?: string
  hideDefaultValue?: boolean
  isInvalid?: boolean
  label?: string
  name?: string
  options: SelectOption[]
  required?: boolean
  size?: Sizes
  tooltip?: string
}

const props = withDefaults(defineProps<Props>(), {
  label: '',
  hideDefaultValue: false,
  defaultValue: 'Select an option',
  name: undefined,
  required: false,
  disabled: false,
  autocomplete: 'on',
  isInvalid: false,
  errorMessage: '',
  size: 'md',
  help: '',
  tooltip: '',
})

const selectModel = defineModel<string | number>()

const selectReferenceId = useId()
const helpMessageId = useId()
const errorMessageId = useId()

const capitalizedLabel = computed(() => capitalizeFirstLetter(props.label))

const dynamicClasses = computed(() => {
  return [
    `cpSelect--${props.size}`,
    {
      'cpSelect--isInvalid': props.isInvalid,
      'cpSelect--isDisabled': props.disabled,
    },
  ]
})

const displayHelp = computed(() => props.help?.length && !displayErrorMessage.value)
const displayErrorMessage = computed(() => props.isInvalid && props.errorMessage.length)
</script>

<style lang="scss">
.cpSelect {
  position: relative;

  &__container {
    position: relative;

    &::after {
      position: absolute;
      top: 50%;
      right: var(--cp-dimensions-3);
      width: var(--cp-dimensions-4);
      height: var(--cp-dimensions-4);
      background-color: var(--cp-foreground-secondary);
      content: '';
      mask-image: url('@/assets/images/icons/chevron-down-icon.svg');
      mask-repeat: no-repeat;
      mask-size: cover;
      pointer-events: none;
      transform: translateY(-50%);
    }
  }

  &:has(.cpSelect__help, .cpSelect__error) .cpSelect__container {
    margin-bottom: var(--cp-spacing-md);
  }

  &__inner {
    @extend %u-text-ellipsis;

    width: 100%;
    padding: var(--cp-spacing-md)
      calc(var(--cp-spacing-lg) + var(--cp-spacing-sm) + var(--cp-dimensions-4) + var(--cp-spacing-md))
      var(--cp-spacing-md) var(--cp-spacing-xl);
    border: none;
    border-radius: var(--cp-radius-md);
    appearance: none;
    background-color: var(--cp-background-primary);
    box-shadow:
      var(--cp-shadows-3xs),
      0 0 0 var(--cp-dimensions-0_25) var(--cp-border-soft);
    color: var(--cp-foreground-primary);
    cursor: pointer;
    font-size: var(--cp-text-size-sm);
    line-height: var(--cp-line-height-md);

    &:hover {
      box-shadow:
        var(--cp-shadows-3xs),
        0 0 0 var(--cp-dimensions-0_25) var(--cp-border-soft-hover);
    }

    &:focus {
      background-color: var(--cp-background-primary);
      outline: var(--cp-dimensions-0_5) solid var(--cp-focus);
    }
  }

  &__help,
  &__error {
    font-size: var(--cp-text-size-sm);
    line-height: var(--cp-line-height-md);
  }

  &__help {
    color: var(--cp-text-secondary);
  }

  &__error {
    color: var(--cp-foreground-error-primary);

    &::first-letter {
      text-transform: capitalize;
    }
  }

  &--isDisabled {
    .cpSelect__inner {
      background: var(--cp-background-disabled);
      box-shadow: 0 0 0 var(--cp-dimensions-0_25) var(--cp-border-disabled);
    }

    .cpSelect__inner,
    .cpSelect__container::after {
      color: var(--cp-text-disabled);
      cursor: not-allowed;
      opacity: 1;
    }

    .cpSelect__container::after {
      background-color: var(--cp-foreground-disabled);
    }
  }

  &--sm {
    .cpSelect__inner {
      padding: var(--cp-spacing-sm) calc(var(--cp-spacing-2xl) + var(--cp-dimensions-3)) var(--cp-spacing-sm)
        var(--cp-spacing-lg);
    }
  }

  &--lg {
    .cpSelect__inner {
      padding: var(--cp-spacing-lg) calc(var(--cp-spacing-xl) + var(--cp-dimensions-5) + var(--cp-spacing-sm))
        var(--cp-spacing-lg) var(--cp-spacing-xl);
      border-radius: var(--cp-radius-md-lg);
      font-size: var(--cp-text-size-md);
    }

    .cpSelect__container::after {
      width: var(--cp-dimensions-5);
      height: var(--cp-dimensions-5);
    }
  }

  &--isInvalid {
    .cpSelect__inner,
    .cpSelect__inner:hover,
    .cpSelect__inner:focus {
      box-shadow: 0 0 0 var(--cp-dimensions-0_25) var(--cp-border-error-solid);
    }

    .cpSelect__inner:focus {
      outline: var(--cp-dimensions-0_5) solid var(--cp-border-error-solid);
    }
  }
}
</style>
