<template>
  <div class="cpSegmentedControl" :class="segmentedControlDynamicClasses">
    <div class="cpSegmentedControl__options">
      <template v-for="(option, index) in options" :key="option.value">
        <cp-segmented-control-item
          :option="option"
          :name="name"
          :is-disabled="isDisabled"
          :is-full-width="isFullWidth"
          :is-invalid="isInvalid"
          :is-selected="isSelected(index)"
          :orientation="orientation"
          v-model="selectedValue"
          :size="size"
          @mouseenter="handleOptionMouseEnter(index)"
          @mouseleave="handleOptionMouseLeave"
          @focusin="handleOptionFocusIn(index)"
          @focusout="handleOptionFocusOut"
        />
        <div
          v-if="!isLastOption(index)"
          class="cpSegmentedControl__divider"
          :class="getDynamicDividerClasses(index)"
          aria-hidden="true"
        />
      </template>
    </div>
  </div>
</template>

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

import { capitalizeFirstLetter } from '@/helpers'
import CpSegmentedControlItem from './CpSegmentedControlItem.vue'

interface Option {
  label: string
  leadingIcon?: string
  trailingIcon?: string
  value: string
}

interface Props {
  isDisabled?: boolean
  isFullWidth?: boolean
  isInvalid?: boolean
  name: string
  options: Option[]
  orientation?: 'horizontal' | 'vertical'
  size?: 'sm' | 'md'
}

const props = withDefaults(defineProps<Props>(), {
  size: 'md',
  orientation: 'horizontal',
})

const segmentedControlDynamicClasses = computed(() => ({
  'cpSegmentedControl--isInvalid': props.isInvalid,
  'cpSegmentedControl--fullWidth': props.isFullWidth,
  'cpSegmentedControl--isDisabled': props.isDisabled,
  [`cpSegmentedControl--is${capitalizeFirstLetter(props.orientation)}`]: true,
}))

const selectedValue = defineModel<string | undefined>()
const hoveredIndex = ref<number | null>(null)
const focusedIndex = ref<number | null>(null)

const isSelected = (index: number) => index === selectedIndex.value

const isLastOption = (index: number) => index === props.options.length - 1

const selectedIndex = computed(() => {
  if (selectedValue.value === undefined) return -1

  return props.options.findIndex((option) => option.value === selectedValue.value)
})

const setAdjacentDividerIndexes = (indexes: Set<number>, optionIndex: number) => {
  if (optionIndex < 0) return

  if (optionIndex > 0) {
    indexes.add(optionIndex - 1)
  }

  if (optionIndex < props.options.length - 1) {
    indexes.add(optionIndex)
  }
}

const selectedDividerIndexes = computed(() => {
  const indexes = new Set<number>()

  setAdjacentDividerIndexes(indexes, selectedIndex.value)

  if (focusedIndex.value !== null) {
    setAdjacentDividerIndexes(indexes, focusedIndex.value)
  }

  return indexes
})

const hoveredDividerIndexes = computed(() => {
  const indexes = new Set<number>()

  if (
    hoveredIndex.value !== null
    && hoveredIndex.value !== selectedIndex.value
    && hoveredIndex.value !== focusedIndex.value
  ) {
    setAdjacentDividerIndexes(indexes, hoveredIndex.value)
  }

  return indexes
})

const getDynamicDividerClasses = (index: number) => {
  const isActive = selectedDividerIndexes.value.has(index)

  return {
    'cpSegmentedControl__divider--isActive': isActive,
    'cpSegmentedControl__divider--isHovered': !isActive && hoveredDividerIndexes.value.has(index),
  }
}

const handleOptionMouseEnter = (index: number) => {
  if (props.isDisabled) return

  hoveredIndex.value = index
}

const handleOptionMouseLeave = () => (hoveredIndex.value = null)

const handleOptionFocusIn = (index: number) => {
  if (props.isDisabled) return

  focusedIndex.value = index
}

const handleOptionFocusOut = () => (focusedIndex.value = null)
</script>

<style lang="scss">
.cpSegmentedControl {
  width: fit-content;
  min-width: 0;
  max-width: 100%;

  &--fullWidth {
    width: 100%;
  }

  &__options {
    display: flex;
    width: 100%;
    min-width: 0;
    border-radius: var(--cp-radius-md);
    box-shadow: var(--cp-shadows-3xs);
  }

  &__divider {
    width: fn.px-to-rem(1);
    flex-shrink: 0;
    align-self: stretch;
    background-color: var(--cp-border-soft);
    transition: background-color 100ms ease;

    &--isHovered {
      background-color: var(--cp-border-soft-hover);
    }

    &--isActive {
      position: relative;
      z-index: 5;
      background-color: var(--cp-border-accent-solid);
    }
  }

  &--isInvalid {
    .cpSegmentedControl__divider {
      background-color: var(--cp-border-error-solid);
    }

    .cpSegmentedControl__divider--isHovered,
    .cpSegmentedControl__divider--isActive {
      background-color: var(--cp-border-error-solid);
    }
  }

  &--isDisabled {
    .cpSegmentedControl__divider,
    .cpSegmentedControl__divider--isHovered,
    .cpSegmentedControl__divider--isActive {
      background-color: var(--cp-border-disabled);
    }
  }

  &--isVertical {
    .cpSegmentedControl__options {
      flex-direction: column;
    }

    .cpSegmentedControl__divider {
      width: 100%;
      height: fn.px-to-rem(1);
    }
  }
}
</style>
