<script setup lang="ts">
import { watch } from 'vue'

export interface RangeInputProps {
	modelValue: number | [number, number]
	min?: number
	max?: number
	step?: number
	required?: boolean
	label?: string
	disabled?: boolean
	id?: string
	rtl?: boolean
	multiRange?: boolean
	formatValue?: (value: number) => string
}

const props = defineProps<RangeInputProps>()
const emit = defineEmits(['update:modelValue'])

const {
	min = 0,
	max = 100,
	step = 1,
	multiRange = false,
	formatValue = (value: number) => value.toString()
} = props

let from = $ref<number>(Array.isArray(props.modelValue) ? props.modelValue[0] : (props.modelValue ?? min))
let to = $ref<number>(Array.isArray(props.modelValue) ? props.modelValue[1] : max)

const validFrom = $computed(() => Math.min(Math.max(from, min), multiRange ? to : max))
const validTo = $computed(() => Math.max(Math.min(to, max), from))

const fromPercentage = $computed(() => ((validFrom - min) / (max - min)) * 100)
const toPercentage = $computed(() => ((validTo - min) / (max - min)) * 100)

watch(() => props.modelValue, (newVal) => {
	if (Array.isArray(newVal) && multiRange) {
		from = newVal[0] ?? min
		to = newVal[1] ?? max
	} else if (!Array.isArray(newVal)) {
		from = newVal ?? min
		to = max
	}
}, { immediate: true })

function handleInput(value: number, isFromInput: boolean) {
	if (isFromInput) {
		from = value
	} else {
		to = value
	}
	emit('update:modelValue', multiRange ? [validFrom, validTo] : validFrom)
}

const rangeStyle = $computed(() => {
	if (multiRange) {
		return {
			left: `${fromPercentage}%`,
			width: `${toPercentage - fromPercentage}%`
		}
	}
	return props.rtl
		? { left: `${100 - fromPercentage}%`, width: `${fromPercentage}%` }
		: { left: '0', width: `${fromPercentage}%` }
})

const displayFrom = $computed(() => formatValue(validFrom))
const displayTo = $computed(() => formatValue(validTo))
</script>

<template>
	<div :dir="rtl ? 'rtl' : 'ltr'">
		<label v-if="props.label" class="label">{{ props.label }}</label>
		<div class="range-slider relative w-100">
			<input
				:id="id"
				:value="validFrom"
				class="from"
				type="range"
				:min="min"
				:max="max"
				:step="step"
				:required="required"
				:disabled="disabled"
				:aria-label="multiRange ? 'Minimum value' : 'Value'"
				@input="(e) => handleInput(+(e.target as HTMLInputElement).value, true)"
			>
			<input
				v-if="multiRange"
				:value="validTo"
				class="to"
				type="range"
				:min="min"
				:max="max"
				:step="step"
				:required="required"
				:disabled="disabled"
				aria-label="Maximum value"
				@input="(e) => handleInput(+(e.target as HTMLInputElement).value, false)"
			>
			<div class="track absolute pointer-events-none overflow-hidden round">
				<div
					class="active-range absolute h-100 pointer-events-none bg-primary"
					:style="rangeStyle"
				/>
			</div>
			<p
				v-if="validFrom !== min"
				class="txt-center txt-12 range-slider-position-txt absolute line-height-1"
				:style="{ '--progress': `${fromPercentage}` }"
			>
				<slot v-if="!multiRange" name="progress" :progress="displayFrom" :min="formatValue(min)" :max="formatValue(max)">
					{{ displayFrom }}
				</slot>
				<slot v-if="multiRange" name="from" :from="displayFrom" :to="displayTo" :min="formatValue(min)" :max="formatValue(max)">
					{{ displayFrom }}
				</slot>
			</p>
			<p
				v-if="multiRange && validTo !== max"
				class="txt-center txt-12 range-slider-position-txt line-height-1 absolute"
				:style="{ '--progress': `${toPercentage}` }"
			>
				<slot name="to" :to="displayTo" :from="displayFrom" :min="formatValue(min)" :max="formatValue(max)">
					{{ displayTo }}
				</slot>
			</p>
		</div>
		<p class="txt-center txt-14 user-select-none range-slider-txt flex space-between opacity-4 mx-05">
			<slot name="min" :max="formatValue(max)" :min="formatValue(min)" :from="displayFrom" :to="displayTo" :progress="displayFrom">
				<span>{{ formatValue(min) }}</span>
			</slot>
			<slot name="max" :max="formatValue(max)" :min="formatValue(min)" :from="displayFrom" :to="displayTo" :progress="displayFrom">
				<span>{{ formatValue(max) }}</span>
			</slot>
		</p>
	</div>
</template>

<style scoped>
.range-slider-position-txt{
	margin-inline-start:  calc((var(--progress) * 1%) - (var(--bgl-range-thumb-size) * var(--progress) / 100));
	top: calc(var(--bgl-range-thumb-size) / 2 ) ;
	transition: transform 0.1s, opacity 0.5s, top 0.5s;
	transform: scale(0.8);
	width: var(--bgl-range-thumb-size);
}
.range-slider:hover .range-slider-position-txt{
	opacity: 1;
	transform: scale(1);
	top: calc(var(--bgl-range-thumb-size) / 2);
}

.range-slider {
	height: var(--bgl-range-track-size);
	display: flex;
	align-items: center;
	margin-top: calc(var(--bgl-range-thumb-size) / 2 + 0.5rem) ;
}
.range-slider-txt{
	margin-top: calc(var(--bgl-range-thumb-size) / 2) !important;
}

input[type="range"] {
  position: absolute;
  width: 100%;
  height: 100%;
  height: var(--bgl-range-thumb-size);
  background: transparent;
  pointer-events: none;
  appearance: none;
  margin: 0;
}

input[type="range"]::-webkit-slider-thumb {
  pointer-events: all;
  appearance: none;
  width: var(--bgl-range-thumb-size);
  height: var(--bgl-range-thumb-size);
  background: var(--bgl-range-thumb-color);
  border-radius: 50%;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  position: relative;
  z-index: 2;
  cursor: grab;
  transition: var(--bgl-transition);
}

input[type="range"]::-webkit-slider-thumb:hover {
	box-shadow: 0 0 0 calc(var(--bgl-range-thumb-size) / 2) var(--bgl-primary-tint);
	filter: brightness(90%);
}

input[type="range"]:focus::-webkit-slider-thumb {
  outline: none;
  box-shadow: 0 0 0 calc(var(--bgl-range-thumb-size) / 2.2) var(--bgl-primary-tint);
}

input[type="range"]:active::-webkit-slider-thumb {
	cursor: grabbing;
}

.track {
  height: var(--bgl-range-track-height);
  background: var(--bgl-bg);
  margin-inline-start: calc(var(--bgl-range-thumb-size) / 2);
  width: calc(100% - var(--bgl-range-thumb-size));
}
@media screen and (max-width: 768px) {
	.range-slider-position-txt{
		opacity: 1;
		transform: scale(1);
		top: calc(var(--bgl-range-thumb-size) / 1.8) ;
	}
}
</style>
