<script lang="ts">
  // 공용 textarea. TextInput과 같은 구조 + autoGrow 옵션.
  interface Props {
    value?: string;
    label?: string;
    error?: string;
    hint?: string;
    placeholder?: string;
    id?: string;
    name?: string;
    rows?: number;
    disabled?: boolean;
    readonly?: boolean;
    required?: boolean;
    autoGrow?: boolean;
    maxRows?: number;
    class?: string;
  }

  let {
    value = $bindable(''),
    label,
    error,
    hint,
    placeholder,
    id: idProp,
    name,
    rows = 3,
    disabled = false,
    readonly = false,
    required = false,
    autoGrow = false,
    maxRows,
    class: className = '',
    ...rest
  }: Props = $props();

  const autoId = $props.id();
  let inputId = $derived(idProp ?? `textarea-${autoId}`);
  let hintId = $derived(`${inputId}-hint`);
  let errorId = $derived(`${inputId}-error`);
  let describedBy = $derived(
    [error ? errorId : null, hint && !error ? hintId : null].filter(Boolean).join(' ') || undefined
  );

  let textareaEl: HTMLTextAreaElement | undefined = $state();

  // autoGrow: value 변경 시마다 height를 scrollHeight로 동기화
  $effect(() => {
    if (!autoGrow || !textareaEl) return;
    // value를 reactivity 의존성으로 등록
    void value;
    textareaEl.style.height = 'auto';
    let next = textareaEl.scrollHeight;
    if (maxRows) {
      const lineHeight = parseFloat(getComputedStyle(textareaEl).lineHeight) || 20;
      const maxHeight = lineHeight * maxRows;
      if (next > maxHeight) next = maxHeight;
    }
    textareaEl.style.height = next + 'px';
  });

  let textareaClass = $derived(
    [
      'w-full px-3 py-2 rounded-md text-sm bg-bg text-text placeholder:text-faint',
      'border outline-none transition-colors',
      error
        ? 'border-error focus:border-error focus:ring-2 focus:ring-error/30'
        : 'border-default focus:border-accent focus:ring-2 focus:ring-accent-ring',
      'disabled:opacity-50 disabled:cursor-not-allowed',
      autoGrow ? 'resize-none overflow-hidden' : 'resize-y',
    ].join(' ')
  );
</script>

<div class={'flex flex-col gap-1 ' + className}>
  {#if label}
    <label for={inputId} class="text-xs font-medium text-dim">
      {label}
      {#if required}<span class="text-error">*</span>{/if}
    </label>
  {/if}

  <textarea
    id={inputId}
    bind:this={textareaEl}
    bind:value
    {name}
    {rows}
    {placeholder}
    {disabled}
    {readonly}
    {required}
    class={textareaClass}
    aria-invalid={error ? 'true' : undefined}
    aria-describedby={describedBy}
    {...rest}
  ></textarea>

  {#if error}
    <p id={errorId} class="text-xs text-error">{error}</p>
  {:else if hint}
    <p id={hintId} class="text-xs text-faint">{hint}</p>
  {/if}
</div>
