import { computed, inject, provide, type ComputedRef, type InjectionKey } from "vue"
import { useFormDataStore } from "@/stores/formDataStore"

/**
 * Vue inject key used by the page-level component (ShowPage / IndexPage
 * / FormPanel) to advertise which formId child renderers should bind
 * to. Avoids prop-drilling `formId` through every nested card/element.
 */
export const FORM_ID_KEY = Symbol("gx-modui:formId") as InjectionKey<string>

/**
 * Provide a formId to descendants. Call once at the page boundary.
 */
export function provideFormId(formId: string): void {
  provide(FORM_ID_KEY, formId)
}

export interface UseFormDataBindings {
  /** Current value for `name` (undefined if unset). */
  value: ComputedRef<unknown>
  /** Errors for `name`. Empty array if no errors. */
  errors: ComputedRef<string[]>
  /** Whether the field has been touched since initialisation. */
  touched: ComputedRef<boolean>
  /** Set the field's value. */
  setValue: (value: unknown) => void
  /** Clear errors for this field. */
  clearError: () => void
}

/**
 * Bind an element's `name` to the form-data store. Returns reactive
 * value, errors, and a setter. Renderers typically:
 *
 *   const { value, errors, setValue } = useFormData(props.element.name)
 *   <input :value="value" @input="setValue(($event.target as HTMLInputElement).value)" />
 */
export function useFormData(name: string, formIdOverride?: string): UseFormDataBindings {
  const formId =
    formIdOverride ?? inject(FORM_ID_KEY, undefined) ?? "default"
  const store = useFormDataStore()
  // Ensure the form exists in the store before reading.
  store.ensureForm(formId)

  return {
    value: computed(() => store.forms[formId]?.values[name]),
    errors: computed(() => store.forms[formId]?.errors[name] ?? []),
    touched: computed(() => Boolean(store.forms[formId]?.touched[name])),
    setValue: (value: unknown) => store.setValue(formId, name, value),
    clearError: () => store.clearErrors(formId, name),
  }
}
