<template>
  <div class="vm-number-range" :class="{ 'is-disabled': disabled }">
    <div class="vm-number-range__side">
      <input
        class="vm-number-range__input"
        :type="mode === 'float' ? 'text' : 'number'"
        inputmode="decimal"
        :placeholder="startPlaceholder ?? crudLabel('min')"
        :disabled="disabled"
        :value="display(0)"
        @input="(e) => onInput(0, e)"
        @blur="(e) => onBlur(0, e)"
      />
      <i class="ri-hashtag vm-number-range__icon" aria-hidden="true" />
    </div>
    <span class="vm-number-range__sep">-</span>
    <div class="vm-number-range__side">
      <input
        class="vm-number-range__input"
        :type="mode === 'float' ? 'text' : 'number'"
        inputmode="decimal"
        :placeholder="endPlaceholder ?? crudLabel('max')"
        :disabled="disabled"
        :value="display(1)"
        @input="(e) => onInput(1, e)"
        @blur="(e) => onBlur(1, e)"
      />
      <i class="ri-hashtag vm-number-range__icon" aria-hidden="true" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { crudLabel } from '../style'
defineOptions({ name: 'vm-number-range' })

const props = withDefaults(
  defineProps<{
    modelValue?: Array<number | string | null>
    /** int = 整数；float = 最多两位小数 */
    mode?: 'int' | 'float'
    startPlaceholder?: string
    endPlaceholder?: string
    disabled?: boolean
  }>(),
  {
    mode: 'int',
    startPlaceholder: undefined,
    endPlaceholder: undefined,
  },
)

const emit = defineEmits<{
  'update:modelValue': [v: Array<number | null>]
  change: [v: Array<number | null>]
}>()

function display(idx: 0 | 1) {
  const v = props.modelValue?.[idx]
  return v == null || v === '' ? '' : String(v)
}

function parse(raw: string): number | null {
  const t = raw.trim()
  if (!t || t === '-' || t === '.' || t === '-.') return null
  if (props.mode === 'int') {
    if (!/^-?\d+$/.test(t)) return null
    const n = Number(t)
    return Number.isFinite(n) ? n : null
  }
  if (!/^-?\d+(\.\d{0,2})?$/.test(t)) return null
  const n = Number(t)
  if (!Number.isFinite(n)) return null
  return Math.round(n * 100) / 100
}

function emitPair(next: Array<number | null>) {
  emit('update:modelValue', next)
  emit('change', next)
}

function onInput(idx: 0 | 1, e: Event) {
  const el = e.target as HTMLInputElement
  let raw = el.value
  if (props.mode === 'int') {
    raw = raw.replace(/[^\d-]/g, '').replace(/(?!^)-/g, '')
  } else {
    raw = raw
      .replace(/[^\d.-]/g, '')
      .replace(/(?!^)-/g, '')
      .replace(/(\..*)\./g, '$1')
    const m = raw.match(/^(-?\d*)(\.?\d{0,2})/)
    raw = m ? `${m[1] || ''}${m[2] || ''}` : ''
  }
  el.value = raw
  const next: Array<number | null> = [
    props.modelValue?.[0] != null && props.modelValue[0] !== ''
      ? Number(props.modelValue[0])
      : null,
    props.modelValue?.[1] != null && props.modelValue[1] !== ''
      ? Number(props.modelValue[1])
      : null,
  ]
  next[idx] = parse(raw)
  emitPair(next)
}

function onBlur(idx: 0 | 1, e: Event) {
  const raw = (e.target as HTMLInputElement).value
  const next: Array<number | null> = [
    props.modelValue?.[0] != null && props.modelValue[0] !== ''
      ? Number(props.modelValue[0])
      : null,
    props.modelValue?.[1] != null && props.modelValue[1] !== ''
      ? Number(props.modelValue[1])
      : null,
  ]
  next[idx] = parse(raw)
  emitPair(next)
}
</script>

<style lang="scss" scoped>
.vm-number-range {
  display: flex;
  box-sizing: border-box;
  width: 100%;
  height: var(--vm-control-height);
  align-items: center;
  padding: 0 10px;
  border: 1px solid transparent;
  border-radius: 12px;
  background: var(--muted);
  gap: 0;

  &.is-disabled {
    opacity: 0.55;
    pointer-events: none;
  }

  /* 筛控件：不展示点击聚焦描边 */
}

.vm-number-range__side {
  display: flex;
  min-width: 0;
  flex: 1 1 0;
  height: 100%;
  align-items: center;
  gap: 6px;
}

.vm-number-range__input {
  min-width: 0;
  flex: 1 1 0;
  height: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--foreground);
  font-size: 13px;
  text-align: center;
  outline: none;
  appearance: textfield;

  &::-webkit-outer-spin-button,
  &::-webkit-inner-spin-button {
    margin: 0;
    appearance: none;
  }

  &::placeholder {
    color: var(--muted-foreground);
  }
}

.vm-number-range__icon {
  display: inline-flex;
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  align-items: center;
  justify-content: center;
  color: var(--muted-foreground);
  font-size: 14px;
  line-height: 1;
  pointer-events: none;
}

.vm-number-range__sep {
  flex: 0 0 auto;
  padding: 0 8px;
  color: var(--muted-foreground);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  user-select: none;
}
</style>
