<!-- Range-слайдер (от-до) для числовых фильтров, синхронизирован с query -->
<template>
  <ClientOnly v-if="getSliderRangeInfo(item.options)">
    <UiSlider
      v-if="(item.kind === 'range') && (item.group.name === groupName)"
      :key="`model-filter-range-${index}`"
      :min="getSliderRangeInfo(item.options)?.min"
      :max="getSliderRangeInfo(item.options)?.max"
      :step="getSliderRangeInfo(item.options)?.step"
      :model-value="[
        minRangeValue(item),
        maxRangeValue(item)
      ]"
      :title="item.title"
      :icon="icon"
      :icon-prefix="iconPrefix"
      :active="isActive(item.name)"
      :format="formatterSlider()"
      :between="betweenText(item.options, getSliderRangeInfo(item.options)?.min, getSliderRangeInfo(item.options)?.max)"
      @update:model-value="val => updateRangeFilter(item, val)"
    >
      <template
        v-for="(_, name) in $slots"
        #[name]="slotData"
      >
        <slot
          :name="name"
          v-bind="slotData"
        />
      </template>
    </UiSlider>
  </ClientOnly>
</template>

<script setup lang="ts">
import type { IModelFilter, IModelFilterOptions } from '../../types';
import type { LocationQuery } from '#vue-router';
import { useRoute, useRouter } from '#vue-router';
import { getSliderRangeInfo } from '../../utils/filter-slider/get-slider-range-info';
import { buildRangeFilterQuery } from '../../utils/filter-slider/build-range-filter-query';

const props = defineProps<{
  item: IModelFilter
  index: number
  groupName: string
  query?: LocationQuery
  icon?: string
  iconPrefix?: string
}>();

const emit = defineEmits<{
  (e: 'update:query', value: LocationQuery): void
}>();

const route = useRoute();
const router = useRouter();

const effectiveQuery = computed<LocationQuery>(() => props.query ?? route.query);

function commitQuery(newQuery: LocationQuery) {
  if (props.query !== undefined) {
    emit('update:query', newQuery);
  } else {
    router.replace({ query: newQuery });
  }
}

function updateRangeFilter(item: IModelFilter, val: string[] | number[]) {
  nextTick(() => {
    const rangeInfo = getSliderRangeInfo(item.options);
    if (!rangeInfo) return;
    const [from, to] = val;

    commitQuery(buildRangeFilterQuery({
      query: effectiveQuery.value,
      name: item.name,
      from,
      to,
      rangeInfo,
    }));
  });
}

function getRangeValue(name: string, defaultValue: number | undefined) {
  const value = effectiveQuery.value[`filter_${name}`];
  if (value !== undefined) {
    return Number(value);
  } else {
    return defaultValue;
  }
}

function minRangeValue(item: IModelFilter) {
  const min = getSliderRangeInfo(item.options)?.min;
  return min !== undefined ? getRangeValue(`${item.name}_from`, min) : 0;
}

function maxRangeValue(item: IModelFilter) {
  const max = getSliderRangeInfo(item.options)?.max;
  return max !== undefined ? getRangeValue(`${item.name}_to`, max) : 0;
}

function isSliderHasTitle(options: IModelFilterOptions[] | undefined): boolean | undefined {
  return options && options[0] && isNaN(Number(options[0].title));
}

function formatterSlider() {
  return (event: number) => Math.round(event);
}

function betweenText(options: IModelFilterOptions[], min: number | undefined, max: number | undefined): string[] | undefined {
  if (isSliderHasTitle(options)) {
    const getText = (number: number | undefined): string | undefined => {
      return options.find((item: IModelFilterOptions) => Number(item.name) === number)?.title;
    };
    return [getText(min) || '', getText(max) || ''];
  }
}

function isActive(name: string) {
  const baseName = name.replace(/_(from|to)$/, '');
  return Object.keys(effectiveQuery.value).some(key => key.startsWith(`filter_${baseName}`));
}
</script>
