<script setup lang="ts">
/**
 * Props-driven number input composition. Composes the shadcn `Input`
 * primitive (with `type="number"`) and `FieldFrame` chrome.
 *
 * Self-contained — usable directly in any Vue app:
 *
 *   <NumberInput v-model="age" label="Age" :min="0" :max="120" />
 *
 * The JSON-driven engine renders this via `ElementRenderer`, which
 * binds `modelValue` / `errors` to the form-data store automatically.
 */
import { onMounted, useTemplateRef } from "vue"
import { Input } from "@/components/ui/input"
import { FieldFrame } from "@/components/ui/field-frame"

export interface NumberInputProps {
  modelValue?: number | null
  id?: string
  name?: string
  label?: string
  hideLabel?: boolean
  placeholder?: string
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  min?: number
  max?: number
  step?: number
  helpText?: string
  errors?: string[]
  autoFocus?: boolean
}

const props = withDefaults(defineProps<NumberInputProps>(), {
  errors: () => [],
})

const model = defineModel<number | null>("modelValue")

const inputRef = useTemplateRef<HTMLInputElement>("inputRef")

onMounted(() => {
  if (props.autoFocus) {
    inputRef.value?.focus()
  }
})

function onUpdate(raw: string | number | undefined): void {
  if (raw === undefined || raw === "" || raw === null) {
    model.value = null
    return
  }
  const num = typeof raw === "number" ? raw : Number(raw)
  model.value = Number.isFinite(num) ? num : null
}
</script>

<template>
  <FieldFrame
    :label="label"
    :required="required"
    :hide-label="hideLabel"
    :for="id"
    :help-text="helpText"
    :errors="errors"
  >
    <Input
      ref="inputRef"
      :model-value="model ?? undefined"
      :id="id"
      :name="name ?? undefined"
      type="number"
      :placeholder="placeholder ?? ''"
      :readonly="readonly"
      :disabled="disabled"
      :required="required"
      :min="min"
      :max="max"
      :step="step"
      :data-element-name="name ?? undefined"
      :class="errors.length ? 'border-destructive ring-destructive' : ''"
      @update:model-value="onUpdate"
    />
  </FieldFrame>
</template>
