<script setup lang="ts">
import { ref, computed, nextTick, useAttrs } from "vue";

const props = defineProps({
  infinityEnabled: { type: Boolean, default: false }, // Enable ∞ display for 0
});

const modelValue = defineModel<number>(); // Store actual number
const inputRef = ref<HTMLInputElement | null>(null);
const attrs = useAttrs();

let cursorPosition = 0;
let forceCursorToEnd = false;

// Computed property to format value with commas or infinity sign
const formattedValue = computed({
  get: () => {
    if (props.infinityEnabled && modelValue.value === 0) return "∞"; // Show ∞ if enabled
    return modelValue.value?.toLocaleString() ?? "";
  },
  set: (val: string) => {
    if (props.infinityEnabled && val === "∞") {
      modelValue.value = 0; // Convert back to 0 internally
      return;
    }

    const rawValue = val.replace(/\D/g, ""); // Remove non-numeric characters
    const numericValue = rawValue ? Number(rawValue) : 0;

    if (!isNaN(numericValue)) {
      modelValue.value = numericValue;
      nextTick(() => restoreCursor());
    }
  },
});

// Handle keydown for navigation & number changes
const handleKeyDown = (event: KeyboardEvent) => {
  if (!inputRef.value || modelValue.value === undefined) return;

  const { selectionStart, selectionEnd, value } = inputRef.value;
  const isAllSelected = selectionStart === 0 && selectionEnd === value.length;

  if (
    !/^\d$/.test(event.key) &&
    ![
      "Backspace",
      "Delete",
      "ArrowLeft",
      "ArrowRight",
      "ArrowUp",
      "ArrowDown",
    ].includes(event.key)
  ) {
    event.preventDefault();
    return;
  }

  if (isAllSelected && /^\d$/.test(event.key)) {
    event.preventDefault();
    modelValue.value = Number(event.key);
    forceCursorToEnd = true;
    nextTick(() => restoreCursor());
    return;
  }

  if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
    forceCursorToEnd = false;
    return;
  }

  if (event.key === "ArrowUp") {
    event.preventDefault();
    modelValue.value += 1;
    forceCursorToEnd = true;
  } else if (event.key === "ArrowDown") {
    event.preventDefault();
    modelValue.value = Math.max(0, modelValue.value - 1);
    forceCursorToEnd = true;
  } else {
    cursorPosition = selectionStart || 0;
  }

  nextTick(() => restoreCursor());
};

// Restore cursor position
const restoreCursor = () => {
  if (!inputRef.value) return;
  const length = formattedValue.value.length;

  if (forceCursorToEnd) {
    inputRef.value.setSelectionRange(length, length);
  } else {
    inputRef.value.setSelectionRange(cursorPosition, cursorPosition);
  }
};
</script>

<template>
  <v-text-field
    ref="inputRef"
    v-model="formattedValue"
    v-bind="attrs"
    type="text"
    @keydown="handleKeyDown"
  >
    <template v-if="$slots.prepend" v-slot:prepend>
      <slot name="prepend"></slot>
    </template>

    <template v-if="$slots.append" v-slot:append>
      <slot name="append"></slot>
    </template>

    <template v-if="$slots['append-inner']" v-slot:append-inner>
      <slot name="append-inner"></slot>
    </template>

    <template v-if="$slots['prepend-inner']" v-slot:prepend-inner>
      <slot name="prepend-inner"></slot>
    </template>
  </v-text-field>
</template>
