/**
 * Radio / RadioGroup — B端设计系统 (Tailwind 内联)
 *
 * 单选组：API 对齐 HiUI Radio（RadioGroup + Radio、value/defaultValue/onChange、禁用）。
 * **选型**：互斥单选且选项少（建议 ≤5）、需平铺展示 → Radio；选项多或占位窄 → `Select`；多选 → `CheckboxGroup`；单布尔即时切换 → `Switch`。
 * 视觉参考 HIUIpackage 内 @douyinfe/semi-ui 的 `.semi-radio` 规范（umd/view.css）：
 * 默认 16×16px、1px 边框（未选）、hover/active 填充态、选中为实心主色圆 + 中心白点、
 * 纵向组 row-gap 12px、横向组 gap 16px、项内图文间距 8px、指示器 margin-top 2px 与 20px 行高对齐。
 *
 * @component RadioGroup
 * @prop {'brand'|'black'} [variant='brand'] — 色系：brand 选中绿色、black 选中深灰
 * @prop {'basic'|'card'|'pureCard'} [styleType='basic'] — 样式：基础样式 / 带圆点单选卡片 / 单选卡片
 * @prop {'vertical'|'horizontal'} [layout='vertical'] — 布局：vertical 纵向 12px / horizontal 横向 16px
 * @prop {boolean} [disabled=false] — 禁用整组
 * @prop {string} [value] — 受控选中值
 * @prop {string} [defaultValue] — 非受控初始值
 * @prop {(value, event) => void} [onChange] — 选中回调
 * @prop {string} [name] — 原生 name（同组共享，未传时自动生成）
 * @prop {string} [className='']
 *
 * @component Radio（须在 RadioGroup 内）
 * @prop {string} value — 选项标识（必填）
 * @prop {boolean} [disabled=false] — 单项禁用
 * @prop {string} [className='']
 * @prop {ReactNode} children — 文案
 */

import {
  createContext,
  useContext,
  useId,
  useRef,
  useLayoutEffect,
  useEffect,
  useMemo,
  useState,
  useCallback,
} from 'react';
import Tooltip from './Tooltip';

const RadioContext = createContext(null);

/* ── 布局方向 → 纵向组距 12px / 横向组距 16px ── */
const LAYOUT_CLASS = {
  vertical: 'flex flex-col gap-3',
  horizontal: 'flex w-full flex-row flex-wrap items-start gap-4',
};

const CARD_LAYOUT_CLASS = {
  vertical: 'flex flex-col gap-3',
  horizontal: 'flex w-full flex-row flex-wrap items-start gap-4',
};

/* ── 基础 → 组容器字体继承 ── */
const GROUP_BASE = '[font-family:inherit]';

const LABEL_ROW = 'group inline-flex items-start gap-2 select-none rounded-sm';
const CARD_LABEL_BASE = [
  'group inline-flex h-[46px] max-w-full select-none items-center justify-start rounded-md',
  'border border-solid bg-white px-4 text-sm leading-[20px] transition-colors tfds-motion-ui-fast',
].join(' ');
const CARD_WITH_DOT_SIZE = 'min-w-[128px] gap-2';
const PURE_CARD_SIZE = 'min-w-[104px]';
const CARD_TEXT = 'block min-w-0 flex-1 truncate text-left';
const CARD_TOOLTIP_TRIGGER = 'block min-w-0 flex-1';

/* ── 指示器 → 内包裹层，margin-top 2px 与 20px 行高对齐 ── */
const INNER_WRAP = 'relative mt-[2px] inline-flex shrink-0';

/* ── 指示圈 → 外圈基础样式（16×16、1px solid、圆角 full） ── */
const OUTER_BASE = [
  'relative flex shrink-0 items-center justify-center rounded-full',
  'border border-solid transition-colors tfds-motion-ui-fast',
].join(' ');

const OUTER_SIZE = 'size-[16px]';

const INNER_DOT = 'size-[6px]';

const LABEL_TEXT = 'text-sm leading-[20px]';

const FOCUS_OUTLINE = {
  brand: 'has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-brand-200',
  black: 'has-[:focus-visible]:outline has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-grey-400',
};

