<script lang="ts">
import { computed, defineComponent, onUnmounted, ref } from 'vue'

export default defineComponent({
  props: {
    start: {
      type: Number,
      required: true,
    },

    end: {
      type: Number,
      required: true,
    },

    min: {
      type: Number,
      required: true,
    },

    max: {
      type: Number,
      required: true,
    },
  },
  emits: ['update:start', 'update:end'],
  setup(props, { emit }) {
    const startRatio = computed(() => (props.start - props.min) / (props.max - props.min))
    const endRatio = computed(() => (props.max - props.end) / (props.max - props.min))

    const el = ref(null)

    let mouseStartX: number, initialValue: number

    // Main bar

    const moving = ref(false)

    function onMainBarMouseDown(event: MouseEvent) {
      mouseStartX = event.clientX
      initialValue = props.start
      moving.value = true
      window.addEventListener('mousemove', onMainBarMouseMove)
      window.addEventListener('mouseup', onMainBarMouseUp)
    }

    function onMainBarMouseMove(event: MouseEvent) {
      let start = props.start
      const size = props.end - props.start
      start = initialValue + (event.clientX - mouseStartX) / el.value.offsetWidth * (props.max - props.min)
      if (start < props.min) {
        start = props.min
      }
      else if (start > props.max - size) {
        start = props.max - size
      }
      emit('update:start', Math.round(start))
      emit('update:end', Math.round(start + size))
    }

    function onMainBarMouseUp() {
      moving.value = false
      removeMainBarEvents()
    }

    function removeMainBarEvents() {
      window.removeEventListener('mousemove', onMainBarMouseMove)
      window.removeEventListener('mouseup', onMainBarMouseUp)
    }

    onUnmounted(() => {
      removeMainBarEvents()
    })

    // Start resize handle

    function onStartHandleMouseDown(event: MouseEvent) {
      mouseStartX = event.clientX
      initialValue = props.start
      window.addEventListener('mousemove', onStartHandleMouseMove)
      window.addEventListener('mouseup', onStartHandleMouseUp)
    }

    function onStartHandleMouseMove(event: MouseEvent) {
      let start = props.start
      start = initialValue + (event.clientX - mouseStartX) / el.value.offsetWidth * (props.max - props.min)
      if (start < props.min) {
        start = props.min
      }
      else if (start > props.end - 1) {
        start = props.end - 1
      }
      emit('update:start', Math.round(start))
    }

    function onStartHandleMouseUp() {
      removeStartHandleEvents()
    }

    function removeStartHandleEvents() {
      window.removeEventListener('mousemove', onStartHandleMouseMove)
      window.removeEventListener('mouseup', onStartHandleMouseUp)
    }

    onUnmounted(() => {
      removeStartHandleEvents()
    })

    // End resize handle

    function onEndHandleMouseDown(event: MouseEvent) {
      mouseStartX = event.clientX
      initialValue = props.end
      window.addEventListener('mousemove', onEndHandleMouseMove)
      window.addEventListener('mouseup', onEndHandleMouseUp)
    }

    function onEndHandleMouseMove(event: MouseEvent) {
      let end = props.end
      end = initialValue + (event.clientX - mouseStartX) / el.value.offsetWidth * (props.max - props.min)
      if (end < props.start + 1) {
        end = props.start + 1
      }
      else if (end > props.max) {
        end = props.max
      }
      emit('update:end', Math.round(end))
    }

    function onEndHandleMouseUp() {
      removeEndHandleEvents()
    }

    function removeEndHandleEvents() {
      window.removeEventListener('mousemove', onEndHandleMouseMove)
      window.removeEventListener('mouseup', onEndHandleMouseUp)
    }

    onUnmounted(() => {
      removeStartHandleEvents()
    })

    return {
      el,
      startRatio,
      endRatio,
      onMainBarMouseDown,
      moving,
      onStartHandleMouseDown,
      onEndHandleMouseDown,
    }
  },
})
</script>

<template>
  <div
    ref="el"
    class="h-6 bg-gray-200 dark:bg-gray-900 rounded relative select-none"
  >
    <!-- Main Bar -->
    <div
      class="absolute h-full top-0 bg-green-200 dark:bg-green-900 hover:bg-green-100 dark:hover:bg-green-800 cursor-move"
      :class="{
        'bg-green-100 dark:bg-green-800': moving,
      }"
      :style="{
        left: `calc(${(start - min) / (max - min) * 100}% - 1px)`,
        width: `calc(${(end - start) / (max - min) * 100}% + 1px)`,
      }"
      @mousedown="onMainBarMouseDown"
    />

    <!-- Start resize handle -->
    <div
      class="absolute h-full rounded top-0 bg-green-300 dark:bg-green-700 cursor-ew-resize"
      :style="{
        left: `calc(${startRatio * 100}% - ${startRatio < 0.05 ? 0 : 4}px)`,
        width: '4px',
      }"
      @mousedown="onStartHandleMouseDown"
    />

    <!-- End resize handle -->
    <div
      class="absolute h-full rounded top-0 bg-green-300 dark:bg-green-700 cursor-ew-resize"
      :style="{
        right: `calc(${endRatio * 100}% - ${endRatio < 0.05 ? 0 : 4}px)`,
        width: '4px',
      }"
      @mousedown="onEndHandleMouseDown"
    />
  </div>
</template>
