<script setup lang="ts">
/**
 * Props-driven button composition. Composes the shadcn `Button`
 * primitive with click / href / emit / confirm behaviour.
 *
 * Self-contained — usable directly in any Vue app:
 *
 *   <ButtonAction label="Save" variant="default" @click="save" />
 *   <ButtonAction label="Docs" href="https://example.com" target="_blank" />
 *   <ButtonAction label="Delete" variant="destructive" confirm @action="onDelete" />
 *
 * Action elements do NOT use FieldFrame — they're not form inputs and
 * don't need label/help/error chrome.
 */
import { computed, ref } from "vue"
import * as LucideIcons from "@lucide/vue"
import type { FunctionalComponent } from "vue"

type LucideIcon = FunctionalComponent

import { Button, type ButtonVariants } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"

export type ButtonActionVariant =
  | "default"
  | "secondary"
  | "destructive"
  | "outline"
  | "ghost"
  | "link"
  | "success"
  | "warning"
  | "info"

export type ButtonActionSize = "sm" | "md" | "lg"

export interface ButtonActionProps {
  label?: string
  variant?: ButtonActionVariant
  size?: ButtonActionSize
  /** Lucide icon name rendered before the label. */
  icon?: string
  /** Navigation target — renders as an anchor when set and confirm is false. */
  href?: string
  target?: "_self" | "_blank" | "_parent" | "_top"
  /** Custom event name emitted via `action` when clicked. */
  emit?: string
  /** Show a confirmation dialog before firing. */
  confirm?: boolean
  /** Confirmation message displayed in the dialog. */
  confirmMessage?: string
  disabled?: boolean
  /** Render full width. */
  block?: boolean
  /** HTML name attribute. */
  name?: string
  /** HTML id attribute. */
  id?: string
}

const props = withDefaults(defineProps<ButtonActionProps>(), {
  variant: "default",
  size: "md",
  target: "_self",
})

const emit = defineEmits<{
  (e: "click", event: MouseEvent): void
  (e: "action", payload: { name: string }): void
}>()

const sizeMap: Record<ButtonActionSize, ButtonVariants["size"]> = {
  sm: "sm",
  md: "default",
  lg: "lg",
}

const mappedSize = computed<ButtonVariants["size"]>(
  () => sizeMap[props.size] ?? "default",
)

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

const confirmOpen = ref(false)

function performAction(): void {
  if (props.href) {
    if (props.target === "_blank") {
      window.open(props.href, "_blank")
    } else {
      window.location.assign(props.href)
    }
    return
  }
  if (props.emit) {
    emit("action", { name: props.emit })
  }
}

function onClick(event: MouseEvent): void {
  emit("click", event)
  if (props.confirm) {
    event.preventDefault()
    confirmOpen.value = true
    return
  }
  if (!props.href && props.emit) {
    event.preventDefault()
    performAction()
    return
  }
  if (!props.href && !props.emit) {
    event.preventDefault()
  }
}

function confirmYes(): void {
  confirmOpen.value = false
  performAction()
}

function confirmNo(): void {
  confirmOpen.value = false
}

const renderAs = computed<"a" | "button">(() =>
  props.href && !props.confirm ? "a" : "button",
)
</script>

<template>
  <Button
    :id="id"
    :as="renderAs"
    :variant="variant"
    :size="mappedSize"
    :disabled="disabled"
    :class="block ? 'w-full' : ''"
    :data-action-name="emit ?? label"
    :data-element-name="name ?? undefined"
    :href="renderAs === 'a' ? href : undefined"
    :target="renderAs === 'a' ? target : undefined"
    @click="onClick"
  >
    <component :is="icon" v-if="icon" class="h-4 w-4" />
    <span v-if="label">{{ label }}</span>
  </Button>

  <Dialog v-if="confirm" v-model:open="confirmOpen">
    <DialogContent>
      <DialogHeader>
        <DialogTitle>Confirm action</DialogTitle>
        <DialogDescription>
          {{ confirmMessage ?? "Are you sure you want to continue?" }}
        </DialogDescription>
      </DialogHeader>
      <DialogFooter>
        <Button variant="outline" type="button" @click="confirmNo">
          Cancel
        </Button>
        <Button variant="default" type="button" @click="confirmYes">
          Confirm
        </Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>
</template>
