"use client";

import { useId, type ReactNode, type Ref } from "react";
import { cx } from "../../utils";
import { FoxCheckbox } from "../fox-checkbox";
import { FoxCheckboxGroup } from "../fox-checkbox-group";
import { FoxRadio } from "../fox-radio";
import { FoxRadioGroup } from "../fox-radio-group";

export type FoxChipSelectionMode = "single" | "multiple";

/** 칩 목록의 항목 하나. 그리는 일은 `FoxCheckbox`·`FoxRadio`가 한다. */
export interface FoxChipItem {
  value: string;
  label: ReactNode;
  /** 이 항목만 고를 수 없게 한다. */
  disabled?: boolean;
}

export interface FoxChipSelectOptionProps {
  /** 목록을 여는 요소의 `aria-controls`가 가리킬 값. */
  id?: string;
  /** 목록에 이름을 주는 요소의 id — 보통 칩 자신이다. */
  labelledBy?: string;
  /**
   * 하나만 고를지 여러 개를 고를지. 항목의 모양이 여기서 갈린다 —
   * `single`은 라디오 목록, `multiple`은 체크박스 목록이다.
   */
  selectionMode?: FoxChipSelectionMode;
  options: FoxChipItem[];
  /**
   * 라디오 묶음의 `name`. `single`에서만 쓰이고, 넘기지 않으면 자동으로 만든다.
   *
   * 같은 화면에 칩 목록이 둘 이상 열릴 일은 없지만, `name`이 겹치면 브라우저가 한 묶음으로
   * 보고 서로를 끄기 때문에 자동 생성이라도 반드시 있어야 한다.
   */
  name?: string;
  /** 지금 켜진 값들. `single`이면 길이가 0 또는 1이다 — 두 계열의 상태를 한 모양으로 받는다. */
  values?: string[];
  /** 항목을 켜거나 끌 때 호출된다. 무엇을 어떻게 반영할지는 받는 쪽이 정한다. */
  onSelect?: (value: string) => void;
  /**
   * 모바일에만 보이는 확인 버튼의 글자. 버튼 자체는 언제나 렌더되고 **CSS가 데스크톱에서
   * 숨긴다** — 조건부 렌더로 하면 창 폭이 바뀔 때마다 DOM이 들락거려서, 열린 채로 화면을
   * 돌리면 포커스가 날아간다.
   */
  confirmLabel?: string;
  /** 확인 버튼을 눌렀을 때. 보통 목록을 닫는다. */
  onConfirm?: () => void;
  /**
   * 항목(체크박스·라디오)의 크기. 여는 칩의 크기를 그대로 받는다 — 두 컴포넌트의 크기
   * 이름이 같고 글자 크기도 같은 값이라(lg 17px, md 15px) 그대로 이어진다. 칩만 크고
   * 목록은 작으면 같은 필터인데 두 벌처럼 보인다.
   */
  size?: "lg" | "md";
  /** 배치 조정용. 모양이 달라야 하면 여기 말고 모디파이어를 추가한다. */
  className?: string;
  ref?: Ref<HTMLDivElement>;
}

/**
 * @fox 칩의 `select`가 열렸을 때 뜨는 목록. 배치만 책임지고 상태를 갖지 않는다 —
 * 열림 여부·고른 값은 전부 목록을 여는 칩이 소유한다.
 *
 * `FoxSelectOption`과 **다른 컴포넌트다.** 저쪽은 `role="listbox"` + `role="option"`이고
 * 항목이 글자 한 줄이지만, 이쪽은 시안이 **체크박스·라디오 목록**이라 이미 있는
 * `FoxCheckboxGroup`·`FoxRadioGroup`을 그대로 쓴다. 네이티브 입력이라 단일 선택의
 * 화살표 이동·폼 전송을 브라우저가 처리하고, 항목 모양이 다른 화면의 체크박스와 어긋나지
 * 않는다.
 *
 * 항목이 진짜 입력이라 `FoxSelectOption`처럼 `mousedown`을 막지 않는다 — 눌러서 그 입력에
 * 포커스가 가는 것이 맞다. 목록이 닫히지 않는 이유는 포커스가 여는 쪽과 **같은 조상 안**에
 * 머물러서다(칩의 focusout 처리가 그것을 본다).
 *
 * ⚠️ 스스로 위치를 잡지 못한다 — `position: absolute`라 위치 기준이 되는 조상이 필요하다.
 * `FoxChip` 안에서는 `fox-chip-select`가 그 역할을 한다.
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxChipSelectOption({
  id,
  labelledBy,
  selectionMode = "single",
  options,
  name,
  values = [],
  onSelect,
  confirmLabel = "확인",
  onConfirm,
  size = "md",
  className,
  ref,
}: FoxChipSelectOptionProps) {
  const generatedName = useId();
  const groupName = name ?? generatedName;

  const isMultiple = selectionMode === "multiple";

  return (
    <div
      ref={ref}
      id={id}
      // 목록 전체는 그냥 묶음이다. 단일 선택의 `radiogroup` 의미는 안쪽
      // `FoxRadioGroup`이 갖는다 — 확인 버튼이 그 묶음 밖에 있어야 하기 때문이다.
      role="group"
      aria-labelledby={labelledBy}
      className={cx("fox-chip-select-option", className)}
    >
      <div className="fox-chip-select-option__list">
        {isMultiple ? (
          <FoxCheckboxGroup
            orientation="vertical"
            labelledBy={labelledBy}
            // 항목 사이 간격만 묶음 기본값과 다르다 — 스타일 파일의 같은 이름 규칙 참고.
            className="fox-chip-select-option__group"
          >
            {options.map((option) => (
              <FoxCheckbox
                key={option.value}
                size={size}
                value={option.value}
                label={option.label}
                checked={values.includes(option.value)}
                disabled={option.disabled}
                onChange={() => onSelect?.(option.value)}
              />
            ))}
          </FoxCheckboxGroup>
        ) : (
          <FoxRadioGroup
            orientation="vertical"
            name={groupName}
            labelledBy={labelledBy}
            className="fox-chip-select-option__group"
          >
            {options.map((option) => (
              <FoxRadio
                key={option.value}
                size={size}
                value={option.value}
                label={option.label}
                checked={values.includes(option.value)}
                disabled={option.disabled}
                onChange={() => onSelect?.(option.value)}
              />
            ))}
          </FoxRadioGroup>
        )}
      </div>

      {/*
        확인 버튼은 **다중 선택에만** 있다. 이 버튼이 하는 일은 "고르기를 마쳤다"고 알려 목록을
        닫는 것인데, 단일 선택은 하나 고르는 순간 목록이 닫히므로 버튼이 할 일이 없다 — 남겨
        두면 눌러도 아무 일이 없는 버튼이 모바일 화면 아래를 차지한다.

        값이 반영되는 시점은 플랫폼과 무관하게 같다(고르는 즉시). 모바일에서 달라지는 것은
        **닫는 수단이 하나 더 생기는 것**뿐이고, 데스크톱에서는 CSS가 이 버튼을 숨긴다.
      */}
      {isMultiple ? (
        <button
          type="button"
          className="fox-chip-select-option__confirm"
          onClick={onConfirm}
        >
          {confirmLabel}
        </button>
      ) : null}
    </div>
  );
}
