"use client";

import type { ComponentPropsWithRef } from "react";
import { cx } from "../../utils";

/**
 * 필수·선택 표시. 둘은 배타적이라 boolean 두 개가 아니라 하나의 값으로 받는다 — 그래야
 * "필수이면서 선택"이라는 있을 수 없는 조합이 타입에서 막힌다.
 */
export type FoxFormLabelRequirement = "required" | "optional";

/**
 * 네이티브 `<label>`이 받는 것을 그대로 넘겨받는다 — htmlFor·id·title 등. 이름이 겹치는
 * 것만 걷어내고 아래에서 다시 정의한다.
 */
type NativeLabelProps = Omit<ComponentPropsWithRef<"label">, "className" | "hidden">;

export interface FoxFormLabelProps extends NativeLabelProps {
  /**
   * 그릴 태그. 칸 하나를 가리킬 때는 `label`이고, 칸 여러 개를 묶은 필드
   * (전화번호·주소처럼)에서는 `span`이다 — 가리킬 대상이 하나가 아니라 `htmlFor`를 쓸 수
   * 없고, 아무것도 가리키지 않는 `<label>`을 두면 의미가 어긋난다. 그때 이름 연결은
   * 감싼 쪽이 `aria-labelledby`로 한다.
   */
  as?: "label" | "span";
  requirement?: FoxFormLabelRequirement;
  /** "(선택)" 대신 쓸 문구. */
  optionalText?: string;
  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
  hidden?: boolean;
  /** 배치 조정용. */
  className?: string;
}

/**
 * @fox 입력 칸 위에 붙는 라벨. 상태를 갖지 않는다.
 *
 * 필수는 글자 뒤에 `*`, 선택은 "(선택)"을 붙인다. `*`는 `aria-hidden`이라 스크린리더가 읽지
 * 않는다 — 필수 여부는 입력 요소의 `required`가 알리는 것이고 별표는 그 눈에 보이는 짝이라,
 * 둘 다 읽히면 같은 말이 두 번 나온다. 반대로 "(선택)"은 대신 알려 줄 속성이 없어 읽히게 둔다.
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxFormLabel({
  as: Tag = "label",
  requirement,
  optionalText = "(선택)",
  hidden = false,
  className,
  children,
  ...rest
}: FoxFormLabelProps) {
  if (hidden) {
    return null;
  }

  return (
    <Tag {...rest} className={cx("fox-form-label", className)}>
      {children}
      {requirement === "required" ? (
        <span className="fox-form-label__required" aria-hidden="true">
          *
        </span>
      ) : null}
      {requirement === "optional" ? (
        <span className="fox-form-label__optional">{optionalText}</span>
      ) : null}
    </Tag>
  );
}
