import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Avatar from './Avatar';
import Button from './Button';
import { Checkbox } from './Checkbox';
import Dropdown from './Dropdown';
import Filter from './Filter';
import Icon from './Icon';
import Input from './Input';
import Select from './Select';
import Switch from './Switch';
import Skeleton from './Skeleton';
import Tag from './Tag';
import Tooltip from './Tooltip';
import { getTeamAvatarBySeed, getTeamMemberByIndex } from '../teamMembers';

/**
 * Table — B端业务列表表格（Tailwind 内联）
 *
 * 对齐 Figma 业务表格样式，覆盖标题、标签、描述、创建人、创建时间、操作区和分页区。
 * 组件默认沉淀业务列表场景，同时保留列级 render 扩展能力，适合后台内容管理、策略管理、知识库列表等场景。
 * avatar / avatarText 单元格未传 avatarSrc 时，会按 name/description 从本地成员头像素材中取默认图片。
 *
 * @prop {Array<object>} [columns=[]] — 列配置，支持 title / key / dataIndex / width / minWidth / align / type / render
 *   type="actions" 会被自动归位到表格尾栏，并在横向空间不足时 sticky 固定在右侧可视区
 * @prop {Array<object>} [dataSource=[]] — 行数据
 * @prop {'table'|'card-form'} [variant='table'] — 展示类型：table 为标准表格；card-form 为卡片型表单
 * @prop {string|((record: object, index: number) => string|number)} [rowKey='id'] — 行 key
 * @prop {object|null} [pagination=null] — 分页配置：current / pageSize / total / pageSizeOptions / summaryText / displayPages / pageSizeLabel
 * @prop {Array<string|number>} [expandedRowKeys] — 卡片型表单受控展开项
 * @prop {Array<string|number>} [defaultExpandedRowKeys=[]] — 卡片型表单默认展开项
 * @prop {(keys: Array<string|number>) => void} [onExpandedRowKeysChange=null] — 卡片型表单展开变化回调
 * @prop {(record: object, context: object) => void} [onView=null] — 卡片型表单查看操作
 * @prop {(record: object, context: object) => void} [onMore=null] — 卡片型表单更多操作
 * @prop {(page: number) => void} [onPageChange=null] — 页码变更回调
 * @prop {(pageSize: number) => void} [onPageSizeChange=null] — 每页条数变更回调
 * @prop {boolean} [showSearchFilters=true] — 标准表格是否显示顶部搜索筛选栏；仅 variant="table" 生效
 * @prop {string} [searchPlaceholder='搜索表格内容'] — 顶部搜索框占位文案
 * @prop {string|number} [searchInputWidth='240px'] — 顶部搜索框宽度，窄容器下自动不超过 100%
 * @prop {string} [searchValue] — 顶部搜索框受控值
 * @prop {string} [defaultSearchValue] — 顶部搜索框默认值
 * @prop {(value: string, event: Event) => void} [onSearchChange=null] — 搜索框变更回调
 * @prop {Array<object>} [searchFilterItems] — 顶部 4 个 Filter 配置，默认按当前表头语义生成
 * @prop {(item: object, value: Array<string|number>|string|number|null) => void} [onSearchFilterChange=null] — Filter 变更回调
 * @prop {string} [emptyText='暂无数据'] — 空态文案
 * @prop {boolean} [loading=false] — 首屏/刷新加载态：保留表头与搜索筛选，表体渲染 Skeleton 占位，隐藏分页
 * @prop {number} [loadingRowCount=6] — loading 时 Skeleton 行数
 * @prop {string} [className=''] — 附加类名
 */

/* ── 默认列宽（对齐 Figma） ── */
const TYPE_ALIAS_MAP = {
  title: 'link',
  tags: 'tag',
  description: 'text',
  creator: 'avatar',
  datetime: 'datetime',
  actions: 'actions',
};

const DEFAULT_COLUMN_WIDTH = {
  text: 162,
  link: 188,
  iconText: 176,
  textButton: 186,
  status: 130,
  tag: 112,
  switch: 108,
  checkbox: 72,
  avatar: 168,
  avatarText: 220,
  linkDescription: 220,
  image: 132,
  progress: 164,
  datetime: 180,
  actions: 104,
  dragHandle: 68,
};

const MIN_COLUMN_WIDTH = {
  text: 116,
  link: 132,
  iconText: 144,
  textButton: 148,
  status: 112,
  tag: 96,
  switch: 96,
  checkbox: 56,
  avatar: 132,
  avatarText: 168,
  linkDescription: 168,
  image: 112,
  progress: 132,
  datetime: 156,
  actions: 96,
  dragHandle: 52,
};

const CELL_SIZE_CLASS = {
  default: 'px-3 py-3',
  middle: 'px-3 py-2',
  small: 'px-2 py-1',
};

const HEADER_SIZE_CLASS = {
  default: 'px-3 py-3',
  middle: 'px-3 py-2',
  small: 'px-2 py-1',
};

const HEADER_MIN_HEIGHT = {
  default: 44,
  middle: 36,
  small: 28,
};

const TYPE_MIN_HEIGHT = {
  text: { default: 44, middle: 36, small: 28 },
  link: { default: 44, middle: 36, small: 28 },
  iconText: { default: 44, middle: 36, small: 28 },
  textButton: { default: 44, middle: 36, small: 28 },
  status: { default: 44, middle: 36, small: 28 },
  tag: { default: 44, middle: 36, small: 28 },
  switch: { default: 48, middle: 40, small: 32 },
  checkbox: { default: 44, middle: 36, small: 28 },
  avatar: { default: 44, middle: 36, small: 28 },
  avatarText: { default: 64, middle: 56, small: 48 },
  linkDescription: { default: 64, middle: 56, small: 48 },
  image: { default: 72, middle: 64, small: 56 },
  progress: { default: 44, middle: 36, small: 28 },
  datetime: { default: 44, middle: 36, small: 28 },
  actions: { default: 48, middle: 40, small: 32 },
  dragHandle: { default: 44, middle: 36, small: 28 },
};

/* ── 容器 / 表格 ──
 * Table 自身不带白色背景、不带四周 padding、不带圆角；
 * 由外部容器（业务白卡 / 预览容器）决定外观与留白。
 * 表头默认使用 Blue Grey 100，sticky 固定列保持不透明，
 * 用于保证横向滚动时表头、固定列和内容层级清晰。
 */
const WRAPPER = [
  'tfds-table',
  'flex h-full min-h-0 w-full flex-col',
  '[font-family:Inter,"PingFang_SC","PingFang_TC","Hiragino_Sans_GB","Microsoft_YaHei",sans-serif]',
].join(' ');

const TABLE_SHELL = [
  'flex h-full min-h-0 w-full flex-1 flex-col',
  '[font-family:Inter,"PingFang_SC","PingFang_TC","Hiragino_Sans_GB","Microsoft_YaHei",sans-serif]',
].join(' ');
const SEARCH_FILTER_BAR = 'flex shrink-0 flex-wrap items-center gap-2 pb-3';
const SEARCH_FILTER_INPUT_STYLE = { '--size-input-width': 'min(240px,100%)' };

const TABLE = 'flex w-full min-w-0 flex-1 min-h-0 flex-col';
const TABLE_VIEWPORT = 'flex flex-col flex-1 min-h-0 w-full overflow-auto';
const TABLE_CONTENT = 'flex w-full flex-1 min-h-0 flex-col';
const TABLE_BODY = 'flex-1 min-h-0 w-full';

/* ── 表头 / 单元格 ──
 * Table 自身不带外层背景；表头统一使用 Blue Grey 100，
 * 表体由外部容器或默认 surface 决定底色。
 */
const HEADER_ROW = 'sticky top-0 z-40 grid w-full min-w-0 bg-blueGrey-100';
const BODY_ROW = 'grid w-full min-w-0';

const HEADER_CELL = [
  'flex w-full min-w-0 items-center justify-start gap-2 border-b-2 border-border-default text-left',
  'text-left text-sm [font-weight:var(--font-semibold)] leading-5 text-foreground-muted',
].join(' ');

