<script
  setup
  lang="ts"
  generic="From extends Record<PropertyKey, any>,
  To extends Record<PropertyKey, any>,
  Name extends DeepKeys<From> | undefined = DeepKeys<From>"
>
import { type DeepKeys } from "@tanstack/vue-form"
import { computed, provide, ref, watch } from "vue"
import { type TaggedUnionOption } from "./InputProps"
import OmegaTaggedUnionInternal from "./OmegaTaggedUnionInternal.vue"
import { type FieldPath } from "./types"
import { type useOmegaForm } from "./useOmegaForm"

const props = defineProps<{
  name?: Name
  form: ReturnType<typeof useOmegaForm<From, To>>
  type?: "select" | "radio"
  options: TaggedUnionOption<From, Name>[]
  label?: string
}>()

// Track the current tag value reactively
const currentTag = ref<string | null>(null)

// Watch the form's _tag field value
const tagPath = computed(() => props.name ? `${props.name}._tag` : "_tag")
const formValues = props.form.useStore((state) => state.values)
watch(
  () => {
    const path = tagPath.value
    // Navigate to the nested value
    // eslint-disable-next-line @typescript-eslint/no-explicit-any -- traversing arbitrary nested values
    return path.split(".").reduce((acc: any, key) => acc?.[key], formValues.value) as string | null
  },
  (newTag) => {
    currentTag.value = newTag ?? null
  },
  { immediate: true }
)

// Provide tag-specific metadata to all child Input components
const getMetaFromArray = computed(() => {
  const tag = currentTag.value

  const getMeta = (path: string) => {
    if (!tag) return null

    // Get the tag-specific metadata
    const tagMeta = props.form.unionMeta[tag]
    if (!tagMeta) return null

    // Look up the meta for this path
    return tagMeta[path as keyof typeof tagMeta] ?? null
  }

  return getMeta
})

provide("getMetaFromArray", getMetaFromArray)
</script>

<template>
  <form.Field :name="name ? `${name}._tag` : '_tag'">
    <template #default="inputProps">
      <slot
        name="OmegaCustomInput"
        v-bind="inputProps"
      >
        <form.Input
          :name="(name ? `${name}._tag` : '_tag') as FieldPath<From>"
          :label="label"
          :type="type ?? 'select'"
          :options="options"
        />
      </slot>
      <slot />
      <!--
        Drive the branch off `currentTag`: the tag is read from the form store
        (the canonical state), the same single source of truth that feeds
        `getMetaFromArray` above — rather than the `Field` slot's `state`,
        which is only a projection of it.
      -->
      <OmegaTaggedUnionInternal
        :field="inputProps.field as any"
        :tag="currentTag"
        :name="name"
        :form="form"
      >
        <template
          v-for="(_, slotname) in $slots"
          #[slotname]="slotProps"
        >
          <slot
            :name="slotname"
            v-bind="slotProps"
          />
        </template>
      </OmegaTaggedUnionInternal>
      <slot
        v-if="currentTag"
        name="OmegaCommon"
      />
    </template>
  </form.Field>
</template>
