<script setup lang='ts'>
import type { FormKitFrameworkContext } from '@formkit/core'
import type { InputNumberBlurEvent, InputNumberProps } from 'primevue/inputnumber'

import type { PropType } from 'vue'
import { watch } from 'vue'
import { useFormKitInput } from '../composables'

export interface FormKitPrimeInputNumberProps {
  useGrouping?: InputNumberProps['useGrouping']
  min?: InputNumberProps['min']
  max?: InputNumberProps['max']
  minFractionDigits?: InputNumberProps['minFractionDigits']
  maxFractionDigits?: InputNumberProps['maxFractionDigits']
  locale?: InputNumberProps['locale']
  mode?: InputNumberProps['mode']
  currency?: InputNumberProps['currency']
  prefix?: InputNumberProps['prefix']
  suffix?: InputNumberProps['suffix']
  showButtons?: InputNumberProps['showButtons']
  buttonLayout?: InputNumberProps['buttonLayout']
  step?: InputNumberProps['step']
  pt?: InputNumberProps['pt']
  ptOptions?: InputNumberProps['ptOptions']
  unstyled?: InputNumberProps['unstyled']
  placeholder?: InputNumberProps['placeholder']
  size?: InputNumberProps['size']
}

const props = defineProps({
  context: {
    type: Object as PropType<FormKitFrameworkContext & FormKitPrimeInputNumberProps>,
    required: true,
  },
})

const { validSlotNames, unstyled, isInvalid, modelValue } = useFormKitInput(props.context)

function handleBlur(e: InputNumberBlurEvent) {
  props.context?.handlers.blur(e.originalEvent as FocusEvent)
}

function handleInput(_: any) {
  if (typeof _.value === 'number' || _.value === null)
    props.context?.node.input(_.value)
}

function roundToDecimals(value: any, decimals: number) {
  const factor = 10 ** decimals
  return Math.round(value * factor) / factor
}

watch(
  () => props.context._value,
  (newValue) => {
    // Only update if the value is different
    if (newValue !== props.context.node.value && typeof newValue === 'number') {
      if (props.context.maxFractionDigits && props.context.maxFractionDigits > 0) {
        // fix floating-point precision issues
        props.context?.node.input(roundToDecimals(newValue, props.context.maxFractionDigits))
      }
      else {
        props.context?.node.input(newValue)
      }
    }
  },
)
</script>

<template>
  <div class="p-formkit">
    <InputNumber
      v-model="modelValue"
      v-bind="context?.attrs"
      :input-id="context.id"
      :disabled="!!context?.disabled"
      :readonly="context?.attrs.readonly ?? false"
      :input-style="context?.attrs.style"
      :input-class="context?.attrs?.class"
      :invalid="isInvalid"
      :tabindex="context?.attrs.tabindex"
      :aria-label="context?.attrs.ariaLabel"
      :aria-labelledby="context?.attrs.ariaLabelledby"
      :size="context?.size ?? undefined"
      :placeholder="context.placeholder"
      :use-grouping="context.useGrouping ?? true"
      :min="context.min ?? undefined"
      :max="context.max ?? undefined"
      :min-fraction-digits="context.minFractionDigits ?? undefined"
      :max-fraction-digits="context.maxFractionDigits ?? undefined"
      :locale="context.locale ?? undefined"
      :mode="context.mode ?? undefined"
      :currency="context.currency ?? undefined"
      :prefix="context.prefix ?? undefined"
      :suffix="context.suffix ?? undefined"
      :show-buttons="context.showButtons ?? undefined"
      :button-layout="context.buttonLayout ?? 'stacked'"
      :step="context.step ?? undefined"
      :pt="context.pt"
      :pt-options="context.ptOptions"
      :unstyled="unstyled"
      @input="handleInput"
      @blur="handleBlur"
    >
      <template v-for="slotName in validSlotNames" :key="slotName" #[slotName]="slotProps">
        <component :is="context?.slots[slotName]" v-bind="{ ...context, ...slotProps }" />
      </template>
    </InputNumber>
  </div>
</template>
