/**
 * Filter — B 端筛选胶囊项
 *
 * 用于筛选栏中的单个触发器/已选筛选条件。传入 `options` 时，下拉面板**默认**基于
 * `Dropdown` 的 **checkbox 多选列表**（`Dropdown.List` + `selectionIndicator="leading-checkbox"`）；
 * 仅 `multiple={false}` 时切换为行尾 ✓ 的单选列表。
 *
 * **选项列表**：仅展示业务筛选项（如「商家主页」「预约到店」），**不提供「全部」类选项**；
 * 未筛选 = 不勾选任何项，触发器仅显示 `label`。
 *
 * **默认展示**：未选中任何项时，触发器**仅显示 `label` 筛选名称**，不展示 `：value`；右侧为下拉箭头。
 *
 * @prop {string} [label='筛选项'] — 筛选项名称
 * @prop {string|number|null} [value=null] — 已选值，存在时显示在 label 后
 * @prop {Array<{label:string,value:string|number,disabled?:boolean}>} [options=[]] — 业务筛选项（禁止含「全部」/ value=all）
 * @prop {boolean} [multiple=true] — 是否多选（默认 true = checkbox 下拉）；`false` 为单选 ✓ 列表
 * @prop {Array<string|number>|string|number} [selectedValues] — 受控值；多选传数组、单选传单值（也兼容单元素数组）
 * @prop {Array<string|number>|string|number} [defaultValue] — 非受控初始值；**默认 `[]`（无任何勾选）**
 * @prop {function|null} [onChange=null] — 变更回调；多选返回数组，单选返回单值（或 null 已清空）
 * @prop {boolean} [selected=false] — 品牌色选中态
 * @prop {boolean} [filled=false] — 中性填充态，适合 hover/轻强调容器
 * @prop {boolean} [disabled=false] — 禁用态
 * @prop {boolean} [closable=false] — 有展示值时是否显示清除图标；已选值默认显示清除入口
 * @prop {function|null} [onClear=null] — 清除回调
 * @prop {string} [className=''] — 附加类名
 */

import {
  useCallback,
  useEffect,
  useId,
  useMemo,
  useRef,
  useState,
} from 'react';
import Dropdown from './Dropdown';

const PANEL_GAP = 4;
const PANEL_MAX_HEIGHT = 260;

const BASE = [
  'tfds-filter',
  'inline-flex h-[var(--size-control-md)] shrink-0 items-center justify-center gap-[var(--spacing-2)]',
  'rounded-[var(--radius-full)] border border-solid',
  'px-[var(--spacing-3)]',
  '[font-size:var(--text-sm)] leading-[var(--leading-5)] tracking-[var(--tracking-normal)]',
  '[font-family:inherit]',
  'select-none whitespace-nowrap outline-none',
  'transition-colors tfds-motion-ui-fast',
].join(' ');

const TONE_CLASS = {
  outline: [
    'bg-surface border-border-default text-foreground',
    'hover:border-border-strong',
    'active:bg-fill-active',
    'data-[open=true]:border-primary data-[open=true]:hover:border-primary',
  ].join(' '),
  fill: [
    'bg-fill border-border-default text-foreground',
    'hover:bg-fill-hover hover:border-border-strong',
    'active:bg-fill-active',
    'data-[open=true]:border-primary data-[open=true]:hover:border-primary',
  ].join(' '),
  selected: [
    'bg-brand-50 border-brand-300 text-brand-800',
    'hover:bg-brand-100 hover:border-brand-400',
    'active:bg-brand-100',
    'data-[open=true]:border-primary data-[open=true]:hover:border-primary',
  ].join(' '),
  disabled: [
    'bg-disabled border-grey-100 text-foreground-disabled',
    'cursor-not-allowed pointer-events-none',
  ].join(' '),
  selectedDisabled: [
    'bg-brand-50 border-brand-200 text-brand-300',
    'cursor-not-allowed pointer-events-none',
  ].join(' '),
};

const LABEL_CLASS = '[font-weight:var(--font-semibold)]';
const LABEL_DEFAULT_COLOR_CLASS = '[color:var(--tfds-text-secondary,var(--color-foreground-secondary))]';
const VALUE_CLASS = '[font-weight:var(--font-normal)]';
const ICON_CLASS = 'inline-flex size-[var(--spacing-3)] shrink-0 items-center justify-center [&>svg]:size-[var(--spacing-3)]';
const CLEAR_CLASS = [
  'inline-flex items-center justify-center shrink-0 size-[var(--spacing-4)]',
  'rounded-full cursor-pointer',
  'transition-opacity tfds-motion-ui-fast',
  'bg-transparent border-none p-0 mr-[var(--spacing-1)]',
].join(' ');
const CLEAR_DEFAULT_CLASS = 'text-foreground-disabled hover:text-foreground-secondary';
const CLEAR_SELECTED_CLASS = '![color:var(--color-brand-500)] hover:![color:var(--color-brand-700)]';

