<template>
  <div
    ref="container"
    class="malio-wheel relative h-[160px] 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-8 w-full snap-center items-center justify-center leading-none outline-none transition-all"
      :class="itemClass(item.flat)"
      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 = 32
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 buffer = computed(() =>
  [0, 1, 2].flatMap((copy) =>
    props.values.map((value, i) => {
      const flat = copy * props.values.length + i
      return {value, flat, key: flat}
    }),
  ),
)

// Taille décroissante avec la distance au centre (effet molette iOS).
const itemClass = (flat: number) => {
  const distance = Math.abs(flat - (props.values.length + centeredIndex.value))
  if (distance === 0) return 'text-[16px] font-medium text-black'
  if (distance === 1) return 'text-[14px] text-m-muted'
  return 'text-[12px] text-m-muted'
}

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

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

<style scoped>
.malio-wheel {
  scrollbar-width: none;
  /* Estompe les valeurs en haut et en bas (effet molette iOS) pour qu'elles ne
     débordent pas visuellement du cadre. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 30%, #000 70%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 30%, #000 70%, transparent 100%);
}
.malio-wheel::-webkit-scrollbar {
  display: none;
}
</style>
