"use client";

import { useRef, type ReactNode } from "react";
import { cx } from "../../utils";
import { FoxCheckbox } from "../fox-checkbox";
import { FoxRadio } from "../fox-radio";
import { FoxSelect, type FoxSelectItem } from "../fox-select";

export type FoxConditionalOptionOrientation = "horizontal" | "vertical";

/**
 * 앞에 놓이는 컨트롤. 라디오는 묶음에서 하나만 골리고, 체크박스는 여러 개를 동시에 골릴 수
 * 있다 — 나머지는 전부 같다.
 */
export type FoxConditionalOptionControl = "radio" | "checkbox";

/** 라디오·체크박스가 같은 두 단계를 쓴다. */
export type FoxConditionalOptionSize = "lg" | "md";

export interface FoxConditionalOptionProps {
  /**
   * 앞에 놓이는 컨트롤. 기본은 라디오다.
   *
   * 시안에서는 `trigger`라고 부르지만 이름을 바꿨다 — 이 패키지에서 `trigger`는 이미
   * `fox-select__trigger`(목록을 여는 버튼)라는 다른 뜻으로 쓰인다. 여기 라디오·체크박스는
   * 무엇을 여는 게 아니라 답을 담는 컨트롤이다.
   */
  control?: FoxConditionalOptionControl;
  /** 컨트롤 값. 같은 `name` 안에서 이 칸을 가리킨다. */
  value: string;
  label: ReactNode;
  /** 라벨 아래 보조 설명. 넘기지 않으면 영역을 렌더링하지 않는다. */
  description?: ReactNode;
  /** 딸린 select의 목록. */
  options: FoxSelectItem[];
  /** 딸린 select의 값(제어). 넘기지 않으면 안에서 들고 있는다. */
  detail?: string;
  /** 비제어로 쓸 때 딸린 select의 초기 값. */
  defaultDetail?: string;
  /** 딸린 select 값이 바뀔 때 부른다. 값이 첫 인자다. */
  onChange?: (detail: string) => void;
  /**
   * 켜짐 여부가 바뀔 때 부른다 — select를 골라 자동으로 켜진 경우도 포함이다.
   *
   * 라디오는 켜질 때만 뛰므로 항상 `true`로 온다. 체크박스는 끌 때도 뛰어서 `false`가 올 수
   * 있다. 값은 호출부가 이미 아는 것이라 되돌려주지 않는다.
   */
  onCheckedChange?: (checked: boolean) => void;
  /** 아무것도 고르지 않았을 때 select에 보여줄 문구. */
  placeholder?: ReactNode;
  orientation?: FoxConditionalOptionOrientation;
  /** 묶음 이름. 그룹 안에 넣으면 그룹이 넣어 주므로 직접 적지 않아도 된다. */
  name?: string;
  /** `FoxRadioGroup`·`FoxCheckboxGroup`이 넣어 준다. 직접 넣으면 그 값이 컨트롤 크기가 된다. */
  size?: FoxConditionalOptionSize;
  /** 처음부터 켜진 채로 둔다(비제어). */
  defaultChecked?: boolean;
  /** 주면 켜짐 여부를 호출부가 소유한다. */
  checked?: boolean;
  disabled?: boolean;
  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
  hidden?: boolean;
  /** 배치 조정용. */
  className?: string;
}

const ORIENTATION_CLASS: Record<FoxConditionalOptionOrientation, string> = {
  horizontal: "fox-conditional-option--horizontal",
  vertical: "fox-conditional-option--vertical",
};

/**
 * @fox 후속 질문이 딸린 선택지. 컨트롤 한 칸과 select를 묶어 하나의 답으로 다룬다.
 *
 * `control`로 라디오와 체크박스를 고른다. 두 컨트롤이 `name`·`value`·`size`·`checked`를 같은
 * 이름으로 받고 크기 단계도 같아서, 나머지 배선은 그대로 쓴다. 그래서 `FoxRadioGroup`이든
 * `FoxCheckboxGroup`이든 그대로 넣을 수 있다 — 그룹이 `name`·`size`를 넣어 준다.
 *
 * select는 이 칸이 켜지지 않아도 **조작할 수 있다.** 값을 고르면 컨트롤이 자동으로 켜진다 —
 * 값을 고르고도 컨트롤을 안 눌러 답이 비는 일이 흔해서다. 반대로 select를 잠가 두면 그 자동
 * 선택 자체가 불가능해진다(`disabled`는 클릭을 먹지 않는다).
 *
 * 켜는 방법은 숨은 input을 실제로 클릭하는 것이다. 그래야 라디오에서 같은 `name`의 다른 칸이
 * 꺼지는 것과 change 이벤트가 브라우저 규칙 그대로 일어난다 — `checked`를 직접 대입하면
 * 이벤트가 뛰지 않아 호출부가 모른다. 이미 켜져 있으면 누르지 않는다(체크박스가 꺼져 버린다).
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxConditionalOption({
  control = "radio",
  value,
  label,
  description,
  options,
  detail,
  defaultDetail,
  onChange,
  onCheckedChange,
  placeholder,
  orientation = "vertical",
  name,
  size = "lg",
  defaultChecked,
  checked,
  disabled = false,
  hidden = false,
  className,
}: FoxConditionalOptionProps) {
  const inputRef = useRef<HTMLInputElement>(null);

  if (hidden) {
    return null;
  }

  // 비제어일 때의 값은 `FoxSelect`가 이미 들고 있다 — 여기서 또 들면 두 벌이 어긋난다.
  const handleDetail = (next: string) => {
    onChange?.(next);

    // 켜짐 여부는 DOM에서 읽는다 — 라디오에서 형제 칸을 고르면 이 칸이 조용히 꺼지므로 따로
    // 들고 있으면 어긋난다. 이미 켜져 있으면 다시 눌러 끄지 않는다.
    if (inputRef.current && !inputRef.current.checked) {
      inputRef.current.click();
    }
  };

  // 두 컨트롤이 같은 props를 받는다. 다른 것은 change가 무엇을 넘기는지뿐이다.
  const shared = {
    ref: inputRef,
    name,
    value,
    label,
    description,
    size,
    checked,
    defaultChecked,
    disabled,
  };

  return (
    <div className={cx("fox-conditional-option", ORIENTATION_CLASS[orientation], className)}>
      {control === "checkbox" ? (
        // 체크박스는 끌 때도 뛰므로 켜짐 여부를 그대로 넘긴다.
        <FoxCheckbox {...shared} onChange={(next) => onCheckedChange?.(next)} />
      ) : (
        // 라디오는 켜질 때만 뛴다 — 그래서 `true`로 고정해 넘긴다.
        <FoxRadio {...shared} onChange={() => onCheckedChange?.(true)} />
      )}

      <div className="fox-conditional-option__detail">
        <FoxSelect
          size="md"
          options={options}
          value={detail}
          defaultValue={defaultDetail}
          placeholder={placeholder}
          onValueChange={handleDetail}
          disabled={disabled}
        />
      </div>
    </div>
  );
}