function ChevronIcon() {
  return (
    <svg viewBox="0 0 12 12" fill="none" aria-hidden="true">
      <path d="M3 4.5L6 7.5L9 4.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}

function ClearIcon() {
  return (
    <svg viewBox="0 0 16 16" fill="none" className="size-[var(--spacing-4)]" aria-hidden="true">
      <circle cx="8" cy="8" r="7" fill="currentColor" fillOpacity="0.15" />
      <path d="M5.5 5.5L10.5 10.5M10.5 5.5L5.5 10.5" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
    </svg>
  );
}

function getValueKey(item) {
  return String(item);
}

/** 历史配置中的「全部」项在运行时剔除，不再出现在面板中 */
function isExcludedAllOption(option) {
  if (!option) return true;
  if (getValueKey(option.value).toLowerCase() === 'all') return true;
  const label = String(option.label || '').trim();
  return label === '全部' || label.startsWith('全部');
}

function normalizeOptions(options) {
  const source = Array.isArray(options) && options.length > 0 ? options : [];
  return source
    .map((item) => {
      if (typeof item === 'string' || typeof item === 'number') {
        return { label: String(item), value: item };
      }
      if (!item || typeof item !== 'object') return null;
      const value = item.value ?? item.label;
      if (value === undefined || value === null || value === '') return null;
      return {
        label: item.label != null ? String(item.label) : String(value),
        value,
        disabled: item.disabled === true,
      };
    })
    .filter(Boolean)
    .filter((item) => !isExcludedAllOption(item));
}

function normalizeValueList(raw) {
  if (raw === undefined || raw === null || raw === '') return [];
  if (Array.isArray(raw)) {
    return raw.filter((item) => item !== undefined && item !== null && item !== '');
  }
  return [raw];
}

export default function Filter({
  label = '筛选项',
  value = null,
  options = [],
  multiple = true,
  selectedValues,
  defaultValue,
  onChange = null,
  selected = false,
  filled = false,
  disabled = false,
  closable = false,
  onClear = null,
  className = '',
  children,
  ...rest
}) {
  const uid = useId();
  const listboxId = `${uid}-filter-listbox`;
  const triggerRef = useRef(null);
  const normalizedOptions = useMemo(() => normalizeOptions(options), [options]);
  const hasDropdown = normalizedOptions.length > 0;
  const isControlled = selectedValues !== undefined;
  const [innerValues, setInnerValues] = useState(() => {
    const initial = defaultValue !== undefined ? normalizeValueList(defaultValue) : [];
    return multiple ? initial : initial.slice(0, 1);
  });
  const [open, setOpen] = useState(false);
  const currentValues = isControlled
    ? (multiple ? normalizeValueList(selectedValues) : normalizeValueList(selectedValues).slice(0, 1))
    : innerValues;
  const selectedKeySet = useMemo(
    () => new Set(currentValues.map(getValueKey)),
    [currentValues],
  );
  const selectedOptions = useMemo(
    () => normalizedOptions.filter((item) => selectedKeySet.has(getValueKey(item.value))),
    [normalizedOptions, selectedKeySet],
  );
  const hasExplicitValue = value !== null && value !== undefined && value !== '';
  const hasEffectiveFilter = selectedOptions.length > 0;
  const derivedValue = useMemo(() => {
    if (hasExplicitValue) return value;
    if (!hasEffectiveFilter) return null;
    if (selectedOptions.length === 1) return selectedOptions[0].label;
    if (!multiple) return null;
    if (selectedOptions.length > 1) return `已选 ${selectedOptions.length} 项`;
    return null;
  }, [hasEffectiveFilter, hasExplicitValue, multiple, selectedOptions, value]);
  const hasValue = derivedValue !== null && derivedValue !== undefined && derivedValue !== '';
  const isSelected = selected || hasEffectiveFilter;
  const tone = disabled
    ? (isSelected ? 'selectedDisabled' : 'disabled')
    : (isSelected ? 'selected' : (filled ? 'fill' : 'outline'));
  const showClear = !disabled && hasValue && (hasEffectiveFilter || (closable && hasExplicitValue));

  const commitValues = useCallback((nextValues, event) => {
    if (!isControlled) {
      setInnerValues(nextValues);
    }
    if (multiple) {
      onChange?.(nextValues, event);
    } else {
      onChange?.(nextValues[0] ?? null, event);
    }
  }, [isControlled, multiple, onChange]);

  const toggleOpen = useCallback(() => {
    if (disabled || !hasDropdown) return;
    setOpen((prev) => !prev);
  }, [disabled, hasDropdown]);

  const toggleOption = useCallback((option, event) => {
    if (option.disabled) return;
    const optionKey = getValueKey(option.value);
    const exists = selectedKeySet.has(optionKey);

    if (multiple) {
      const nextValues = exists
        ? currentValues.filter((item) => getValueKey(item) !== optionKey)
        : [...currentValues, option.value];
      commitValues(nextValues, event);
      return;
    }

    const nextValues = exists ? [] : [option.value];
    commitValues(nextValues, event);
    setOpen(false);
    triggerRef.current?.focus();
  }, [commitValues, currentValues, multiple, selectedKeySet]);

  const handleClear = (event) => {
    event.stopPropagation();
    if (disabled) return;
    if (hasDropdown) {
      commitValues([], event);
      setOpen(false);
    }
    onClear?.(event);
    triggerRef.current?.focus();
  };

  const handleKeyDown = (event) => {
    if (disabled || !hasDropdown) return;
    if (event.key === 'Enter' || event.key === ' ') {
      event.preventDefault();
      toggleOpen();
    }
    if (event.key === 'Escape') {
      setOpen(false);
    }
  };

  useEffect(() => {
    if (!open) return undefined;
    const handlePointerDown = (event) => {
      const target = event.target;
      if (triggerRef.current?.contains(target)) return;
      const panelEl = document.getElementById(listboxId);
      if (panelEl?.contains(target)) return;
      setOpen(false);
    };
    document.addEventListener('mousedown', handlePointerDown);
    return () => document.removeEventListener('mousedown', handlePointerDown);
  }, [open, listboxId]);

  const listPanel = (
    <Dropdown.Panel
      open={open && !disabled && hasDropdown}
      triggerRef={triggerRef}
      gap={PANEL_GAP}
      maxHeight={PANEL_MAX_HEIGHT}
      id={listboxId}
      role="listbox"
    >
      <Dropdown.List
        mode="select"
        selectionIndicator={multiple ? 'leading-checkbox' : 'leading-check'}
        multiple={multiple}
      >
        {normalizedOptions.map((option, index) => {
          const checked = selectedKeySet.has(getValueKey(option.value));
          return (
            <Dropdown.Item
              key={`${getValueKey(option.value)}-${index}`}
              value={option.value}
              label={option.label}
              selected={checked}
              disabled={option.disabled}
              onMouseDown={(event) => event.preventDefault()}
              onClick={(event) => toggleOption(option, event)}
            />
          );
        })}
      </Dropdown.List>
    </Dropdown.Panel>
  );

  return (
    <>
      <div
        ref={triggerRef}
        role={hasDropdown ? 'combobox' : 'button'}
        tabIndex={disabled ? -1 : 0}
        className={[
          BASE,
          TONE_CLASS[tone],
          disabled ? '' : 'cursor-pointer',
          className,
        ].filter(Boolean).join(' ')}
        aria-disabled={disabled || undefined}
        data-tfds-component="Filter"
        data-open={open || undefined}
        data-selected={isSelected || undefined}
        data-filled={filled || undefined}
        data-multiple={multiple ? undefined : 'false'}
        aria-expanded={hasDropdown ? open : undefined}
        aria-haspopup={hasDropdown ? 'listbox' : undefined}
        aria-controls={hasDropdown ? listboxId : undefined}
        onClick={toggleOpen}
        onKeyDown={handleKeyDown}
        {...rest}
      >
        <span className={[
          LABEL_CLASS,
          tone === 'outline' || tone === 'fill' ? LABEL_DEFAULT_COLOR_CLASS : '',
        ].filter(Boolean).join(' ')}>{label}</span>
        {hasValue ? (
          <span className={VALUE_CLASS}>
            <span aria-hidden="true">：</span>
            {derivedValue}
          </span>
        ) : null}
        {children}
        {showClear ? (
          <button
            type="button"
            className={[
              CLEAR_CLASS,
              isSelected ? CLEAR_SELECTED_CLASS : CLEAR_DEFAULT_CLASS,
            ].filter(Boolean).join(' ')}
            tabIndex={-1}
            aria-label="清除"
            onClick={handleClear}
          >
            <ClearIcon />
          </button>
        ) : (
          <span className={ICON_CLASS} aria-hidden="true">
            <ChevronIcon />
          </span>
        )}
      </div>
      {listPanel}
    </>
  );
}
