<script lang="ts">
  // 공용 Button 프리미티브.
  // - variant: 시각적 강도 (primary/secondary/ghost/danger)
  // - size: sm/md
  // - href가 있으면 <a>로, 없으면 <button>으로 렌더
  // - icon은 lucide 컴포넌트 참조 (예: import { Trash2 } 후 icon={Trash2})
  // - loading이면 disabled + 회전 아이콘
  import { Loader2 } from 'lucide-svelte';
  import type { Snippet } from 'svelte';

  // lucide-svelte v0.400은 아직 legacy SvelteComponentTyped 기반이라 Svelte 5의
  // Component 타입과 호환되지 않는다. 향후 lucide v0.469+ 업그레이드 시 정식 타입으로 좁히기.
  // 우리는 size prop만 넘기므로 any로 받아도 충분히 안전.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  type IconComponent = any;

  type Variant = 'primary' | 'secondary' | 'ghost' | 'danger';
  type Size = 'sm' | 'md';

  interface Props {
    variant?: Variant;
    size?: Size;
    loading?: boolean;
    disabled?: boolean;
    type?: 'button' | 'submit' | 'reset';
    icon?: IconComponent;
    iconPosition?: 'left' | 'right';
    href?: string;
    target?: string;
    onclick?: (e: MouseEvent) => void;
    children?: Snippet;
    class?: string;
  }

  let {
    variant = 'primary',
    size = 'md',
    loading = false,
    disabled = false,
    type = 'button',
    icon: Icon,
    iconPosition = 'left',
    href,
    target,
    onclick,
    children,
    class: className = '',
    ...rest
  }: Props = $props();

  const variantClass: Record<Variant, string> = {
    primary: 'bg-accent text-white hover:bg-accent-hover',
    secondary: 'bg-surface border border-default text-text hover:bg-surface-hover',
    ghost: 'text-dim hover:bg-surface hover:text-text',
    danger: 'bg-error/10 text-error border border-error/30 hover:bg-error/20',
  };

  const sizeClass: Record<Size, string> = {
    sm: 'h-7 px-2.5 text-xs gap-1.5',
    md: 'h-9 px-3.5 text-sm gap-2',
  };

  let iconSize = $derived(size === 'sm' ? 14 : 16);

  let baseClass = $derived(
    [
      'inline-flex items-center justify-center rounded-md font-medium',
      'transition-colors',
      'focus-visible:ring-2 focus-visible:ring-accent-ring focus-visible:outline-none',
      'disabled:opacity-50 disabled:cursor-not-allowed',
      sizeClass[size],
      variantClass[variant],
      className,
    ].join(' ')
  );

  let isDisabled = $derived(disabled || loading);
</script>

{#if href}
  <a
    {href}
    {target}
    class={baseClass}
    aria-disabled={isDisabled || undefined}
    tabindex={isDisabled ? -1 : undefined}
    {...rest}
  >
    {#if loading}
      <Loader2 size={iconSize} class="animate-spin" />
    {:else if Icon && iconPosition === 'left'}
      <Icon size={iconSize} />
    {/if}
    {@render children?.()}
    {#if !loading && Icon && iconPosition === 'right'}
      <Icon size={iconSize} />
    {/if}
  </a>
{:else}
  <button
    {type}
    class={baseClass}
    disabled={isDisabled}
    aria-busy={loading || undefined}
    {onclick}
    {...rest}
  >
    {#if loading}
      <Loader2 size={iconSize} class="animate-spin" />
    {:else if Icon && iconPosition === 'left'}
      <Icon size={iconSize} />
    {/if}
    {@render children?.()}
    {#if !loading && Icon && iconPosition === 'right'}
      <Icon size={iconSize} />
    {/if}
  </button>
{/if}