const BODY_CELL = [
  'flex w-full min-w-0 items-center justify-start border-b border-border-default text-left',
  'text-left text-sm font-normal leading-5 text-foreground',
].join(' ');

/* ── 通用文本截断 ── */
const TRUNCATE_TEXT = 'block w-full min-w-0 truncate text-left';
const SECONDARY_TEXT = 'block w-full min-w-0 truncate text-left text-xs leading-4 text-foreground-muted';
const HEADER_TEXT = 'block w-full min-w-0 truncate text-left text-sm [font-weight:var(--font-semibold)] leading-5 text-foreground-muted';
const PLAIN_TEXT = 'block w-full min-w-0 truncate text-left text-sm font-normal leading-5 text-foreground';
const INLINE_PLAIN_TEXT = 'block min-w-0 truncate text-left text-sm font-normal leading-5 text-foreground';
const EMPHASIS_TEXT = 'block w-full min-w-0 truncate text-left [font-weight:var(--font-semibold)]';
const ACTION_FULL_TEXT = 'block whitespace-nowrap [font-weight:var(--font-semibold)]';
const ELLIPSIS_TOOLTIP_WRAP = 'block w-full min-w-0';
/* ── 标题列 ──
 * link 列单独跟随全局 text-link token（brand 色阶）。
 * 用 !text-brand-* 覆盖 Button variant 自带的 text-brand-500 / hover / active。
 */
const TEXT_BRAND_BUTTON_CLASS = [
  '!h-auto !min-h-0 !w-full !max-w-full !min-w-0 !justify-start !gap-0 !border-transparent !p-0',
  '!text-left !text-sm !leading-5',
  '!text-brand-700 hover:!text-brand-800 active:!text-brand-900',
  '[&_span]:truncate',
].join(' ');
const ACTION_TEXT_BUTTON_CLASS = [
  '!h-auto !min-h-0 !justify-start !gap-0 !border-transparent !p-0',
  '!text-left !text-sm !leading-5',
].join(' ');
const ICON_ONLY_BUTTON_RESET = '!gap-0 !p-0';

/* ── 创建人列 ── */
const CREATOR_WRAP = 'flex w-full min-w-0 items-center justify-start gap-2 text-left';
const CREATOR_NAME = 'flex-1 min-w-0 truncate text-left text-sm font-normal leading-5 text-foreground';
const AVATAR_TEXT_WRAP = 'flex min-w-0 flex-1 flex-col items-start justify-center gap-1 text-left';

/* ── 操作区 ── */
const ACTION_WRAP = 'inline-flex w-max min-w-max items-center justify-start gap-2 text-left';
const ACTION_OVERFLOW_TRIGGER_CLASS = [
  ACTION_TEXT_BUTTON_CLASS,
  '!w-6 !justify-center',
].join(' ');
const TEXT_BUTTON_ICON_CLASS = [
  '!size-6 shrink-0 !rounded-md !border-transparent !p-0 !text-foreground',
  'hover:!bg-fill hover:!text-foreground active:!bg-fill',
].join(' ');
const DRAG_HANDLE_BUTTON_CLASS = [
  '!size-6 shrink-0 !rounded-md !border-transparent !p-0 !text-foreground-muted',
  'hover:!bg-fill hover:!text-foreground active:!bg-fill',
].join(' ');

/* ── 分页 ── */
const FOOTER = 'flex shrink-0 flex-wrap items-center justify-between gap-4 px-0 pt-3 pb-0';
const FOOTER_SUMMARY = 'text-sm font-normal leading-5 text-foreground-muted';
const FOOTER_RIGHT = 'flex items-center gap-4';
const PAGE_GROUP = 'flex items-center px-1';
const PAGE_LIST = 'flex items-center gap-1';

const PAGE_ARROW_BUTTON_CLASS = [
  '!size-9 !rounded-md !border-transparent !p-0 !text-foreground-muted',
  'hover:!text-foreground disabled:!text-foreground-disabled',
].join(' ');

const PAGE_NUMBER_BUTTON_CLASS = [
  '!size-8 !rounded-md !border-transparent !p-0',
  '!text-sm !font-normal !leading-5 !text-foreground',
  'hover:!bg-blueGrey-50 focus-visible:!outline-none focus-visible:!bg-blueGrey-50',
].join(' ');

const PAGE_BUTTON_ACTIVE = '!bg-brand-50 ![font-weight:var(--font-semibold)] !text-brand-600 hover:!bg-brand-50 focus-visible:!bg-brand-50';
const PAGE_BUTTON_ACTIVE_STYLE = { color: 'var(--color-brand-600)' };
const PAGE_ELLIPSIS = 'inline-flex size-8 items-center justify-center text-sm font-normal leading-5 text-foreground';

/* ── 空态 ── */
const EMPTY_CELL = 'px-4 py-10 text-center text-sm font-normal leading-5 text-foreground-muted';
const TABLE_HEADER_BACKGROUND = 'var(--color-blueGrey-100, #F9FAFB)';
const PINNED_SURFACE_BACKGROUND = 'var(--color-surface, #FFFFFF)';

/* ── 卡片型表单 ── */
const CARD_FORM_BODY = 'flex min-h-0 flex-1 flex-col gap-3 overflow-y-auto';
const CARD_FORM_ITEM = 'flex shrink-0 flex-col overflow-hidden rounded-xl border border-border-default bg-surface transition-shadow tfds-motion-ui-fast';
const CARD_FORM_PARENT = [
  'flex items-center px-8 py-4 transition-colors tfds-motion-ui-fast',
  'hover:bg-blueGrey-50',
].join(' ');
const CARD_FORM_PARENT_STATIC = 'flex items-center px-8 py-4';
const CARD_FORM_TOGGLE_WRAP = 'shrink-0 transition-transform tfds-motion-ui-normal';
const CARD_FORM_MAIN = 'ml-4 flex min-w-0 flex-1 flex-col gap-1.5 overflow-hidden';
const CARD_FORM_TITLE = 'block w-full min-w-0 truncate text-base [font-weight:var(--font-semibold)] leading-6 text-foreground';
const CARD_FORM_SUBTITLE = 'block w-full min-w-0 truncate text-xs leading-4 text-foreground-muted';
const CARD_FORM_ASIDE = 'ml-4 flex shrink-0 items-center gap-8';
const CARD_FORM_CHILDREN = 'flex flex-col gap-2 px-4 pb-4';
const CARD_FORM_VERSION_ROW = [
  'flex items-center rounded-lg bg-blueGrey-100 p-4 transition-colors tfds-motion-ui-fast',
  'hover:bg-blueGrey-200',
].join(' ');
const CARD_FORM_VERSION_BADGE = 'inline-flex size-6 shrink-0 items-center justify-center rounded-md bg-blueGrey-900 text-[11px] [font-weight:var(--font-bold)] leading-none text-white';
const CARD_FORM_VERSION_TITLE = 'ml-4 min-w-0 flex-[0_1_180px]';
const CARD_FORM_VERSION_TITLE_TEXT = 'block w-full min-w-0 truncate text-xs leading-5 text-foreground-secondary';
const CARD_FORM_VERSION_STATUS = 'ml-3 shrink-0';
const CARD_FORM_METRICS = 'ml-5 mr-8 min-w-0 flex-1 overflow-hidden';
const CARD_FORM_METRICS_LINE = 'block min-w-0 overflow-hidden text-ellipsis whitespace-nowrap text-right text-xs leading-4';
const CARD_FORM_RIGHT = 'ml-4 flex shrink-0 items-center gap-8';
const CARD_FORM_USER_DATE = 'flex items-center gap-1.5';
const CARD_FORM_DATE = 'block min-w-0 truncate whitespace-nowrap text-xs leading-4 text-foreground-muted';
const CARD_FORM_ACTIONS = 'flex items-center gap-2';

const CARD_FORM_STATUS_VARIANT = {
  线上生效: 'green',
  暂未生效: 'grey',
  草稿中: 'grey',
  实验中: 'blue',
  已发布: 'green',
  已下线: 'grey',
};

