<script setup lang="ts">
import type { SliderRootEmits, SliderRootProps } from "reka-ui"
import type { HTMLAttributes } from "vue"
import type { SliderVariants } from "."
import { computed } from "vue"
import { reactiveOmit } from "@vueuse/core"
import {
  SliderRange,
  SliderRoot,
  SliderThumb,
  SliderTrack,
  useForwardPropsEmits,
} from "reka-ui"
import { cn } from "@/lib/utils"
import { sliderThumbVariants, sliderTrackVariants, sliderVariants } from "."

export interface SliderProps extends /* @vue-ignore */ Omit<SliderRootProps, "modelValue" | "orientation"> {
  /** Size variant: sm, default, lg. */
  size?: SliderVariants["size"]
  /** Layout direction. Horizontal by default. */
  orientation?: SliderVariants["orientation"]
  /** Minimum value. */
  min?: number
  /** Maximum value. */
  max?: number
  /** Step increment. */
  step?: number
  /** Disable interaction. */
  disabled?: boolean
  /** Inverts the direction the thumb travels. */
  inverted?: boolean
  /** Minimum distance between thumbs in a range slider. */
  minStepsBetweenThumbs?: number
  /** Additional classes merged via tailwind-merge. */
  class?: HTMLAttributes["class"]
}

const props = withDefaults(defineProps<SliderProps>(), {
  size: "default",
  orientation: "horizontal",
})

const emits = defineEmits<SliderRootEmits>()

const modelValue = defineModel<number[] | number>("modelValue")

const delegatedProps = reactiveOmit(
  props,
  "class",
  "size",
  "orientation",
  "modelValue" as never,
)

const orientation = computed<"horizontal" | "vertical">(() =>
  props.orientation === "vertical" ? "vertical" : "horizontal",
)

const forwarded = useForwardPropsEmits(delegatedProps, emits)

const normalizedValue = computed<number[] | undefined>({
  get() {
    const val = modelValue.value
    if (val === undefined || val === null) {
      return undefined
    }
    return Array.isArray(val) ? val : [val]
  },
  set(next) {
    if (next === undefined) {
      modelValue.value = next
      return
    }
    // Preserve the consumer's original shape (single number vs array).
    if (typeof modelValue.value === "number" && next.length === 1) {
      modelValue.value = next[0] as number
    }
    else {
      modelValue.value = next
    }
  },
})

const thumbValues = computed<readonly unknown[]>(() => {
  const val = normalizedValue.value
  if (!val || val.length === 0) {
    return [0]
  }
  return val
})
</script>

<template>
  <SliderRoot
    v-model="normalizedValue"
    v-bind="forwarded"
    :orientation="orientation"
    :class="cn(sliderVariants({ size, orientation }), props.class)"
  >
    <SliderTrack :class="sliderTrackVariants({ size })">
      <SliderRange
        class="absolute bg-primary data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
      />
    </SliderTrack>
    <SliderThumb
      v-for="(_, key) in thumbValues"
      :key="key"
      :class="sliderThumbVariants({ size })"
    />
  </SliderRoot>
</template>
