<template>
  <div
    ref="container"
    class="malio-wheel relative h-[200px] w-14 snap-y snap-mandatory overflow-y-scroll"
    role="spinbutton"
    :tabindex="0"
    :aria-label="ariaLabel"
    :aria-valuenow="modelValue"
    :aria-valuemin="values[0]"
    :aria-valuemax="values[values.length - 1]"
    :aria-valuetext="pad(modelValue)"
    @keydown="onKeydown"
  >
    <button
      v-for="item in buffer"
      :key="item.key"
      type="button"
      data-test="wheel-item"
      class="flex h-10 w-full snap-center items-center justify-center text-lg outline-none transition-colors"
      :class="item.value === centeredValue ? 'font-bold text-black' : 'text-m-muted'"
      tabindex="-1"
      @click="onItemClick(item.value)"
    >
      {{ pad(item.value) }}
    </button>
  </div>
</template>

<script setup lang="ts">
import {computed, ref, watch} from 'vue'
import {useInfiniteWheel} from '../composables/useInfiniteWheel'
import {padSegment} from '../composables/timeFormat'

defineOptions({name: 'MalioTimeWheel', inheritAttrs: false})

const props = defineProps<{
  modelValue: number
  values: number[]
  ariaLabel: string
}>()

const emit = defineEmits<{(e: 'update:modelValue', value: number): void}>()

const ITEM_HEIGHT = 40
const container = ref<HTMLElement | null>(null)

const pad = (value: number) => padSegment(value)
const indexOfValue = (value: number) => Math.max(0, props.values.indexOf(value))

const {centeredIndex, scrollToIndex, onKeydown} = useInfiniteWheel(container, {
  length: props.values.length,
  itemHeight: ITEM_HEIGHT,
  initialIndex: () => indexOfValue(props.modelValue),
  onChange: (index) => emit('update:modelValue', props.values[index]),
})

const centeredValue = computed(() => props.values[centeredIndex.value])

const buffer = computed(() =>
  [0, 1, 2].flatMap((copy) =>
    props.values.map((value) => ({value, key: copy * props.values.length + value})),
  ),
)

const onItemClick = (value: number) => scrollToIndex(indexOfValue(value))

watch(
  () => props.modelValue,
  (value) => {
    if (props.values[centeredIndex.value] !== value) scrollToIndex(indexOfValue(value), false)
  },
)
</script>

<style scoped>
.malio-wheel {
  scrollbar-width: none;
}
.malio-wheel::-webkit-scrollbar {
  display: none;
}
</style>
