<script setup lang="ts">
/**
 * Props-driven password input composition. Composes the shadcn `Input`
 * primitive (with `type="password"`) and `FieldFrame` chrome. When
 * `togglePasswordVisibility` is set, renders an Eye/EyeOff toggle
 * button.
 *
 * Self-contained — usable directly in any Vue app:
 *
 *   <PasswordInput v-model="pw" label="Password" required toggle-password-visibility />
 */
import { computed, onMounted, ref, useTemplateRef } from "vue"
import { Eye, EyeOff } from "@lucide/vue"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { FieldFrame } from "@/components/ui/field-frame"

export interface PasswordInputProps {
  modelValue?: string
  id?: string
  name?: string
  label?: string
  hideLabel?: boolean
  placeholder?: string
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  maxlength?: number
  minlength?: number
  helpText?: string
  errors?: string[]
  autoFocus?: boolean
  togglePasswordVisibility?: boolean
}

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

const model = defineModel<string>("modelValue")

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

const visible = ref(false)
const inputType = computed<"password" | "text">(() =>
  visible.value ? "text" : "password",
)

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

function toggleVisibility(): void {
  visible.value = !visible.value
}
</script>

<template>
  <FieldFrame
    :label="label"
    :required="required"
    :hide-label="hideLabel"
    :for="id"
    :help-text="helpText"
    :errors="errors"
  >
    <div class="relative">
      <Input
        ref="inputRef"
        :model-value="model ?? undefined"
        :id="id"
        :name="name ?? undefined"
        :type="inputType"
        :placeholder="placeholder ?? ''"
        :readonly="readonly"
        :disabled="disabled"
        :required="required"
        :maxlength="maxlength"
        :minlength="minlength"
        :data-element-name="name ?? undefined"
        :class="[
          errors.length ? 'border-destructive ring-destructive' : '',
          togglePasswordVisibility ? 'pr-10' : '',
        ]"
        @update:model-value="(v: string | number | undefined) => (model = v == null ? '' : String(v))"
      />
      <Button
        v-if="togglePasswordVisibility"
        type="button"
        variant="ghost"
        size="icon-sm"
        class="absolute right-1 top-1/2 -translate-y-1/2"
        :aria-label="visible ? 'Hide password' : 'Show password'"
        data-testid="password-toggle"
        @click="toggleVisibility"
      >
        <EyeOff v-if="visible" class="h-4 w-4" />
        <Eye v-else class="h-4 w-4" />
      </Button>
    </div>
  </FieldFrame>
</template>
