<template>
	<div class="range-container">
		<div
			class="label label-start"
			:class="{ disabled }"
			@click="setValue('valueA', 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="valueA"
				:min="min"
				:max="max"
				:data-value="valueA"
				:disabled="disabled"
				type="range"
				class="slider"
				@input="emit('input')"
				@change="emit('change')"
				@click.stop
			>

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

		<div
			class="label label-end"
			:class="{ disabled }"
			@click="setValue('valueB', max)"
		>
			<slot name="end" />
		</div>
	</div>
</template>

<script>
import { nextTick } from 'vue';

function minValue() {
	return Math.min(this.valueA, this.valueB);
}

function maxValue() {
	return Math.max(this.valueA, this.valueB);
}

function minPercentage() {
	return ((this.minValue - this.min) / (this.max - this.min)) * 100;
}

function maxPercentage() {
	return ((this.maxValue - this.min) / (this.max - this.min)) * 100;
}

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

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

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

	nextTick(() => {
		if (!this.disabled) {
			const closestValue = Math.round((event.offsetX / event.target.getBoundingClientRect().width) * (this.max - this.min)) + this.min;
			const closestSlider = Math.abs(this.valueA - closestValue) < Math.abs(this.valueB - closestValue) ? 'valueA' : 'valueB';

			this[closestSlider] = closestValue;
			this.emit();
		}
	});
}

function setValue(prop, value) {
	if (this.allowEnable) {
		this.emit('enable');
	}

	nextTick(() => {
		if (!this.disabled) {
			this[prop] = value;
			this.emit();
		}
	});
}

export default {
	props: {
		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,
		},
	},
	emits: ['change', 'input', 'enable'],
	data() {
		if (this.values) {
			return {
				valueA: this.values.indexOf(this.value[0]),
				valueB: this.values.indexOf(this.value[1]),
			};
		}

		return {
			valueA: this.value[0],
			valueB: this.value[1],
		};
	},
	computed: {
		minValue,
		maxValue,
		minPercentage,
		maxPercentage,
	},
	methods: {
		emit,
		setNearest,
		setValue,
	},
};
</script>

<style lang="scss">
.dark .range-container .range {
	--slider-range: var(--lighten-weak);
}
</style>

<style lang="scss" scoped>
@mixin 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(--darken-weak);
}

.range-container {
	display: flex;
	justify-content: space-between;
}

.range {
	--slider-track: var(--shadow-hint);
	--slider-range: var(--primary-faded);
	--slider-thumb: var(--primary);

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

	&.disabled {
		--slider-range: var(--shadow-weak);
		--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 {
	@include thumb;
}

.slider::-moz-range-thumb {
	@include thumb;
	transform: translateY(2px);
}

.label {
	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>