<template>
  <view class="ruler-wrapper" v-show="visible">
    <scroll-view class="ruler-scroll" scroll-x :scroll-left="scrollLeft" :scroll-with-animation="useAnimation"
      @scroll="onScroll" @touchend="onTouchEnd" @touchcancel="onTouchEnd" scroll-into-view="">
      <view class="ruler-inner" :style="{ width: totalWidth + 'px' }">
        <view v-for="(g, idx) in gridList" :key="idx" class="grid-item" :class="{ long: g.isLongGrid }"
          :style="{ width: props.gutter + 'px' }">
          <view class="tick" :class="{ long: g.isLongGrid }"></view>
          <text v-if="g.showText" class="grid-num">{{ g.displayNum }}</text>
        </view>
      </view>
    </scroll-view>
    <view class="indicator">
      <view class="value-box"><text class="value-text">{{ currentValue }}</text></view>
      <view class="indicator-triangle"></view>
      <view class="indicator-line"></view>

    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { getCurrentInstance } from 'vue'

interface GridItem { num: number; displayNum: number | string; isLongGrid: boolean; showText: boolean }

const props = defineProps({
  min: { type: Number, default: 0 },
  max: { type: Number, default: 100 },
  step: { type: Number, default: 1 }, 
  unit: { type: String, default: '' },
  initialValue: { type: Number, default: 0 },
  gutter: { type: Number, default: 10 }, 
  visible: { type: Boolean, default: true },
  useAnimation: { type: Boolean, default: true }
})

const emit = defineEmits(['update:value', 'change'])

const instance = getCurrentInstance()
const scrollLeft = ref(0)
const actualScrollLeft = ref(0)

const currentValue = ref(Math.round(props.initialValue || props.min))


const totalUnits = computed(() => Math.round((props.max - props.min) / props.step))


const extraGridCount = Math.ceil((uni?.getSystemInfoSync?.().windowWidth || 375) / props.gutter / 2) * 2

const gridList = ref<GridItem[]>([])
const totalWidth = ref(0)

const gridItemStyle = computed(() => ({ width: props.gutter + 'px', height: '24px' }))

function buildGrid() {
  const count = totalUnits.value
  const arr: GridItem[] = []
  for (let i = 0; i <= count + extraGridCount * 1; i++) {
    const numIndex = i - extraGridCount / 2
    const num = props.min + numIndex * props.step
    const displayNum = num
    const isLongGrid = (numIndex % 10 === 0)
    const showText = isLongGrid && num >= props.min && num <= props.max
    arr.push({ num, displayNum, isLongGrid, showText })
  }
  gridList.value = arr
  totalWidth.value = arr.length * props.gutter
}

buildGrid()

const offsetScroll = computed(() => extraGridCount * props.gutter/2)

const windowWidth = uni?.getSystemInfoSync?.().windowWidth || 375
const halfWindow = windowWidth / 2


onMounted(() => {

  const initIndex = Math.round((props.initialValue - props.min) / props.step)

  scrollLeft.value = offsetScroll.value + initIndex * props.gutter + props.gutter / 2 - halfWindow

  currentValue.value = Math.round(initIndex * props.step + props.min)
})

function onScroll(e: any) {
  const left = e?.detail?.scrollLeft ?? e?.detail?.scrollLeft ?? 0
  actualScrollLeft.value = left

  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
  let value = numIndex * props.step + props.min
  if (value < props.min) value = props.min
  if (value > props.max) value = props.max

  currentValue.value = Math.round(value)
  emit('update:value', value)
}

function adjustScrollPosition() {

  const left = actualScrollLeft.value

  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)

  const targetLeft = offsetScroll.value + numIndex * props.gutter + props.gutter / 2 - halfWindow

  const maxScroll = Math.max(0, totalWidth.value - windowWidth)
  const clamped = Math.min(Math.max(targetLeft, 0), maxScroll)
  scrollLeft.value = clamped
}

function onTouchEnd() {

  adjustScrollPosition()

  const left = scrollLeft.value
  const numIndex = Math.round((left + halfWindow - offsetScroll.value - props.gutter / 2) / props.gutter)
  let value = numIndex * props.step + props.min
  if (value < props.min) value = props.min
  if (value > props.max) value = props.max

  currentValue.value = Math.round(value)
  emit('change', value)
}
</script>

<style scoped>
.ruler-wrapper {
  position: relative;
  height: 520rpx;
  display: flex;
  align-items: flex-start;
}

.ruler-scroll {
  margin-top: 210rpx;
  width: 100%;
  height: 180rpx;
  overflow-x: scroll;
  scrollbar-width: none; /* Firefox */
  -ms-overflow-style: none; /* IE and Edge */
}

.ruler-scroll::-webkit-scrollbar {
  display: none; /* Chrome, Safari, Opera */
}

.ruler-inner {
  display: flex;
  align-items: flex-start;
}

.grid-item {
  width: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding-top: 8rpx;
}



.tick {
  width: 2px;
  margin-top: 10rpx;
  height: 60rpx;
  background: #d5d5d5;
}

.tick.long {
  width: 3px;
  margin-top: 0rpx;
  /* margin-left: 1px; */
  height: 80rpx;
  background: #414141;
}

.grid-num {
  font-size: 36rpx;
  color: #666;
  margin-block: 8rpx;

}

.indicator {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  width: 2px;
  height: 100%;
  display: flex;
  align-items: center;
  flex-direction: column;
  pointer-events: none;
}

.indicator-line {
  width: 4px;
  margin-top: -4px;
  /* margin-left: 1px; */
  height: 15px;
  background: #ff6a00;
}

.indicator-triangle {
  width: 0;
  height: 0;
  border-left: 8px solid transparent;
  border-right: 8px solid transparent;
  border-top: 10px solid #ff6a00;
  margin-top: 100px;
}

.value-box {
  margin-top: 70rpx;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  padding: 6rpx 12rpx;
  border-radius: 6rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}

.value-text {
  color: #000000;
  font-size: 70rpx;
  font-weight: 900;
  line-height: 1;
}
</style>