const SEARCH_FILTER_FALLBACK_TITLES = ['业务状态', '所属类目', '创建人', '更新时间'];
const SEARCH_FILTER_OPTIONS = {
  link: ['春季团购', '门店直播', '周末套餐'],
  text: ['商家主页', '预约到店', '高意向用户'],
  iconText: ['平台推荐', '重点扶持', '履约加分'],
  textButton: ['待补充', '已完善', '需复核'],
  status: ['生效中', '待上线', '已停用'],
  tag: ['到店餐饮', '新客引流', '品牌连锁'],
  switch: ['已开启', '已关闭', '待确认'],
  checkbox: ['已勾选', '未勾选', '部分勾选'],
  avatar: ['段然', '程程murphy', '李思儒'],
  avatarText: ['商家运营', '投放经理', '审核同学'],
  linkDescription: ['联合活动', '达人探店', '预约服务'],
  image: ['已上传', '待补充', '审核中'],
  progress: ['低于 30%', '30%-70%', '高于 70%'],
  datetime: ['近 7 天', '近 30 天', '更早'],
  actions: ['可编辑', '可查看', '可下线'],
  dragHandle: ['已排序', '待调整', '不可拖拽'],
};

function isFirstColumnFixed(mode) {
  return mode === 'first' || mode === 'both';
}

function isLastColumnFixed(mode) {
  return mode === 'last' || mode === 'both';
}

function normalizeColumnWidth(column) {
  if (column.width != null) return column.width;
  const type = normalizeColumnType(column.type);
  return DEFAULT_COLUMN_WIDTH[type] ?? undefined;
}

function normalizeColumnType(type) {
  if (!type) return 'text';
  return TYPE_ALIAS_MAP[type] || type;
}

function normalizeCellSize(cellSize) {
  if (cellSize === 'middle' || cellSize === 'small') return cellSize;
  return 'default';
}

function isActionsColumn(column) {
  return normalizeColumnType(column?.type) === 'actions';
}

function normalizeTableColumns(columns) {
  if (!Array.isArray(columns) || columns.length === 0) return [];
  const regularColumns = [];
  const actionColumns = [];
  columns.forEach((column) => {
    if (isActionsColumn(column)) actionColumns.push(column);
    else regularColumns.push(column);
  });
  return [...regularColumns, ...actionColumns];
}

function normalizeSearchInputWidth(width) {
  if (width === undefined || width === null || width === '') return SEARCH_FILTER_INPUT_STYLE['--size-input-width'];
  if (typeof width === 'number') return `${width}px`;
  return String(width);
}

function normalizeSearchFilterOptions(options, fallbackTitle) {
  const source = Array.isArray(options) && options.length > 0
    ? options
    : [`${fallbackTitle}选项一`, `${fallbackTitle}选项二`, `${fallbackTitle}选项三`];

  return source
    .map((option, index) => {
      const rawOption = typeof option === 'object' && option !== null ? option : { label: String(option), value: option };
      const rawLabel = rawOption.label != null ? String(rawOption.label) : String(rawOption.value ?? '');
      if (String(rawOption.value ?? '').toLowerCase() === 'all' || rawLabel === '全部' || rawLabel.startsWith('全部')) {
        return null;
      }
      return {
        ...rawOption,
        label: rawLabel,
        value: rawOption.value ?? rawLabel ?? `${fallbackTitle}-${index}`,
      };
    })
    .filter(Boolean);
}

function buildDefaultSearchFilterItems(columns) {
  const sourceColumns = columns.filter((column) => {
    const type = normalizeColumnType(column?.type);
    return column?.title && type !== 'actions' && type !== 'dragHandle';
  });

  return Array.from({ length: 4 }, (_, index) => {
    const column = sourceColumns[index];
    const type = normalizeColumnType(column?.type || 'text');
    const title = column?.title || SEARCH_FILTER_FALLBACK_TITLES[index] || `筛选项${index + 1}`;
    const optionLabels = SEARCH_FILTER_OPTIONS[type] || [`${title}选项一`, `${title}选项二`, `${title}选项三`];

    return {
      id: `table-filter-${index + 1}`,
      label: title,
      options: normalizeSearchFilterOptions(optionLabels, title).map((option, optionIndex) => ({
        ...option,
        value: option.value ?? `${title}-${optionIndex}`,
      })),
    };
  });
}

function normalizeSearchFilterItems(items, columns) {
  const sourceItems = Array.isArray(items) && items.length > 0 ? items : buildDefaultSearchFilterItems(columns);
  return sourceItems.slice(0, 4).map((item, index) => {
    const sourceItem = typeof item === 'object' && item !== null ? item : {};
    const fallbackTitle = sourceItem.label || SEARCH_FILTER_FALLBACK_TITLES[index] || `筛选项${index + 1}`;
    return {
      ...sourceItem,
      id: sourceItem.id || `table-filter-${index + 1}`,
      label: sourceItem.label || fallbackTitle,
      options: normalizeSearchFilterOptions(sourceItem.options, fallbackTitle),
      multiple: sourceItem.multiple !== false,
    };
  });
}

function getTypeMinHeight(type, sizeKey) {
  return TYPE_MIN_HEIGHT[type]?.[sizeKey] ?? TYPE_MIN_HEIGHT.text[sizeKey];
}

function resolveColumnMetrics(column) {
  const type = normalizeColumnType(column.type);
  const baseWidth = Number(column.width ?? normalizeColumnWidth(column) ?? DEFAULT_COLUMN_WIDTH[type] ?? 1);
  const minWidth = Number(column.minWidth ?? MIN_COLUMN_WIDTH[type] ?? 96);
  return {
    baseWidth,
    minWidth: Math.max(minWidth, 0),
  };
}

function getTextVisualWidth(text) {
  return String(text || '').split('').reduce((sum, char) => (
    sum + (char.charCodeAt(0) > 255 ? 14 : 7)
  ), 0);
}

function getActionColumnWidth(column, rows = []) {
  const type = normalizeColumnType(column?.type);
  if (type !== 'actions') return null;
  const configuredWidth = Number(column.width);
  if (Number.isFinite(configuredWidth) && configuredWidth > 0) {
    return configuredWidth;
  }

  const cellSize = normalizeCellSize(column.cellSize);
  const horizontalPadding = cellSize === 'small' ? 16 : 24;
  const gap = 8;
  const overflowButtonWidth = 24;
  const labels = rows.flatMap((record) => {
    const rawValue = column.dataIndex ? record?.[column.dataIndex] : record?.[column.key];
    const actions = Array.isArray(rawValue) ? rawValue : [];
    const visibleActions = actions.length > 2 ? actions.slice(0, 2) : actions;
    const textWidth = visibleActions.reduce((sum, action) => sum + getTextVisualWidth(getActionLabel(action)), 0);
    const visibleCount = visibleActions.length + (actions.length > 2 ? 1 : 0);
    const gapWidth = Math.max(0, visibleCount - 1) * gap;
    const overflowWidth = actions.length > 2 ? overflowButtonWidth : 0;
    return [horizontalPadding + textWidth + gapWidth + overflowWidth];
  });
  const contentWidth = Math.max(0, ...labels);
  const minWidth = Number(column.minWidth ?? MIN_COLUMN_WIDTH.actions);
  return Math.ceil(Math.max(minWidth, contentWidth));
}

function resolveColumnTrack(column, rows) {
  if (isActionsColumn(column)) {
    return `${getActionColumnWidth(column, rows)}px`;
  }
  const { baseWidth, minWidth } = resolveColumnMetrics(column);
  return `minmax(${minWidth}px, ${baseWidth}fr)`;
}

function buildColumnGridTemplate(columns, rows) {
  if (!columns.length) return 'minmax(0, 1fr)';
  return columns.map((column) => resolveColumnTrack(column, rows)).join(' ');
}

function getColumnTemplateMinWidth(columns) {
  if (!columns.length) return 0;
  return columns.reduce((sum, column) => sum + resolveColumnMetrics(column).minWidth, 0);
}