function OverflowTooltipText({
  children,
  triggerClassName,
  textClassName,
  textStyle,
}) {
  const textRef = useRef(null);
  const [showTooltip, setShowTooltip] = useState(false);

  const measureOverflow = useCallback(() => {
    const el = textRef.current;
    if (!el) return;
    setShowTooltip(el.scrollWidth - el.clientWidth > 1);
  }, []);

  useLayoutEffect(() => {
    measureOverflow();
  }, [children, measureOverflow]);

  useEffect(() => {
    const el = textRef.current;
    if (!el) return undefined;

    measureOverflow();

    let observer;
    if (typeof ResizeObserver !== 'undefined') {
      observer = new ResizeObserver(() => measureOverflow());
      observer.observe(el);
    }

    const handleResize = () => measureOverflow();
    window.addEventListener('resize', handleResize);

    return () => {
      observer?.disconnect();
      window.removeEventListener('resize', handleResize);
    };
  }, [measureOverflow]);

  const textNode = (
    <span
      ref={textRef}
      className={textClassName}
      style={textStyle}
    >
      {children}
    </span>
  );

  if (!showTooltip) {
    return (
      <span className={[triggerClassName, textClassName].filter(Boolean).join(' ')} style={textStyle} ref={textRef}>
        {children}
      </span>
    );
  }

  return (
    <Tooltip content={children} placement="top" triggerClassName={triggerClassName}>
      {textNode}
    </Tooltip>
  );
}

function buildCardLabelClass(checked, disabled, variant, styleType) {
  const widthCls = styleType === 'card' ? CARD_WITH_DOT_SIZE : PURE_CARD_SIZE;
  const selectedCls = variant === 'black'
    ? [
        'border-grey-950 !bg-[var(--fill-default,var(--color-fill))] text-foreground',
        'hover:border-grey-900 hover:bg-blueGrey-100',
        'active:border-grey-800',
      ].join(' ')
    : [
        'border-border-brand !bg-[var(--color-brand-50)] text-foreground',
        'hover:border-brand-600 hover:bg-brand-100',
        'active:border-brand-700',
      ].join(' ');

  if (disabled) {
    return [
      CARD_LABEL_BASE,
      widthCls,
      'cursor-not-allowed border-border-default bg-disabled text-foreground-disabled opacity-75',
    ].join(' ');
  }

  return [
    CARD_LABEL_BASE,
    widthCls,
    checked
      ? selectedCls
      : 'cursor-pointer border-border-default text-foreground hover:border-border-strong hover:bg-fill',
  ].join(' ');
}

function buildDisplayClass(checked, disabled, variant) {
  const sz = OUTER_SIZE;
  if (disabled) {
    if (checked) {
      if (variant === 'black') {
        return [
          OUTER_BASE, sz,
          'opacity-75 bg-blueGrey-400 border-blueGrey-400',
        ].join(' ');
      }
      return [
        OUTER_BASE, sz,
        'opacity-75 bg-brand-200 border-brand-200',
      ].join(' ');
    }
    return [
      OUTER_BASE, sz,
      'opacity-75 bg-disabled border-border-default',
    ].join(' ');
  }

  if (checked) {
    if (variant === 'black') {
      return [
        OUTER_BASE, sz,
        'bg-grey-950 border-grey-950',
        'group-hover:bg-grey-900 group-hover:border-grey-900',
        'group-active:bg-grey-800 group-active:border-grey-800',
      ].join(' ');
    }
    return [
      OUTER_BASE, sz,
      'bg-brand-500 border-brand-500',
      'group-hover:bg-brand-600 group-hover:border-brand-600',
      'group-active:bg-brand-700 group-active:border-brand-700',
    ].join(' ');
  }

  return [
    OUTER_BASE, sz,
    'border-foreground-muted bg-transparent',
    variant === 'black'
      ? 'group-hover:bg-fill group-hover:border-grey-950'
      : 'group-hover:bg-fill group-hover:border-border-brand',
    'group-active:bg-blueGrey-100',
  ].join(' ');
}

