"use client";

import {
  Children,
  Fragment,
  cloneElement,
  isValidElement,
  type ReactElement,
  type ReactNode,
  type Ref,
} from "react";
import { cx } from "../../utils";
import type { FoxChipSize } from "../fox-chip";

export interface FoxChipAreaProps {
  /**
   * 자식 칩의 `size`를 전부 이 값으로 덮어쓴다. 넘기지 않으면 자식이 각자 정한다.
   *
   * `FoxTagList`와 달리 `type`은 덮어쓰지 않는다 — 한 줄에 계열이 섞이는 것이 칩에서는
   * 정상이기 때문이다(예: `기간 ∨` 옆에 `전체`·`입금`). 크기만 통일한다.
   */
  size?: FoxChipSize;
  /** 묶음을 읽어 줄 이름. 화면에 보이는 제목이 이미 있으면 `labelledBy`를 쓴다. */
  label?: string;
  /** 묶음 이름 역할을 하는 요소의 id. `label`보다 우선한다 — 화면의 글자와 어긋나지 않는다. */
  labelledBy?: string;
  /** 칩이 한 줄에 다 들어가지 않으면 다음 줄로 흘린다(`FoxButtonGroup`과 같은 규약). */
  wrap?: boolean;
  /** `FoxChip`들. */
  children?: ReactNode;
  /** 배치 조정용. */
  className?: string;
  ref?: Ref<HTMLDivElement>;
}

type Overrides = { size?: FoxChipSize };

/**
 * 자식 칩에 묶음 값을 강제로 덮어쓴다.
 *
 * - 호스트 요소(`div` 등)는 건드리지 않는다 — DOM에 없는 속성이 넘어가면 React가 경고한다.
 * - `Children.map`은 프래그먼트 안으로 들어가지 않아 직접 내려간다. 그러지 않으면
 *   `<>…</>`로 감싼 칩들이 덮어쓰기를 피해 가고 Fragment에 `size`가 붙어 경고가 난다.
 *
 * `FoxTagList`의 같은 함수와 규칙이 같다 — 다른 점은 덮어쓰는 값이 `size` 하나라는 것뿐이다.
 */
function overrideChildren(children: ReactNode, overrides: Overrides): ReactNode {
  return Children.map(children, (child) => {
    if (!isValidElement(child)) {
      return child;
    }

    if (child.type === Fragment) {
      const fragment = child as ReactElement<{ children?: ReactNode }>;
      return overrideChildren(fragment.props.children, overrides);
    }

    if (typeof child.type === "string") {
      return child;
    }

    return cloneElement(child as ReactElement<Record<string, unknown>>, overrides);
  });
}

/**
 * @fox 칩 묶음. 배치와 `size` 통일만 책임지고 상태를 갖지 않는다 — 무엇이 켜져 있는지는
 * 각 칩이(또는 칩에게 값을 주는 호출부가) 소유한다.
 *
 * 방향 수식어가 없다 — 칩은 가로로 나란히 놓이는 것이 유일한 배치다.
 *
 * `role="radiogroup"`이 아니라 `role="group"`이다 — 하나만 고르는 묶음이 아니고, 각 칩이
 * 독립적으로 Tab을 받는 버튼이다(`FoxTagList`와 같은 근거).
 *
 * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
 * (또는 개별 파티셜)로 한 번 불러와야 한다.
 */
export function FoxChipArea({
  size,
  label,
  labelledBy,
  wrap = false,
  children,
  className,
  ref,
}: FoxChipAreaProps) {
  // 값을 준 것만 넣는다 — `undefined`를 그대로 넘기면 자식이 스스로 정한 값을 지운다.
  const overrides: Overrides = {};
  if (size !== undefined) {
    overrides.size = size;
  }

  return (
    <div
      ref={ref}
      role="group"
      aria-label={labelledBy ? undefined : label}
      aria-labelledby={labelledBy}
      className={cx("fox-chip-area", wrap && "fox-chip-area--wrap", className)}
    >
      {overrideChildren(children, overrides)}
    </div>
  );
}