function getPinnedColumnStates(columns, fixedColumnsMode, rows = []) {
  const states = columns.map(() => null);
  const hasActionsTail = columns.length > 0 && isActionsColumn(columns[columns.length - 1]);

  if (!columns.length || (fixedColumnsMode === 'none' && !hasActionsTail)) {
    return states;
  }

  const lastColumnIndex = columns.length - 1;

  if (isFirstColumnFixed(fixedColumnsMode)) {
    states[0] = {
      side: 'left',
      offset: 0,
      edge: 'right',
    };
  }

  if ((isLastColumnFixed(fixedColumnsMode) || hasActionsTail) && lastColumnIndex > 0) {
    let rightPinnedStart = lastColumnIndex;
    if (hasActionsTail) {
      while (rightPinnedStart > 0 && isActionsColumn(columns[rightPinnedStart - 1])) {
        rightPinnedStart -= 1;
      }
    }

    let offset = 0;
    for (let index = lastColumnIndex; index >= rightPinnedStart; index -= 1) {
      states[index] = {
        side: 'right',
        offset,
        edge: index === rightPinnedStart ? 'left' : null,
      };
      offset += isActionsColumn(columns[index])
        ? getActionColumnWidth(columns[index], rows)
        : resolveColumnMetrics(columns[index]).minWidth;
    }
  }

  return states;
}

function buildCellClass(baseClass, sizeKey, extraClass = '') {
  return [
    baseClass,
    CELL_SIZE_CLASS[sizeKey] || CELL_SIZE_CLASS.default,
    extraClass,
  ].filter(Boolean).join(' ');
}

function getPinnedCellStyle({
  align,
  minHeight,
  pinnedState,
  isHeader = false,
}) {
  const style = {
    minHeight: `${minHeight}px`,
    textAlign: align || 'left',
  };

  if (!pinnedState) {
    return style;
  }

  style.position = 'sticky';
  style.background = isHeader ? TABLE_HEADER_BACKGROUND : PINNED_SURFACE_BACKGROUND;
  style.backgroundClip = 'padding-box';
  style.zIndex = isHeader ? 50 : 30;

  if (pinnedState.side === 'left') {
    style.left = `${pinnedState.offset}px`;
  }

  if (pinnedState.side === 'right') {
    style.right = `${pinnedState.offset}px`;
  }

  if (pinnedState.edge === 'right') {
    style.boxShadow = '2px 0 0 rgba(45, 66, 107, 0.06)';
  }

  if (pinnedState.edge === 'left') {
    style.boxShadow = '-2px 0 0 rgba(45, 66, 107, 0.06)';
  }

  return style;
}

function getRowKeyValue(rowKey, record, index) {
  if (typeof rowKey === 'function') {
    return rowKey(record, index);
  }
  if (typeof rowKey === 'string' && record?.[rowKey] != null) {
    return record[rowKey];
  }
  return `${index}`;
}

function resolveTextValue(value) {
  if (value == null) return '';
  if (typeof value === 'object' && value.label != null) return String(value.label);
  return String(value);
}

function EllipsisTooltipText({
  value,
  className = TRUNCATE_TEXT,
  wrapperClassName = 'w-full min-w-0',
}) {
  const text = resolveTextValue(value);
  const textRef = useRef(null);
  const [isOverflowed, setIsOverflowed] = useState(false);

  const checkOverflow = useCallback(() => {
    const node = textRef.current;
    if (!node) return;
    setIsOverflowed(node.scrollWidth > node.clientWidth + 1);
  }, []);

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

    checkOverflow();

    if (typeof ResizeObserver === 'undefined') {
      return undefined;
    }

    const observer = new ResizeObserver(() => {
      checkOverflow();
    });
    observer.observe(node);

    return () => observer.disconnect();
  }, [checkOverflow, text]);

  const content = (
    <span ref={textRef} className={className}>
      {text}
    </span>
  );

  const wrapperClass = [ELLIPSIS_TOOLTIP_WRAP, wrapperClassName].filter(Boolean).join(' ');

  if (!isOverflowed || !text) {
    return (
      <span
        className={wrapperClass}
        onMouseEnter={checkOverflow}
      >
        {content}
      </span>
    );
  }

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

function renderSingleLineText(value, className = TRUNCATE_TEXT, wrapperClassName = 'w-full min-w-0') {
  return (
    <EllipsisTooltipText
      value={value}
      className={className}
      wrapperClassName={wrapperClassName}
    />
  );
}

function buildPageItems(current, totalPages) {
  if (totalPages <= 7) {
    return Array.from({ length: totalPages }, (_, index) => index + 1);
  }

  if (current <= 3) {
    return [1, 2, 3, 'ellipsis', totalPages - 2, totalPages - 1, totalPages];
  }

  if (current >= totalPages - 2) {
    return [1, 2, 3, 'ellipsis', totalPages - 2, totalPages - 1, totalPages];
  }

  return [1, 'ellipsis', current - 1, current, current + 1, 'ellipsis', totalPages];
}

function defaultSummaryText(current, pageSize, total) {
  if (!total) {
    return '暂无数据';
  }
  const start = (current - 1) * pageSize + 1;
  const end = Math.min(current * pageSize, total);
  return `显示第 ${start} 条-第 ${end} 条，共 ${total} 条`;
}

function shouldSliceDataSource(pagination, dataSourceLength) {
  if (!pagination) return false;
  if (pagination.clientSide === false) return false;
  if (pagination.clientSide === true) return true;
  return pagination.total == null || Number(pagination.total) === dataSourceLength;
}

function renderTitleValue(value) {
  const label = resolveTextValue(value);
  const href = typeof value === 'object' ? value?.href : undefined;
  const onClick = typeof value === 'object' ? value?.onClick : undefined;
  const labelNode = renderSingleLineText(label, EMPHASIS_TEXT);

  if (href) {
    return (
      <Button as="a" href={href} variant="text-brand" size="sm" className={TEXT_BRAND_BUTTON_CLASS}>
        {labelNode}
      </Button>
    );
  }

  return (
    <Button type="button" variant="text-brand" size="sm" className={TEXT_BRAND_BUTTON_CLASS} onClick={onClick}>
      {labelNode}
    </Button>
  );
}

function renderTagsValue(value) {
  const items = Array.isArray(value) ? value : value ? [value] : [];

  if (items.length === 0) {
    return null;
  }

  const item = items[0];
  const label = typeof item === 'object' ? item.label : item;
  const variant = typeof item === 'object' ? item.variant || 'white' : 'white';

  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      <Tag
        variant={variant}
        size="m"
        radius="md"
      >
        {label}
      </Tag>
    </div>
  );
}

function renderAvatarValue(value, cellSize) {
  if (!value) return null;

  const shouldDefaultToImage = !value.avatarType || value.avatarType === 'image';
  const resolvedAvatarSrc = value.avatarSrc || (shouldDefaultToImage ? getTeamAvatarBySeed(value.name || value.avatarAlt || value.avatarLabel) : null);
  const avatarType = value.avatarType || (resolvedAvatarSrc ? 'image' : 'fallback');
  const avatarLabel = value.avatarLabel || value.name?.slice(0, 2) || 'AI';
  const avatarSize = cellSize === 'small' ? 'xs' : 'xs';

  return (
    <div className={CREATOR_WRAP}>
      <Avatar
        size={avatarSize}
        type={avatarType}
        src={avatarType === 'image' ? resolvedAvatarSrc : null}
        alt={value.avatarAlt || `${value.name || '创建人'}头像`}
        label={avatarLabel}
      />
      {renderSingleLineText(value.name, CREATOR_NAME)}
    </div>
  );
}

