<script setup>
// Wraps PrimeVue Button; use variant (not severity). Use icon name (e.g. "plus") not "pi pi-*".
//
// IMPORTANT (PrimeVue 4): Passing a default slot replaces Button's inner template (label + icons).
// Plain-text default slot content is merged into `label`; we never forward `<slot>` into PV Button.
import { Fragment, computed, useSlots } from "vue";
import Button from "primevue/button";
import { resolveIcon } from "../../lib/icons";

const slots = useSlots();

/** Supports simple default-slot text (`<Btn>Save</Btn>`); complex slot content stays unsupported — use `label`. */
function vnodeToPlain(node) {
  if (node == null || node === false) return "";
  if (typeof node === "string" || typeof node === "number")
    return String(node);
  if (typeof node !== "object") return "";

  const { children, type } = node;
  if (type === Fragment && children != null) {
    return Array.isArray(children)
      ? vnodeListToPlainText(children)
      : vnodeToPlain(children);
  }

  if (typeof children === "string" || typeof children === "number")
    return String(children);
  if (Array.isArray(children)) return vnodeListToPlainText(children);
  return "";
}

function vnodeListToPlainText(nodes) {
  if (nodes == null || nodes.length === 0) return "";
  return nodes.map(vnodeToPlain).join("");
}

const props = defineProps({
  variant: {
    type: String,
    default: "primary",
    validator: (v) =>
      [
        "primary",
        "secondary",
        "success",
        "danger",
        "warning",
        "info",
        "help",
        "contrast",
      ].includes(v),
  }, // visual style (maps to PrimeVue severity)
  label: { type: String, default: "" }, // button text; omit for icon-only
  icon: { type: String, default: "" }, // icon name (e.g. "plus", "trash") or full class; resolved via resolveIcon
  iconPosition: {
    type: String,
    default: "left",
    validator: (v) => ["left", "right"].includes(v),
  }, // left | right
  outlined: { type: Boolean, default: false },
  rounded: { type: Boolean, default: false },
  text: { type: Boolean, default: false }, // text-style (e.g. Cancel)
  iconOnly: { type: Boolean, default: false },
  size: {
    type: String,
    default: undefined,
    validator: (v) => !v || ["small", "large"].includes(v),
  }, // small | large
  fluid: { type: Boolean, default: false }, // full width
  disabled: { type: Boolean, default: false },
  loading: { type: Boolean, default: false },
  type: { type: String, default: "button" }, // native type
  as: { type: [String, Object], default: undefined }, // e.g. "a" for link; use href via $attrs
  class: { type: [String, Object, Array], default: "" },
});

const emit = defineEmits(["click", "focus", "blur"]);

const severityMap = {
  primary: "primary",
  secondary: "secondary",
  success: "success",
  danger: "danger",
  warning: "warn",
  info: "info",
  help: "help",
  contrast: "contrast",
};

const pSeverity = computed(() => severityMap[props.variant] ?? "primary");
const pIconPos = computed(() =>
  props.iconPosition === "right" ? "right" : "left",
);
const pIcon = computed(() =>
  props.icon ? resolveIcon(props.icon) : undefined,
);

/**
 * Text for PrimeVue `label` only (never pass our default slot through — it replaces PV's inner UI).
 * Prop wins; else plain-text from default slot (`<BaseButton>Save</BaseButton>`).
 */
const mergedLabel = computed(() => {
  const fromProp = String(props.label ?? "").trim();
  if (fromProp.length > 0) return fromProp;
  const fromSlot = vnodeListToPlainText(slots.default?.() ?? []).trim();
  return fromSlot.length > 0 ? fromSlot : undefined;
});
</script>

<template>
  <Button
    :label="mergedLabel"
    :icon="pIcon"
    :icon-pos="pIconPos"
    :severity="pSeverity"
    :outlined="outlined"
    :rounded="rounded"
    :text="text"
    :size="size"
    :fluid="fluid"
    :disabled="disabled"
    :loading="loading"
    :type="type"
    :as="as"
    :class="[props.class, iconOnly && 'icon-only']"
    v-bind="$attrs"
    @click="emit('click', $event)"
    @focus="emit('focus', $event)"
    @blur="emit('blur', $event)"
  />
</template>
