<template>
	<div class="range-container">
		<div
			class="label label-start"
			:class="{ disabled }"
			@click="setRange(range.a === minValue ? 'a' : 'b', min)"
		>
			<slot name="start" />
		</div>

		<div
			class="range"
			:class="{ disabled }"
			:style="{ background: `linear-gradient(90deg, var(--slider-track) ${minPercentage}%, var(--slider-range) ${minPercentage}%, var(--slider-range) ${maxPercentage}%, var(--slider-track) ${maxPercentage}%)` }"
			@click="setNearest"
		>
			<input
				v-model.number="range.a"
				:min="min"
				:max="max"
				:data-value="range.a"
				:disabled="disabled"
				type="range"
				class="slider"
				@input="set('input')"
				@change="set('change')"
				@click.stop
			>

			<input
				v-model.number="range.b"
				:min="min"
				:max="max"
				:data-value="range.b"
				:disabled="disabled"
				type="range"
				class="slider"
				@input="set('input')"
				@change="set('change')"
				@click.stop
			>
		</div>

		<div
			class="label label-end"
			:class="{ disabled }"
			@click="setRange(range.b === maxValue ? 'b' : 'a', max)"
		>
			<slot name="end" />
		</div>
	</div>
</template>

<script setup>
import {
	ref,
	computed,
	nextTick,
} from 'vue';

const props = defineProps({
	min: {
		type: Number,
		default: 0,
	},
	max: {
		type: Number,
		default: 10,
	},
	value: {
		type: Array,
		default: () => [3, 7],
	},
	values: {
		type: Array,
		default: null,
	},
	disabled: {
		type: Boolean,
		default: false,
	},
	allowEnable: {
		type: Boolean,
		default: true,
	},
});

const emit = defineEmits(['change', 'input', 'enable']);

const range = ref({
	a: props.values ? props.values.indexOf(props.value[0]) : props.value[0],
	b: props.values ? props.values.indexOf(props.value[1]) : props.value[1],
});

const minValue = computed(() => Math.min(range.value.a, range.value.b));
const maxValue = computed(() => Math.max(range.value.a, range.value.b));
const minPercentage = computed(() => ((minValue.value - props.min) / (props.max - props.min)) * 100);
const maxPercentage = computed(() => ((maxValue.value - props.min) / (props.max - props.min)) * 100);

function set(type = 'change') {
	if (props.values) {
		emit(type, [props.values[minValue.value], props.values[maxValue.value]]);
		return;
	}

	emit(type, [minValue.value, maxValue.value]);
}

async function setNearest(event) {
	if (props.allowEnable) {
		emit('enable');
	}

	await nextTick;

	if (!props.disabled) {
		const closestValue = Math.round((event.offsetX / event.target.getBoundingClientRect().width) * (props.max - props.min)) + props.min;
		const closestSlider = Math.abs(range.value.a - closestValue) < Math.abs(range.value.b - closestValue) ? 'a' : 'b';

		range.value[closestSlider] = closestValue;

		set('change');
	}
}

async function setRange(prop, value) {
	if (props.allowEnable) {
		emit('enable');
	}

	await nextTick;

	if (!props.disabled) {
		range.value[prop] = value;

		set('change');
	}
}
</script>

<style>
.dark .range-container .range {
	--slider-range: var(--lighten-weak-10);
}
</style>

<style scoped>
.range-container {
	display: flex;
	justify-content: space-between;
}

.range {
	--slider-track: var(--shadow-weak-30);
	--slider-range: var(--primary-light-30);
	--slider-thumb: var(--primary);

	position: relative;
	height: 1.25rem;
	flex-grow: 1;
	border-radius: .625rem;

	&.disabled {
		--slider-range: var(--shadow-weak-40);
		--slider-thumb: var(--disabled-handle);
	}
}

.slider {
	width: 100%;
	top: 0;
	margin: 0;
	appearance: none;
	position: absolute;
	background: none;
	outline: none;
	pointer-events: none;
}

.slider::-webkit-slider-thumb {
	appearance: none;
	display: block;
	width: 1.25rem;
	height: 1.25rem;
	border: none;
	border-radius: 50%;
	background: var(--slider-thumb);
	pointer-events: visible;
	cursor: pointer;
	box-shadow: 0 0 3px var(--shadow-weak-10);
}

.slider::-moz-range-thumb {
	appearance: none;
	display: block;
	width: 1.25rem;
	height: 1.25rem;
	border: none;
	border-radius: 50%;
	background: var(--slider-thumb);
	pointer-events: visible;
	cursor: pointer;
	box-shadow: 0 0 3px var(--shadow-weak-10);
	transform: translateY(2px);
}

.label {
	height: 100%;
	padding: 0 .5rem;

	&:hover:not(.disabled) {
		cursor: pointer;

		::v-deep(.icon) {
			fill: var(--primary);
		}
	}
}

::v-deep(.icon) {
	width: 1.25rem;
	height: 1.25rem;
	flex-shrink: 0;
	fill: var(--shadow);
}
</style>