function renderAvatarTextValue(value) {
  if (!value) return null;

  const shouldDefaultToImage = !value.avatarType || value.avatarType === 'image';
  const resolvedAvatarSrc = value.avatarSrc || (shouldDefaultToImage ? getTeamAvatarBySeed(value.name || value.description || value.avatarAlt || value.avatarLabel) : null);
  const avatarType = value.avatarType || (resolvedAvatarSrc ? 'image' : 'fallback');
  const avatarLabel = value.avatarLabel || value.name?.slice(0, 2) || 'AI';

  return (
    <div className={CREATOR_WRAP}>
      <Avatar
        size="xs"
        type={avatarType}
        src={avatarType === 'image' ? resolvedAvatarSrc : null}
        alt={value.avatarAlt || `${value.name || '创建人'}头像`}
        label={avatarLabel}
      />
      <div className={AVATAR_TEXT_WRAP}>
        {renderSingleLineText(value.name, 'block w-full min-w-0 truncate text-left text-sm font-normal leading-5 text-foreground')}
        {renderSingleLineText(value.description, SECONDARY_TEXT)}
      </div>
    </div>
  );
}

function renderDateTimeValue(value) {
  return renderSingleLineText(
    value,
    'block w-full min-w-0 truncate text-left text-sm font-normal leading-5 text-foreground [font-family:Inter,"PingFang_SC","PingFang_TC","Hiragino_Sans_GB","Microsoft_YaHei",sans-serif]',
  );
}

function renderIconTextValue(value) {
  const label = typeof value === 'object' ? value.label : value;
  const iconName = typeof value === 'object' ? value.iconName || 'award-01-stroked' : 'award-01-stroked';
  return (
    <div className="flex w-full min-w-0 items-center justify-start gap-1 text-left">
      <span className="shrink-0 text-foreground-muted">
        <Icon name={iconName} size="sm" />
      </span>
      {renderSingleLineText(label, PLAIN_TEXT)}
    </div>
  );
}

function renderTextButtonValue(value) {
  const label = typeof value === 'object' ? value.label : value;
  const iconName = typeof value === 'object' ? value.iconName || 'edit-04-stroked' : 'edit-04-stroked';
  const onClick = typeof value === 'object' ? value.onClick : undefined;
  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      {renderSingleLineText(label, INLINE_PLAIN_TEXT, 'min-w-0 flex-1')}
      <Button
        type="button"
        variant="ghost-black"
        size="sm"
        iconOnly
        icon={<Icon name={iconName} size="sm" />}
        className={[ICON_ONLY_BUTTON_RESET, TEXT_BUTTON_ICON_CLASS, 'ml-[2px]'].join(' ')}
        tooltip={typeof value === 'object' ? value.tooltip || value.ariaLabel || value.label || '单元格操作' : '单元格操作'}
        aria-label="单元格操作"
        onClick={onClick}
      />
    </div>
  );
}

function renderStatusValue(value) {
  const label = typeof value === 'object' ? value.label : resolveTextValue(value);
  const tone = typeof value === 'object' ? value.tone || 'success' : 'success';
  const dotClass = {
    success: 'bg-green-500',
    warning: 'bg-orange-500',
    danger: 'bg-red-500',
    neutral: 'bg-blueGrey-400',
  }[tone] || 'bg-brand-500';

  return (
    <div className="flex w-full min-w-0 items-center justify-start gap-2 text-left">
      <span className={['size-2 shrink-0 rounded-full', dotClass].join(' ')} />
      {renderSingleLineText(label, PLAIN_TEXT)}
    </div>
  );
}

function renderSwitchValue(value) {
  const checked = typeof value === 'object' ? Boolean(value.checked) : Boolean(value);
  const onChange = typeof value === 'object' ? value.onChange : undefined;
  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      <Switch checked={checked} onChange={onChange} />
    </div>
  );
}

function renderCheckboxValue(value, cellSize) {
  const checked = typeof value === 'object' ? Boolean(value.checked) : Boolean(value);
  const onChange = typeof value === 'object' ? value.onChange : undefined;
  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      <Checkbox checked={checked} size={cellSize === 'default' ? 'md' : 'sm'} onChange={onChange} />
    </div>
  );
}

function renderLinkDescriptionValue(value) {
  if (!value) return null;
  return (
    <div className="flex w-full min-w-0 flex-col items-start justify-center gap-1 text-left">
      {renderTitleValue({ label: value.label, href: value.href, onClick: value.onClick })}
      {renderSingleLineText(value.description, SECONDARY_TEXT)}
    </div>
  );
}

function renderImageValue(value, cellSize) {
  const alt = typeof value === 'object' ? value.alt || '表格图片' : '表格图片';
  const avatarSize = {
    default: 'm',
    middle: 'default',
    small: 's',
  }[cellSize];

  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      <Avatar
        shape="rect"
        type="robot"
        size={avatarSize}
        alt={alt}
      />
    </div>
  );
}

function renderProgressValue(value) {
  const percent = Math.max(0, Math.min(100, typeof value === 'object' ? Number(value.value ?? 0) : Number(value ?? 0)));
  return (
    <div className="flex w-full min-w-0 items-center justify-start text-left">
      <div className="h-[10px] w-[70px] shrink-0 overflow-hidden rounded-full bg-fill">
        <div
          className="h-full rounded-full bg-[var(--color-data-0)]"
          style={{ width: `${percent}%` }}
        />
      </div>
      <span className="shrink-0 pl-2 text-sm leading-[24px] tracking-[-0.14px] text-foreground">{percent}%</span>
    </div>
  );
}

function getActionLabel(action) {
  return resolveTextValue(action?.label || action?.ariaLabel || action?.tooltip || '更多操作');
}

function renderActionButton(action, key, { className = ACTION_TEXT_BUTTON_CLASS, onDone } = {}) {
  const safeAction = action || {};
  const label = getActionLabel(safeAction);
  const handleClick = (event) => {
    safeAction.onClick?.(event);
    onDone?.();
  };

  if (safeAction.href) {
    return (
      <Button
        key={key}
        as="a"
        href={safeAction.href}
        variant="text-brand"
        size="sm"
        className={className}
        onClick={safeAction.onClick}
        role={onDone ? 'menuitem' : undefined}
      >
        <span className={ACTION_FULL_TEXT}>{label}</span>
      </Button>
    );
  }

  return (
    <Button
      key={key}
      type="button"
      variant="text-brand"
      size="sm"
      className={className}
      disabled={safeAction.disabled}
      onClick={handleClick}
      role={onDone ? 'menuitem' : undefined}
    >
      <span className={ACTION_FULL_TEXT}>{label}</span>
    </Button>
  );
}

function ActionOverflowMenu({ actions = [] }) {
  const items = useMemo(
    () => (Array.isArray(actions) ? actions : []).map((action, index) => ({
      id: action?.key || `${getActionLabel(action)}-${index}`,
      value: action?.key || `${getActionLabel(action)}-${index}`,
      label: getActionLabel(action),
      disabled: action?.disabled,
      onClick: (_item, event) => {
        event?.stopPropagation?.();
        if (action?.href && typeof window !== 'undefined') {
          window.location.assign(action.href);
        }
        action?.onClick?.(event);
      },
    })),
    [actions],
  );

  return (
    <Dropdown
      triggerMode="hover"
      hoverCloseDelay={120}
      selectionIndicator="none"
      matchTriggerWidth={false}
      minWidth={112}
      gap={4}
      items={items}
      panelClassName="tfds-table-action-overflow"
      trigger={(
        <Button
          type="button"
          variant="text-brand"
          size="sm"
          iconOnly
          icon={<Icon name="dots-horizontal-stroked" size="sm" />}
          className={ACTION_OVERFLOW_TRIGGER_CLASS}
          tooltip="更多操作"
          aria-label="更多操作"
          onClick={(event) => event.stopPropagation()}
        />
      )}
    />
  );
}

function renderActionsValue(value) {
  const items = Array.isArray(value) ? value : [];

  if (items.length === 0) {
    return null;
  }

  const visibleItems = items.length > 2 ? items.slice(0, 2) : items;
  const overflowItems = items.length > 2 ? items.slice(2) : [];

  return (
    <div className={ACTION_WRAP}>
      {visibleItems.map((action, index) => renderActionButton(
        action,
        action?.key || `${getActionLabel(action)}-${index}`,
      ))}
      {overflowItems.length > 0 ? <ActionOverflowMenu actions={overflowItems} /> : null}
    </div>
  );
}

