<script setup lang="ts">
/**
 * Shared chrome around an input-bearing composition. Provides the
 * label / required asterisk / helpText / error-list visuals so every
 * input composition doesn't repeat the same boilerplate.
 *
 * Usage from a composition:
 *
 *   <FieldFrame
 *     :label="label"
 *     :required="required"
 *     :help-text="helpText"
 *     :errors="errors"
 *     :for="id"
 *   >
 *     <Input v-model="model" ... />
 *   </FieldFrame>
 *
 * FieldFrame is a normal Vue component — consumers can use it directly
 * for ad-hoc inputs, not just via the JSON-driven engine.
 */
import type { HTMLAttributes } from "vue"
import { Label } from "@/components/ui/label"
import { cn } from "@/lib/utils"

export interface FieldFrameProps {
  /** Visible field label. Hidden when `hideLabel` is true. */
  label?: string
  /** Render a required asterisk after the label. */
  required?: boolean
  /** Hide the label visually while keeping it for screen readers. */
  hideLabel?: boolean
  /** `for` attribute on the Label — should match the inner input's id. */
  for?: string
  /** Help text rendered below the input. */
  helpText?: string
  /** Validation error messages. When non-empty the chrome flips to the destructive variant. */
  errors?: string[]
  /** Extra class applied to the wrapper. */
  class?: HTMLAttributes["class"]
}

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

<template>
  <div :class="cn('flex flex-col gap-1.5', props.class)" data-testid="field-frame">
    <Label
      v-if="label && !hideLabel"
      :for="props.for"
      :required="required"
      data-testid="field-frame-label"
    >
      {{ label }}
    </Label>
    <span v-else-if="label" class="sr-only" data-testid="field-frame-label-sr">
      {{ label }}
    </span>

    <slot />

    <p
      v-if="helpText"
      class="text-sm text-muted-foreground"
      data-testid="field-frame-help"
    >
      {{ helpText }}
    </p>
    <ul
      v-if="errors.length"
      class="flex flex-col gap-0.5 text-sm text-destructive"
      role="alert"
      data-testid="field-frame-errors"
    >
      <li v-for="(err, i) in errors" :key="i">{{ err }}</li>
    </ul>
  </div>
</template>
