<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { computed, ref, onMounted, watch, nextTick } from 'vue'
import { cn } from '@/lib/utils'

export interface SlidingToggleOption {
  value: string
  icon?: string
  label?: string
}

const props = defineProps<{
  modelValue: string
  options: SlidingToggleOption[]
  class?: HTMLAttributes['class']
}>()

const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()

const buttonRefs = ref<HTMLButtonElement[]>([])
const indicatorWidth = ref(0)
const indicatorOffset = ref(0)

const activeIndex = computed(() => props.options.findIndex((opt) => opt.value === props.modelValue))

function updateIndicator() {
  const index = activeIndex.value
  if (index < 0 || !buttonRefs.value[index]) return

  const button = buttonRefs.value[index]
  indicatorWidth.value = button.offsetWidth
  indicatorOffset.value = button.offsetLeft
}

const indicatorStyle = computed(() => ({
  width: `${indicatorWidth.value}px`,
  transform: `translateX(${indicatorOffset.value}px)`,
}))

function selectOption(value: string) {
  if (value !== props.modelValue) {
    emit('update:modelValue', value)
  }
}

onMounted(() => {
  nextTick(updateIndicator)
})

watch(activeIndex, () => {
  nextTick(updateIndicator)
})
</script>

<template>
  <div
    :class="
      cn('relative flex flex-1 items-center gap-1 rounded-md h-[36px] border bg-background shadow-xs', props.class)
    "
  >
    <!-- Sliding Indicator -->
    <div
      class="absolute h-9 bg-primary dark:bg-primary/80 transition-all duration-200 ease-out"
      :class="{
        'rounded-tl rounded-bl': activeIndex === 0,
        'rounded-tr rounded-br': activeIndex === options.length - 1,
      }"
      :style="indicatorStyle"
    />

    <!-- Option Buttons -->
    <button
      v-for="(option, index) in options"
      :key="option.value"
      :ref="
        (el) => {
          if (el) buttonRefs[index] = el as HTMLButtonElement
        }
      "
      type="button"
      :class="[
        'flex-1 relative z-10 flex items-center justify-center gap-1.5 rounded-sm px-2 text-sm transition-colors',
        option.value === modelValue ? 'text-white' : 'text-foreground hover:text-primary/90 dark:text-white/60 dark:hover:text-white',
      ]"
      @click="selectOption(option.value)"
    >
      <i v-if="option.icon" :class="`${option.icon}-16 shrink-0`" />
      <span v-if="option.label">{{ option.label }}</span>
    </button>
  </div>
</template>