function renderDragHandleValue(value) {
  const onClick = typeof value === 'object' ? value?.onClick : undefined;
  return (
    <Button
      type="button"
      variant="ghost-black"
      size="sm"
      iconOnly
      icon={<Icon name="dots-grid-stroked" size="sm" />}
      className={[ICON_ONLY_BUTTON_RESET, DRAG_HANDLE_BUTTON_CLASS].join(' ')}
      tooltip="拖拽排序"
      aria-label="拖拽排序"
      onClick={onClick}
    />
  );
}

function getCardFormStatusVariant(status) {
  return CARD_FORM_STATUS_VARIANT[status] || 'grey';
}

function getCardFormMetrics(version = {}) {
  if (Array.isArray(version.metrics)) return version.metrics;
  return [
    { label: '完成率', value: version.completion },
    { label: '执行次数', value: version.execCount },
    { label: '满意度', value: version.satisfaction },
    { label: '转人工率', value: version.humanRate },
  ].filter((item) => item.value != null);
}

function getCardFormMetricText(metrics = []) {
  return metrics
    .filter((metric) => metric?.value != null && metric.value !== '')
    .map((metric) => `${metric.label} ${metric.value}`)
    .join('   ');
}

function getCardFormSubtitle(record = {}) {
  if (record.subtitle) return record.subtitle;
  if (record.description && record.description !== '-') return record.description;
  if (record.channels) return `${record.channels}渠道任务`;
  return '策略配置摘要';
}

function getCardFormCategoryLabel(category) {
  if (!category) return '';
  return String(category).slice(0, 8);
}

function CardFormMetrics({ metrics = [] }) {
  const filteredMetrics = useMemo(
    () => metrics.filter((metric) => metric?.value != null && metric.value !== ''),
    [metrics],
  );
  const metricText = useMemo(() => getCardFormMetricText(filteredMetrics), [filteredMetrics]);
  const lineRef = useRef(null);
  const [isOverflowed, setIsOverflowed] = useState(false);

  const checkOverflow = useCallback(() => {
    const node = lineRef.current;
    if (!node) return;
    setIsOverflowed(node.scrollWidth > node.clientWidth + 1);
  }, []);

  useEffect(() => {
    const node = lineRef.current;
    if (!node) return undefined;

    checkOverflow();

    if (typeof ResizeObserver === 'undefined') {
      return undefined;
    }

    const observer = new ResizeObserver(() => {
      checkOverflow();
    });
    observer.observe(node);

    return () => observer.disconnect();
  }, [checkOverflow, metricText]);

  if (filteredMetrics.length === 0) return <div className={CARD_FORM_METRICS} />;

  const line = (
    <span
      ref={lineRef}
      className={CARD_FORM_METRICS_LINE}
      onMouseEnter={checkOverflow}
    >
      {filteredMetrics.map((metric, index) => (
        <span key={`${metric.label}-${metric.value}`} className={index > 0 ? 'ml-5' : ''}>
          <span className="text-foreground-muted">{metric.label} </span>
          <span className="[font-weight:var(--font-semibold)] text-foreground">{metric.value}</span>
        </span>
      ))}
    </span>
  );

  return (
    <div className={CARD_FORM_METRICS}>
      {isOverflowed ? (
        <Tooltip content={metricText} placement="top" triggerClassName="block min-w-0 w-full overflow-hidden">
          {line}
        </Tooltip>
      ) : line}
    </div>
  );
}

function CardFormDateUser({ date, avatar, seed = 0 }) {
  const defaultMember = getTeamMemberByIndex(seed);
  const avatarName = avatar?.name || defaultMember?.name || '创建人';
  const avatarSrc = avatar?.avatarSrc || defaultMember?.avatarSrc;
  return (
    <div className={CARD_FORM_USER_DATE}>
      <Avatar
        size="mini"
        type={avatarSrc ? 'image' : 'fallback'}
        src={avatarSrc}
        alt={avatar?.avatarAlt || `${avatarName}头像`}
        label={avatar?.avatarLabel || avatarName.slice(0, 2)}
      />
      {renderSingleLineText(date, CARD_FORM_DATE, 'min-w-0')}
    </div>
  );
}

function CardFormActions({ record, context, onView, onMore }) {
  return (
    <div className={CARD_FORM_ACTIONS} onClick={(event) => event.stopPropagation()}>
      <Button
        type="button"
        variant="outline-black"
        onClick={() => onView?.(record, context)}
      >
        查看
      </Button>
      <Button
        type="button"
        variant="ghost-black"
        iconOnly
        icon={<Icon name="dots-horizontal-stroked" />}
        tooltip="更多"
        aria-label="更多"
        onClick={() => onMore?.(record, context)}
      />
    </div>
  );
}

function CardFormVersionRow({ version, parent, index, parentIndex, onView, onMore }) {
  return (
    <div className={CARD_FORM_VERSION_ROW} data-tfds-component="Table.CardForm.VersionRow">
      <span className={CARD_FORM_VERSION_BADGE}>v{index + 1}</span>
      {renderSingleLineText(version.title, CARD_FORM_VERSION_TITLE_TEXT, CARD_FORM_VERSION_TITLE)}
      <div className={CARD_FORM_VERSION_STATUS}>
        <Tag size="m" radius="md" variant={getCardFormStatusVariant(version.status)}>
          {version.status}
        </Tag>
      </div>
      <CardFormMetrics metrics={getCardFormMetrics(version)} />
      <div className={CARD_FORM_RIGHT}>
        <CardFormDateUser
          date={version.updatedAt || parent.updatedAt}
          avatar={version.avatar}
          seed={parentIndex * 5 + index + 1}
        />
        <CardFormActions
          record={version}
          context={{ type: 'version', parentRecord: parent, index, parentIndex }}
          onView={onView}
          onMore={onMore}
        />
      </div>
    </div>
  );
}

function CardFormItem({
  record,
  index,
  rowKey,
  expanded,
  onToggle,
  onView,
  onMore,
}) {
  const keyValue = getRowKeyValue(rowKey, record, index);
  const versions = Array.isArray(record.versions) ? record.versions : [];
  const hasChildren = versions.length > 0;
  const defaultMember = getTeamMemberByIndex(index);
  const parentClassName = hasChildren ? CARD_FORM_PARENT : CARD_FORM_PARENT_STATIC;
  const categoryLabel = getCardFormCategoryLabel(record.category);

  return (
    <div className={CARD_FORM_ITEM} data-tfds-component="Table.CardForm.Item">
      <div className={parentClassName}>
        <div
          className={CARD_FORM_TOGGLE_WRAP}
          style={{
            transform: expanded ? 'rotate(90deg)' : 'none',
            opacity: hasChildren ? 1 : 0,
            pointerEvents: hasChildren ? 'auto' : 'none',
          }}
        >
          <Button
            type="button"
            size="sm"
            variant="ghost-black"
            iconOnly
            icon={<Icon name="chevron-right-stroked" />}
            tooltip={expanded ? '收起子项' : '展开子项'}
            aria-label={expanded ? '收起子项' : '展开子项'}
            aria-expanded={hasChildren ? expanded : undefined}
            onClick={(event) => {
              event.stopPropagation();
              if (hasChildren) onToggle(keyValue);
            }}
          />
        </div>
        <div className={CARD_FORM_MAIN}>
          {renderSingleLineText(record.title, CARD_FORM_TITLE)}
          {renderSingleLineText(getCardFormSubtitle(record), CARD_FORM_SUBTITLE)}
        </div>
        <div className={CARD_FORM_ASIDE}>
          {categoryLabel ? (
            <Tag size="m" radius="md" variant="white">
              {categoryLabel}
            </Tag>
          ) : null}
          <CardFormDateUser
            date={record.updatedAt}
            avatar={record.avatar || defaultMember}
            seed={index}
          />
          <CardFormActions
            record={record}
            context={{ type: 'parent', index }}
            onView={onView}
            onMore={onMore}
          />
        </div>
      </div>

      {expanded && hasChildren ? (
        <div className={CARD_FORM_CHILDREN}>
          {versions.map((version, versionIndex) => (
            <CardFormVersionRow
              key={version.id || `version-${version.v ?? versionIndex}`}
              version={version}
              parent={record}
              index={versionIndex}
              parentIndex={index}
              onView={onView}
              onMore={onMore}
            />
          ))}
        </div>
      ) : null}
    </div>
  );
}

