<script setup lang="ts">
/**
 * Props-driven icon-toggle composition. Renders a Toggle primitive that
 * shows `trueIcon` when pressed and `falseIcon` when not. Icons are
 * looked up from `@lucide/vue` by name; missing icons fall back to
 * `ToggleRight` / `ToggleLeft`.
 *
 *   <IconToggleBoolean
 *     v-model="darkMode"
 *     label="Dark mode"
 *     true-icon="moon"
 *     false-icon="sun"
 *   />
 */
import { computed } from "vue"
import { ToggleLeft, ToggleRight } from "@lucide/vue"
import * as LucideIcons from "@lucide/vue"
import type { FunctionalComponent } from "vue"

type LucideIcon = FunctionalComponent

import { Toggle } from "@/components/ui/toggle"
import { FieldFrame } from "@/components/ui/field-frame"

export interface IconToggleBooleanProps {
  modelValue?: boolean
  id?: string
  name?: string
  label?: string
  hideLabel?: boolean
  required?: boolean
  readonly?: boolean
  disabled?: boolean
  helpText?: string
  errors?: string[]
  /** Lucide icon shown when value is true. */
  trueIcon?: string
  /** Lucide icon shown when value is false. */
  falseIcon?: string
}

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

const model = defineModel<boolean>("modelValue", { default: false })

const iconLibrary = LucideIcons as unknown as Record<string, LucideIcon>

function resolveIcon(name: string | undefined, fallback: LucideIcon): LucideIcon {
  if (!name) {
    return fallback
  }
  const pascal = name
    .split(/[-_\s]/)
    .filter(Boolean)
    .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
    .join("")
  return iconLibrary[pascal] ?? iconLibrary[name] ?? fallback
}

const trueIconComponent = computed(() =>
  resolveIcon(props.trueIcon, ToggleRight),
)
const falseIconComponent = computed(() =>
  resolveIcon(props.falseIcon, ToggleLeft),
)

const activeIcon = computed(() =>
  model.value ? trueIconComponent.value : falseIconComponent.value,
)

function onUpdate(pressed: boolean): void {
  model.value = pressed
}
</script>

<template>
  <FieldFrame
    :label="label"
    :required="required"
    :hide-label="hideLabel"
    :for="id"
    :help-text="helpText"
    :errors="errors"
  >
    <Toggle
      :id="id"
      :name="name"
      :disabled="disabled || readonly"
      :required="required"
      :pressed="model"
      variant="outline"
      :data-element-name="name ?? undefined"
      :aria-label="label"
      @update:pressed="onUpdate"
    >
      <component :is="activeIcon" class="h-4 w-4" />
    </Toggle>
  </FieldFrame>
</template>