export function Radio({ value, disabled: itemDisabled = false, className = '', children }) {
  const ctx = useContext(RadioContext);
  if (!ctx) return null;

  const {
    selected,
    setSelected,
    groupDisabled,
    variant,
    styleType,
    name,
  } = ctx;

  const disabled = groupDisabled || itemDisabled;
  const checked = String(selected) === String(value);
  const fo = FOCUS_OUTLINE[variant] || FOCUS_OUTLINE.brand;

  const displayCls = buildDisplayClass(checked, disabled, variant);

  const dot = INNER_DOT;
  const textCls = LABEL_TEXT;

  const onChange = useCallback((e) => {
    if (disabled) return;
    setSelected(value, e);
  }, [disabled, setSelected, value]);

  if (styleType === 'card' || styleType === 'pureCard') {
    const cardCls = buildCardLabelClass(checked, disabled, variant, styleType);
    const showIndicator = styleType === 'card';
    const cardStyle = checked && !disabled
      ? {
          backgroundColor: variant === 'black'
            ? 'var(--fill-default, var(--color-fill))'
            : 'var(--color-brand-50)',
        }
      : undefined;

    return (
      <label
        className={[`tfds-radio`, cardCls, fo, className].filter(Boolean).join(' ')}
        style={cardStyle}
        data-tfds-component="Radio"
      >
        <input
          type="radio"
          name={name}
          value={String(value)}
          checked={checked}
          disabled={disabled}
          onChange={onChange}
          className="sr-only"
        />
        {showIndicator ? (
          <span className={displayCls} aria-hidden>
            {checked ? (
              <span className={`rounded-full bg-white ${dot}`} />
            ) : null}
          </span>
        ) : null}
        {children != null && children !== false ? (
          <OverflowTooltipText
            triggerClassName={CARD_TOOLTIP_TRIGGER}
            textClassName={[
              CARD_TEXT,
              checked ? '![font-weight:var(--font-semibold)]' : '',
              disabled ? 'text-foreground-disabled' : 'text-current',
            ].join(' ')}
            textStyle={checked ? { fontWeight: 'var(--font-semibold)' } : undefined}
          >
            {children}
          </OverflowTooltipText>
        ) : null}
      </label>
    );
  }

  return (
    <label
      className={[`tfds-radio`, [
        LABEL_ROW,
        fo,
        disabled ? 'cursor-not-allowed' : 'cursor-pointer',
        className,
      ].filter(Boolean).join(' ')].filter(Boolean).join(' ')}
     data-tfds-component="Radio">
      <span className={INNER_WRAP}>
        <input
          type="radio"
          name={name}
          value={String(value)}
          checked={checked}
          disabled={disabled}
          onChange={onChange}
          className="sr-only"
        />
        <span className={displayCls} aria-hidden>
          {checked ? (
            <span className={`rounded-full bg-white ${dot}`} />
          ) : null}
        </span>
      </span>
      {children != null && children !== false ? (
        <span
          className={[
            textCls,
            disabled ? 'text-foreground-disabled' : 'text-foreground',
          ].filter(Boolean).join(' ')}
        >
          {children}
        </span>
      ) : null}
    </label>
  );
}

export default function RadioGroup({
  variant = 'brand',
  styleType = 'basic',
  size: _size = 'md',
  layout = 'vertical',
  disabled = false,
  value,
  defaultValue,
  onChange,
  name: nameProp,
  className = '',
  children,
  ...rest
}) {
  const uid = useId();
  const name = nameProp ?? `radio-group-${uid.replace(/:/g, '')}`;
  const isControlled = value !== undefined;
  const [inner, setInner] = useState(defaultValue);

  const selected = isControlled ? value : inner;

  const setSelected = useCallback((next, e) => {
    if (!isControlled) setInner(next);
    onChange?.(next, e);
  }, [isControlled, onChange]);

  const ctxValue = useMemo(() => ({
    selected,
    setSelected,
    groupDisabled: disabled,
    variant,
    styleType,
    name,
  }), [selected, setSelected, disabled, variant, styleType, name]);

  const layoutMap = styleType === 'card' || styleType === 'pureCard' ? CARD_LAYOUT_CLASS : LAYOUT_CLASS;
  const layoutCls = layoutMap[layout] || layoutMap.vertical;
  const sizeText = 'text-sm';

  return (
    <RadioContext.Provider value={ctxValue}>
      <div
        role="radiogroup"
        className={[GROUP_BASE, sizeText, 'leading-[20px]', layoutCls, className].filter(Boolean).join(' ')}
        {...rest}
      >
        {children}
      </div>
    </RadioContext.Provider>
  );
}