function renderTableLoadingRows({ count, columnTemplate, variant = 'table' }) {
  if (variant === 'card-form') {
    return Array.from({ length: count }, (_, index) => (
      <div key={`table-loading-${index}`} className={CARD_FORM_ITEM} aria-hidden="true">
        <div className="px-8 py-4">
          <Skeleton preset="list" count={1} />
        </div>
      </div>
    ));
  }

  return Array.from({ length: count }, (_, rowIndex) => (
    <div
      key={`table-loading-${rowIndex}`}
      className={BODY_ROW}
      role="row"
      aria-hidden="true"
      style={{ gridTemplateColumns: columnTemplate }}
    >
      <div
        className={buildCellClass(BODY_CELL, 'default')}
        role="gridcell"
        style={{
          gridColumn: '1 / -1',
          minHeight: '44px',
        }}
      >
        <Skeleton preset="table-row" />
      </div>
    </div>
  ));
}

function renderCellContent(column, record, rowIndex) {
  const type = normalizeColumnType(column.type);
  const cellSize = normalizeCellSize(column.cellSize);
  const rawValue = column.dataIndex ? record?.[column.dataIndex] : record?.[column.key];

  if (typeof column.render === 'function') {
    return column.render(rawValue, record, rowIndex);
  }

  switch (type) {
    case 'link':
      return renderTitleValue(rawValue);
    case 'iconText':
      return renderIconTextValue(rawValue);
    case 'textButton':
      return renderTextButtonValue(rawValue);
    case 'status':
      return renderStatusValue(rawValue);
    case 'tag':
      return renderTagsValue(rawValue);
    case 'switch':
      return renderSwitchValue(rawValue);
    case 'checkbox':
      return renderCheckboxValue(rawValue, cellSize);
    case 'avatar':
      return renderAvatarValue(rawValue, cellSize);
    case 'avatarText':
      return renderAvatarTextValue(rawValue);
    case 'linkDescription':
      return renderLinkDescriptionValue(rawValue);
    case 'image':
      return renderImageValue(rawValue, cellSize);
    case 'progress':
      return renderProgressValue(rawValue);
    case 'datetime':
      return renderDateTimeValue(rawValue);
    case 'actions':
      return renderActionsValue(rawValue);
    case 'dragHandle':
      return renderDragHandleValue(rawValue);
    case 'text':
    default:
      return renderSingleLineText(rawValue);
  }
}

export default function Table({
  columns = [],
  dataSource = [],
  variant = 'table',
  rowKey = 'id',
  pagination = null,
  expandedRowKeys = null,
  defaultExpandedRowKeys = [],
  onExpandedRowKeysChange = null,
  onView = null,
  onMore = null,
  onPageChange = null,
  onPageSizeChange = null,
  showSearchFilters = true,
  searchPlaceholder = '搜索表格内容',
  searchInputWidth = '240px',
  searchValue,
  defaultSearchValue,
  onSearchChange = null,
  searchFilterItems,
  onSearchFilterChange = null,
  emptyText = '暂无数据',
  loading = false,
  loadingRowCount = 6,
  className = '',
  fixedColumnsMode = 'none',
}) {
  const paginationCurrent = pagination?.current ?? 1;
  const paginationPageSize = pagination?.pageSize ?? 10;
  const paginationTotal = pagination?.total ?? dataSource.length;

  const [innerCurrent, setInnerCurrent] = useState(paginationCurrent);
  const [innerPageSize, setInnerPageSize] = useState(paginationPageSize);
  const [innerExpandedRowKeys, setInnerExpandedRowKeys] = useState(defaultExpandedRowKeys);

  useEffect(() => {
    setInnerCurrent(paginationCurrent);
  }, [paginationCurrent]);

  useEffect(() => {
    setInnerPageSize(paginationPageSize);
  }, [paginationPageSize]);

  const current = pagination?.current ?? innerCurrent;
  const pageSize = pagination?.pageSize ?? innerPageSize;
  const totalPages = Math.max(1, Math.ceil((paginationTotal || 0) / Math.max(pageSize, 1)));
  const safeCurrent = Math.min(Math.max(Number(current) || 1, 1), totalPages);
  const pageItems = pagination?.displayPages || buildPageItems(safeCurrent, totalPages);
  const shouldPaginateDataSource = shouldSliceDataSource(pagination, dataSource.length);
  const visibleDataSource = useMemo(() => {
    if (!shouldPaginateDataSource) return dataSource;
    const start = (safeCurrent - 1) * pageSize;
    return dataSource.slice(start, start + pageSize);
  }, [dataSource, pageSize, safeCurrent, shouldPaginateDataSource]);
  const pageSizeOptions = pagination?.pageSizeOptions?.length
    ? pagination.pageSizeOptions
    : [pageSize];
  const displayColumns = useMemo(() => normalizeTableColumns(columns), [columns]);
  const shouldShowSearchFilters = variant === 'table' && showSearchFilters !== false;
  const resolvedSearchFilterItems = useMemo(
    () => normalizeSearchFilterItems(searchFilterItems, displayColumns),
    [searchFilterItems, displayColumns],
  );
  const columnTemplate = useMemo(
    () => buildColumnGridTemplate(displayColumns, visibleDataSource),
    [displayColumns, visibleDataSource],
  );
  const columnTemplateMinWidth = useMemo(() => getColumnTemplateMinWidth(displayColumns), [displayColumns]);
  const pinnedColumnStates = useMemo(
    () => getPinnedColumnStates(displayColumns, fixedColumnsMode, visibleDataSource),
    [displayColumns, fixedColumnsMode, visibleDataSource],
  );
  const selectValue = Number.isNaN(Number(pageSize)) ? pageSize : Number(pageSize);
  const selectOptions = useMemo(() => {
    const normalized = Array.from(new Set([...pageSizeOptions, pageSize]));
    return normalized.map((item) => ({
      value: Number(item),
      label:
        pagination?.pageSizeLabel && Number(item) === Number(pageSize)
          ? pagination.pageSizeLabel
          : `${item} 条/页`,
    }));
  }, [pageSize, pageSizeOptions, pagination?.pageSizeLabel]);

  const handleSearchChange = useCallback((event) => {
    onSearchChange?.(event?.target?.value ?? '', event);
  }, [onSearchChange]);

  const handlePageChange = (page) => {
    if (page < 1 || page > totalPages || page === safeCurrent) return;
    if (pagination?.current == null) {
      setInnerCurrent(page);
    }
    onPageChange?.(page);
  };

  const handlePageSizeChange = (nextPageSize) => {
    const parsed = Number(nextPageSize);
    if (Number.isNaN(parsed) || parsed === pageSize) return;
    if (pagination?.pageSize == null) {
      setInnerPageSize(parsed);
    }
    if (pagination?.current == null) {
      setInnerCurrent(1);
    }
    onPageSizeChange?.(parsed);
  };

  const resolvedExpandedRowKeys = Array.isArray(expandedRowKeys) ? expandedRowKeys : innerExpandedRowKeys;
  const expandedKeySet = useMemo(
    () => new Set(resolvedExpandedRowKeys.map((item) => String(item))),
    [resolvedExpandedRowKeys],
  );

  const handleCardFormToggle = (key) => {
    const normalizedKey = String(key);
    const nextKeys = expandedKeySet.has(normalizedKey)
      ? resolvedExpandedRowKeys.filter((item) => String(item) !== normalizedKey)
      : [...resolvedExpandedRowKeys, key];
    if (!Array.isArray(expandedRowKeys)) {
      setInnerExpandedRowKeys(nextKeys);
    }
    onExpandedRowKeysChange?.(nextKeys);
  };

  const paginationFooter = pagination ? (
    <div className={FOOTER}>
      <span className={FOOTER_SUMMARY}>
        {pagination.summaryText || defaultSummaryText(safeCurrent, pageSize, paginationTotal)}
      </span>

      <div className={FOOTER_RIGHT}>
        <div className={PAGE_GROUP}>
          <div className={PAGE_LIST}>
            <Button
              type="button"
              variant="ghost-black"
              size="sm"
              iconOnly
              icon={<Icon name="chevron-left-stroked" size="sm" />}
              className={[ICON_ONLY_BUTTON_RESET, PAGE_ARROW_BUTTON_CLASS].join(' ')}
              onClick={() => handlePageChange(safeCurrent - 1)}
              disabled={safeCurrent <= 1}
              tooltip="上一页"
              aria-label="上一页"
              data-tfds-component="Table.Pagination"
            />

            {pageItems.map((item, index) =>
              item === 'ellipsis' ? (
                <span key={`ellipsis-${index}`} className={PAGE_ELLIPSIS}>
                  ...
                </span>
              ) : (
                <Button
                  key={item}
                  type="button"
                  className={[
                    PAGE_NUMBER_BUTTON_CLASS,
                    Number(item) === safeCurrent ? PAGE_BUTTON_ACTIVE : '',
                  ].filter(Boolean).join(' ')}
                  variant="ghost-black"
                  size="sm"
                  style={Number(item) === safeCurrent ? PAGE_BUTTON_ACTIVE_STYLE : undefined}
                  onClick={() => handlePageChange(Number(item))}
                  aria-current={Number(item) === safeCurrent ? 'page' : undefined}
                  data-tfds-component="Table.Pagination"
                >
                  {item}
                </Button>
              ),
            )}

            <Button
              type="button"
              variant="ghost-black"
              size="sm"
              iconOnly
              icon={<Icon name="chevron-right-stroked" size="sm" />}
              className={[ICON_ONLY_BUTTON_RESET, PAGE_ARROW_BUTTON_CLASS].join(' ')}
              onClick={() => handlePageChange(safeCurrent + 1)}
              disabled={safeCurrent >= totalPages}
              tooltip="下一页"
              aria-label="下一页"
              data-tfds-component="Table.Pagination"
            />
          </div>
        </div>

        <Select
          className="!w-[120px] !min-w-[120px] !max-w-[120px] shrink-0"
          options={selectOptions}
          value={selectValue}
          onChange={(nextValue) => handlePageSizeChange(nextValue)}
          data-tfds-component="Table.PageSize"
        />
      </div>
    </div>
  ) : null;

  const resolvedLoadingRowCount = Math.max(1, loadingRowCount);

  if (variant === 'card-form') {
    return (
      <div
        className={[WRAPPER, className].filter(Boolean).join(' ')}
        data-tfds-component="Table"
        data-variant="card-form"
        aria-busy={loading || undefined}
      >
        <div className={CARD_FORM_BODY}>
          {loading ? (
            renderTableLoadingRows({
              count: resolvedLoadingRowCount,
              variant: 'card-form',
            })
          ) : visibleDataSource.length === 0 ? (
            <div className={EMPTY_CELL}>{emptyText}</div>
          ) : (
            visibleDataSource.map((record, rowIndex) => {
              const sourceIndex = shouldPaginateDataSource ? (safeCurrent - 1) * pageSize + rowIndex : rowIndex;
              const keyValue = getRowKeyValue(rowKey, record, sourceIndex);
              return (
                <CardFormItem
                  key={keyValue}
                  record={record}
                  index={sourceIndex}
                  rowKey={rowKey}
                  expanded={expandedKeySet.has(String(keyValue))}
                  onToggle={handleCardFormToggle}
                  onView={onView}
                  onMore={onMore}
                />
              );
            })
          )}
        </div>
        {!loading ? paginationFooter : null}
      </div>
    );
  }

  return (
    <div
      className={[WRAPPER, className].filter(Boolean).join(' ')}
      data-tfds-component="Table"
      aria-busy={loading || undefined}
    >
      {shouldShowSearchFilters ? (
        <div className={SEARCH_FILTER_BAR} data-tfds-component="Table.SearchFilterBar">
          <Input
            placeholder={searchPlaceholder}
            allowClear
            prefix={<Icon name="search-md-stroked" size="sm" aria-hidden="true" />}
            style={{
              ...SEARCH_FILTER_INPUT_STYLE,
              '--size-input-width': `min(${normalizeSearchInputWidth(searchInputWidth)},100%)`,
            }}
            value={searchValue}
            defaultValue={searchValue === undefined ? defaultSearchValue : undefined}
            onChange={handleSearchChange}
            data-tfds-component="Table.SearchInput"
          />
          {resolvedSearchFilterItems.map((item) => (
            <Filter
              key={item.id}
              label={item.label}
              options={item.options}
              multiple={item.multiple}
              selectedValues={item.selectedValues}
              defaultValue={item.defaultValue}
              disabled={item.disabled}
              onChange={(nextValue) => {
                item.onChange?.(nextValue);
                onSearchFilterChange?.(item, nextValue);
              }}
              data-tfds-component="Table.SearchFilter"
            />
          ))}
        </div>
      ) : null}
      <div className={TABLE_SHELL}>
        <div className={TABLE_VIEWPORT}>
          <div className={TABLE_CONTENT} style={{ minWidth: `${columnTemplateMinWidth}px` }}>
            <div className={TABLE} role="grid" aria-rowcount={visibleDataSource.length + 1} aria-colcount={displayColumns.length}>
              <div className={HEADER_ROW} role="row" style={{ gridTemplateColumns: columnTemplate }}>
                {displayColumns.map((column, columnIndex) => (
                  <div
                    key={column.key || column.dataIndex || column.title}
                    className={[
                      HEADER_CELL,
                      HEADER_SIZE_CLASS[normalizeCellSize(column.cellSize)] || HEADER_SIZE_CLASS.default,
                    ].join(' ')}
                    role="columnheader"
                    style={getPinnedCellStyle({
                      align: column.align,
                      minHeight: HEADER_MIN_HEIGHT[normalizeCellSize(column.cellSize)] || HEADER_MIN_HEIGHT.default,
                      pinnedState: pinnedColumnStates[columnIndex],
                      isHeader: true,
                    })}
                  >
                    <span className={HEADER_TEXT} data-tfds-component="Table.HeaderCell">{column.title}</span>
                  </div>
                ))}
              </div>

              <div className={TABLE_BODY} role="rowgroup">
                {loading ? (
                  renderTableLoadingRows({
                    count: resolvedLoadingRowCount,
                    columnTemplate,
                  })
                ) : visibleDataSource.length === 0 ? (
                  <div className={BODY_ROW} role="row" style={{ gridTemplateColumns: columnTemplate }}>
                    <div className={EMPTY_CELL} role="gridcell" style={{ gridColumn: '1 / -1' }}>
                      {emptyText}
                    </div>
                  </div>
                ) : (
                  visibleDataSource.map((record, rowIndex) => {
                    const sourceIndex = shouldPaginateDataSource ? (safeCurrent - 1) * pageSize + rowIndex : rowIndex;
                    return (
                      <div
                        key={getRowKeyValue(rowKey, record, sourceIndex)}
                        className={BODY_ROW}
                        role="row"
                        style={{ gridTemplateColumns: columnTemplate }}
                        data-tfds-component="Table.Row"
                      >
                        {displayColumns.map((column, columnIndex) => (
                          <div
                            key={column.key || column.dataIndex || column.title}
                            className={buildCellClass(
                              BODY_CELL,
                              normalizeCellSize(column.cellSize),
                            )}
                            role="gridcell"
                            style={getPinnedCellStyle({
                              align: column.align,
                              minHeight: getTypeMinHeight(normalizeColumnType(column.type), normalizeCellSize(column.cellSize)),
                              pinnedState: pinnedColumnStates[columnIndex],
                            })}
                          >
                            <div className="w-full min-w-0">
                              {renderCellContent(column, record, sourceIndex)}
                            </div>
                          </div>
                        ))}
                      </div>
                    );
                  })
                )}
              </div>
            </div>
          </div>
        </div>
      </div>

      {!loading ? paginationFooter : null}
    </div>
  );
}
