import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import AgentFamilyAvatar from './AgentFamilyAvatar';
import Avatar from './Avatar';
import Button from './Button';
import Icon from './Icon';
import IconLoading from './IconLoading';
import Tag from './Tag';
import Tabs from './Tabs';
import Tooltip from './Tooltip';
import Skeleton, {
  ConversationListItemSkeleton,
  ConversationListSectionHeaderSkeleton,
  ConversationListTicketCardSkeleton,
  ConversationListTicketSectionHeaderSkeleton,
} from './Skeleton';
import liSiruAvatar from './team-avatar-assets/li-siru.png';
import chengchengAvatar from './team-avatar-assets/chengcheng-murphy.png';
import liuDelinAvatar from './team-avatar-assets/liu-delin.png';
import duanRanAvatar from './team-avatar-assets/duan-ran.png';
import { messageBubbleEnterClass } from '../motion-bubble-enter.js';
import { TFDS_RESIZE_HANDLE_LINE_TRANSITION, TFDS_RESIZE_LINE_WIDTH_CLASS } from '../shared/resize-handle';

const DEFAULT_TABS = [
  { id: 'all', label: '全部' },
  { id: 'pending', label: '待干预', count: 3 },
  { id: 'managed', label: '托管中', count: 6 },
  { id: 'other', label: '其它' },
];

const STATUS_TAG_BY_TAB = {
  pending: { label: '待干预', variant: 'red' },
  managed: { label: '托管中', variant: 'green' },
};

/* ── 默认展开宽度（与平台预览、TOKEN_MAP 一致）── */
const DEFAULT_WIDTH = 400;
const CARD_MIN_WIDTH = 333;
const AVATAR_ONLY_WIDTH = 88;
const AVATAR_ONLY_THRESHOLD = 150;
const RESIZE_STEP = 16;
const CARD_TWO_COLUMN_THRESHOLD = 580;
const CARD_THREE_COLUMN_THRESHOLD = 950;

const DEFAULT_SECTIONS = [
  {
    id: 'pending',
    title: '待干预',
    count: 3,
    items: [
      {
        id: 'pending-1',
        title: '酒旅·仲裁退款',
        userName: '小兔叽掉毛毛🐰',
        orderId: '2918575148379876',
        time: '13:32',
        avatarSrc: liSiruAvatar,
        tags: [
          { label: '异常提醒', variant: 'grey' },
          { label: '待干预', variant: 'red' },
        ],
      },
      {
        id: 'pending-2',
        title: '订单发货进度咨询',
        userName: '糯叽叽的团子呀',
        orderId: '2918575148391024',
        time: '12:54',
        avatarSrc: chengchengAvatar,
        tags: [
          { label: '催4', variant: 'grey' },
          { label: '待干预', variant: 'red' },
        ],
      },
      {
        id: 'pending-3',
        title: '优惠券核销失败',
        userName: '草莓气泡水🍓',
        orderId: '2918575148403288',
        time: '12:40',
        avatarSrc: liuDelinAvatar,
        tags: [
          { label: '退款异常', variant: 'grey' },
          { label: '待干预', variant: 'red' },
        ],
      },
    ],
  },
  {
    id: 'managed',
    title: '托管中',
    count: 6,
    items: [
      {
        id: 'managed-1',
        title: '物流状态异常跟进',
        userName: '软软想吃糖葫芦',
        orderId: '2918575148472390',
        time: '11:22',
        avatarSrc: chengchengAvatar,
        tags: [
          { label: '24时+', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '托管中', variant: 'green' },
        ],
      },
      {
        id: 'managed-2',
        title: '退款方案确认',
        userName: '月亮送我一束光🌙',
        orderId: '2918575148421185',
        time: '10:18',
        avatarSrc: liSiruAvatar,
        tags: [
          { label: '已挂起', variant: 'orange' },
        ],
      },
      {
        id: 'managed-3',
        title: '售后凭证补充',
        userName: '布丁小熊不吃苦',
        orderId: '2918575148437702',
        time: '09:46',
        avatarSrc: liuDelinAvatar,
        tags: [
          { label: '协商未成', variant: 'grey' },
          { label: '托管中', variant: 'green' },
        ],
      },
    ],
  },
  {
    id: 'other',
    title: '其它',
    count: 20,
    items: [
      {
        id: 'other-1',
        title: '订单已完成回访',
        userName: '星星被窝藏好啦✨',
        orderId: '2918575148499712',
        time: '昨天',
        avatarSrc: duanRanAvatar,
        tags: [
          { label: '已处理', variant: 'blue' },
        ],
      },
      {
        id: 'other-2',
        title: '门店服务评价',
        userName: '困困阿喵要睡觉',
        orderId: '2918575148502149',
        time: '周二',
        avatarSrc: liuDelinAvatar,
        tags: [
          { label: '已处理', variant: 'blue' },
        ],
      },
    ],
  },
];

const DEFAULT_CARD_DRAFT_TEXT = '祝您生活愉快~如果您觉得我的服务态度还可以的话，辛苦您点击左下角结束服务为本次服务点亮小星星哦~';
const DEFAULT_CARD_DRAFT_TEXTS = [
  '好的，我这边先帮您发起内部复核，稍后把需要您补充的内容整理给您。',
  '我先继续核对系统记录，确认完当前进展后第一时间同步您。',
  '理解您的着急，我会持续帮您盯进度，有新结果会尽快回复您。',
  '这边已帮您补充登记处理诉求，后续若需配合我会及时联系您。',
  '我先整理本次处理方案和注意事项，稍后给您一份更清晰的回复口径。',
];
const CARD_CONTENT_OVERRIDES = {
  'pending-1': {
    messages: [
      { id: 'pending-1-user-1', role: 'user', text: '但是我不知道问题出在哪里' },
      { id: 'pending-1-user-2', role: 'user', text: '你帮我看下这个有啥问题呢' },
      { id: 'pending-1-agent-0', role: 'agent', text: '我先帮您看一下处罚记录和最近的申诉结果，您先别着急。' },
      {
        id: 'pending-1-agent-1',
        role: 'agent',
        text: '《抖音网络社区自律公约》：抖音app-我-右上角≡-设置-抖音规则中心，这是咱们抖音官方的一个规则呢',
      },
      { id: 'pending-1-user-3', role: 'user', text: '我之前已经申诉过一次了，但是没有通过。' },
      { id: 'pending-1-agent-2', role: 'agent', text: '明白，我帮您再核对一下驳回原因，看看是不是材料或说明不完整。' },
      { id: 'pending-1-user-4', role: 'user', text: '如果需要补充什么材料你直接告诉我，我这边可以配合。' },
      { id: 'pending-1-agent-3', role: 'agent', text: '好的，我这边先帮您发起内部复核，稍后把需要您补充的内容整理给您。' },
      { id: 'pending-1-user-5', role: 'user', text: '好的明白了，谢谢，没其他问题了' },
    ],
    status: 'generating',
    draftText: '',
  },
  'managed-1': {
    messages: [
      { id: 'managed-1-user-1', role: 'user', text: '你帮我看下这个有啥问题呢' },
      { id: 'managed-1-agent-0', role: 'agent', text: '我先帮您核对一下当前物流轨迹和异常节点，请稍等。' },
      {
        id: 'managed-1-agent-1',
        role: 'agent',
        text: '《抖音网络社区自律公约》：抖音app-我-右上角≡-设置-抖音规则中心，这是咱们抖音官方的一个规则呢',
      },
      { id: 'managed-1-user-2', role: 'user', text: '我看物流一直停在转运中心，没有新的更新。' },
      { id: 'managed-1-agent-2', role: 'agent', text: '当前看是中转环节超时，我这边已经帮您催促承运商优先处理。' },
      { id: 'managed-1-user-3', role: 'user', text: '那我这边还需要额外操作什么吗？' },
      { id: 'managed-1-agent-3', role: 'agent', text: '暂时不需要，您保持电话畅通即可，有新进展我会第一时间同步您。' },
      { id: 'managed-1-user-4', role: 'user', text: '好的明白了，谢谢，没其他问题了' },
    ],
    status: 'editable',
    draftText: DEFAULT_CARD_DRAFT_TEXT,
  },
  'other-1': {
    status: 'replied',
    draftText: '',
  },
};
const DEFAULT_CARD_SCENARIO = 'im';
const TICKET_STATUS_LABELS = {
  pending: '待干预',
  managed: '托管中',
  other: '其它',
};
const DEFAULT_TICKET_SECTIONS = [
  {
    id: 'pending',
    title: '待干预',
    count: 3,
    items: [
      {
        id: 'ticket-pending-1',
        title: '售后·商家拒绝仅退款',
        userName: '海阔**天空',
        orderId: '2918575148379876',
        time: '13:32',
        avatarSrc: liSiruAvatar,
        tags: [{ label: '待干预', variant: 'red' }],
        ticketMetaTags: [
          { label: '24:20', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '催4', variant: 'grey' },
          { label: '高优', variant: 'grey' },
          { label: '退款争议', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：风控 Agent 已完成订单和举证核验，判定商品描述不符责任偏商家侧，客服 Agent 正准备以实付金额 50% 为起点与用户协商退款方案。',
        ticketProgressAgents: ['analysis', 'outbound', 'execution'],
      },
      {
        id: 'ticket-pending-2',
        title: '售后·缺件补发未履约',
        userName: '海*天',
        orderId: '2918575148379981',
        time: '13:18',
        avatarSrc: liSiruAvatar,
        ticketStatusDot: true,
        tags: [{ label: '待干预', variant: 'red' }],
        ticketMetaTags: [
          { label: '18:06', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '催2', variant: 'grey' },
          { label: '补发异常', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：履约 Agent 已确认仓内补发单未正常出库，物流 Agent 正反查波次记录并催仓补发，客服 Agent 待拿到明确承诺时间后同步用户。',
        ticketProgressAgents: ['execution', 'planner', 'outbound'],
      },
      {
        id: 'ticket-pending-3',
        title: '售后·退款执行异常',
        userName: '糖炒**栗子',
        orderId: '2918575148380245',
        time: '12:56',
        avatarSrc: chengchengAvatar,
        tags: [{ label: '待干预', variant: 'red' }],
        ticketMetaTags: [
          { label: '09:42', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '退款失败', variant: 'grey' },
          { label: '系统异常', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：支付 Agent 已定位原退款单回调失败，资损 Agent 正校验资金状态，客服 Agent 暂缓二次退款操作，等待补单结果后再执行人工兜底。',
        ticketProgressAgents: ['execution', 'analysis', 'outbound'],
      },
    ],
  },
  {
    id: 'managed',
    title: '托管中',
    count: 6,
    items: [
      {
        id: 'ticket-managed-1',
        title: '售后·退运费申诉处理中',
        userName: '海阔**天空',
        orderId: '2918575148381166',
        time: '13:20',
        avatarSrc: chengchengAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '催4', variant: 'grey' },
          { label: '退运费', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：规则 Agent 已完成退运费资格判断，商责证据充分，协商 Agent 已向商家发起补偿方案确认，当前等待商家在 SLA 内反馈。',
        ticketProgressAgents: ['analysis', 'outbound', 'execution'],
      },
      {
        id: 'ticket-managed-2',
        title: '履约·物流停滞超时',
        userName: '阔**天张三**空',
        orderId: '2918575148381452',
        time: '12:48',
        avatarSrc: liuDelinAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '催4', variant: 'grey' },
          { label: '物流超时', variant: 'grey' },
          { label: '平台托管', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：物流 Agent 已确认包裹在分拨中心停滞超 48 小时，履约 Agent 正向承运商升级催派，客服 Agent 已向用户承诺优先跟踪并同步最新流转节点。',
        ticketProgressAgents: ['planner', 'execution', 'outbound'],
      },
      {
        id: 'ticket-managed-3',
        title: '售后·退差价申诉',
        userName: '海*天',
        orderId: '2918575148381730',
        time: '12:26',
        avatarSrc: liuDelinAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '价格争议', variant: 'grey' },
          { label: '补差处理中', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：价格 Agent 已比对活动期与下单价差，确认存在价保区间差额，资损 Agent 正复核补差金额，客服 Agent 待复核完成后向用户补发差价说明。',
        ticketProgressAgents: ['analysis', 'execution', 'outbound'],
      },
      {
        id: 'ticket-managed-4',
        title: '售后·破损件补偿审核',
        userName: '可乐**冰块',
        orderId: '2918575148382014',
        time: '11:43',
        avatarSrc: duanRanAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '图片已补充', variant: 'grey' },
          { label: '补偿审核', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：质检 Agent 已完成破损图片校验，判定商品外箱和主体均有明显损伤，补偿 Agent 正依据平台规则计算建议赔付金额并流转审核。',
        ticketProgressAgents: ['analysis', 'execution', 'planner'],
      },
      {
        id: 'ticket-managed-5',
        title: '售后·商家超时未响应',
        userName: '海阔**天',
        orderId: '2918575148382448',
        time: '11:12',
        avatarSrc: liSiruAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '催4', variant: 'grey' },
          { label: '超时未响应', variant: 'grey' },
          { label: '平台介入', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：协商 Agent 已连续 4 次触达商家未获响应，平台托管流程已开启，规则 Agent 正整理责任链路，客服 Agent 将在超时节点后直接给用户同步处理结果。',
        ticketProgressAgents: ['outbound', 'analysis', 'execution'],
      },
      {
        id: 'ticket-managed-6',
        title: '履约·拒收退回跟进',
        userName: '奶油**泡芙',
        orderId: '2918575148382763',
        time: '10:35',
        avatarSrc: chengchengAvatar,
        tags: [{ label: '托管中', variant: 'green' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '拒收退回', variant: 'grey' },
          { label: '逆向物流', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：逆向物流 Agent 已确认包裹进入退回链路，仓配 Agent 正同步签收节点，客服 Agent 待仓侧回传实收结果后判断是否进入退款流程。',
        ticketProgressAgents: ['planner', 'execution', 'outbound'],
      },
    ],
  },
  {
    id: 'other',
    title: '其它',
    count: 20,
    items: [
      {
        id: 'ticket-other-1',
        title: '售后·退款方案已挂起',
        userName: '海阔**天空',
        orderId: '2918575148383090',
        time: '昨天',
        avatarSrc: liSiruAvatar,
        tags: [{ label: '已挂起', variant: 'orange' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '催4', variant: 'grey' },
          { label: '待补充证据', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：举证 Agent 发现用户补充凭证缺少关键签收页面，当前工单已暂时挂起，客服 Agent 已回访用户补充材料，待资料齐全后继续推进退款审核。',
        ticketProgressAgents: ['analysis', 'outbound', 'alert'],
      },
      {
        id: 'ticket-other-2',
        title: '售后·用户撤销退款申请',
        userName: '布丁**奶盖',
        orderId: '2918575148383417',
        time: '昨天',
        avatarSrc: liuDelinAvatar,
        tags: [{ label: '已挂起', variant: 'orange' }],
        ticketMetaTags: [
          { label: '催4', variant: 'grey' },
          { label: '用户撤销', variant: 'grey' },
          { label: '关闭确认', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：客服 Agent 已确认用户主动撤销退款诉求，规则 Agent 正复核是否存在后续追诉风险，当前工单保持挂起，待确认无异议后归档关闭。',
        ticketProgressAgents: ['outbound', 'analysis', 'alert'],
      },
      {
        id: 'ticket-other-3',
        title: '售后·退货退款已完结',
        userName: '海阔**天空',
        orderId: '2918575148383772',
        time: '周二',
        avatarSrc: liuDelinAvatar,
        tags: [{ label: '已处理', variant: 'blue' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '催4', variant: 'grey' },
          { label: '退款成功', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：仓配 Agent 已确认退货签收，资损 Agent 完成退款出款，客服 Agent 已向用户同步到账结果并完成满意度回访，工单归档结束。',
        ticketProgressAgents: ['planner', 'execution', 'outbound'],
      },
      {
        id: 'ticket-other-4',
        title: '履约·超时签收补偿完成',
        userName: '海阔**天空',
        orderId: '2918575148384015',
        time: '周二',
        avatarSrc: duanRanAvatar,
        tags: [{ label: '已处理', variant: 'blue' }],
        ticketMetaTags: [
          { label: '补偿到账', variant: 'grey' },
          { label: '回访完成', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：履约 Agent 已确认签收超时责任成立，补偿 Agent 已完成红包补偿发放，客服 Agent 回访用户确认已收到补偿且无继续申诉需求。',
        ticketProgressAgents: ['planner', 'execution', 'outbound'],
      },
      {
        id: 'ticket-other-5',
        title: '售后·平台介入已处理',
        userName: '奶茶**珍珠',
        orderId: '2918575148384356',
        time: '周一',
        avatarSrc: chengchengAvatar,
        tags: [{ label: '已处理', variant: 'blue' }],
        ticketMetaTags: [
          { label: '24时30分', variant: 'grey', iconName: 'alarm-clock-stroked' },
          { label: '平台判责', variant: 'grey' },
          { label: '用户已确认', variant: 'grey' },
        ],
        ticketProgressText: '最新进度：平台判责 Agent 已输出最终责任结论，资损 Agent 按判责完成退款执行，客服 Agent 已向用户确认处理结果，当前工单已正式完结。',
        ticketProgressAgents: ['analysis', 'execution', 'outbound'],
      },
    ],
  },
];

/* ── 根容器：展开 / 收起（仅头像列）── */
const ROOT = 'tfds-conversation-list relative flex h-full min-h-0 w-full shrink-0 overflow-hidden select-none';
const ROOT_EXPANDED = 'flex-col gap-4 p-4';
const ROOT_COLLAPSED = 'flex-col items-center gap-4 px-3 py-4';

/* ── 顶部标题栏 + 工具按钮 ── */
const HEADER = 'flex h-[26px] items-center justify-between gap-3';
const HEADER_MAIN = 'flex min-w-0 items-center gap-3';
const TITLE = 'm-0 truncate text-sm [font-weight:var(--font-semibold)] leading-5 text-foreground';
const ACTIONS = 'flex shrink-0 items-center gap-1';
/* ── Tabs + 列表滚动区 ── */
const TABS_WRAP = 'max-w-full self-start';
const LIST = 'mx-[-12px] flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto px-3';
const CARD_LIST = 'mx-[-12px] grid min-h-0 flex-1 grid-cols-1 auto-rows-max gap-4 overflow-y-auto px-3';
const TICKET_CARD_LIST = 'mx-[-12px] flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-3';
const CARD_LIST_TWO_COLUMN = 'grid-cols-2';
const CARD_LIST_THREE_COLUMN = 'grid-cols-3';
const SECTION = 'flex flex-col gap-1';
const SECTION_HEADER = [
  'flex h-5 w-full items-center justify-between gap-2 rounded-md p-0.5 text-left',
  'text-xs leading-4 text-foreground-muted transition-colors tfds-motion-ui-fast',
  'hover:text-foreground-secondary active:text-foreground-secondary',
  'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-200',
].join(' ');
const SECTION_TITLE = 'flex min-w-0 items-center gap-1';
const SECTION_CARET = 'transition-transform tfds-motion-ui-fast';
const SECTION_CONTENT = 'flex flex-col gap-1';
/* ── 会话行：默认 / 选中 / 左侧色条 ── */
const ITEM_BASE = [
  'group relative flex w-full items-center gap-3 overflow-hidden rounded-lg p-3 text-left',
  'transition-colors tfds-motion-ui-fast focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-200',
].join(' ');
const ITEM_DEFAULT = 'bg-transparent hover:bg-fill active:bg-fill-active';
const ITEM_ACTIVE = 'bg-surface shadow-list';
const ACTIVE_RAIL = 'absolute bottom-0 left-0 top-0 w-1 bg-brand-500';
const ITEM_BODY = 'flex min-w-0 flex-1 flex-col gap-1';
const ITEM_TITLE_ROW = 'flex min-w-0 items-start justify-between gap-2';
const ITEM_TITLE = 'm-0 min-w-0 flex-1 truncate text-sm [font-weight:var(--font-semibold)] leading-6 text-foreground';
const TAGS = 'flex shrink-0 items-center gap-1';
const META = 'flex min-w-0 items-center gap-1 text-xs leading-4 text-foreground-muted';
const USER = 'block w-[50px] shrink-0 truncate';
const ORDER = 'min-w-0 truncate';
const TIME = 'ml-auto shrink-0 pl-2 text-foreground-muted';

/* ── 收起态：仅头像 + 展开入口 ── */
const AVATAR_ONLY_HEADER = 'flex h-8 w-full items-center justify-center';
const AVATAR_ONLY_LIST = 'flex min-h-0 flex-1 flex-col self-stretch gap-1 overflow-y-auto';
const AVATAR_ONLY_ITEM = [
  'relative inline-flex h-[68px] min-h-[68px] w-full shrink-0 items-center rounded-xl px-4',
  'transition-colors tfds-motion-ui-fast hover:bg-fill active:bg-fill-active',
  'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-200',
].join(' ');
const AVATAR_ONLY_ITEM_INACTIVE = 'justify-center py-[18px]';
const AVATAR_ONLY_ITEM_ACTIVE = 'justify-center overflow-hidden bg-surface py-3 shadow-list hover:bg-surface';
const AVATAR_ONLY_ACTIVE_RAIL = 'absolute bottom-0 left-0 top-0 w-1 bg-data-0';
/* ── 右侧拖拽分隔条 ── */
const RESIZE_HANDLE_CLASS = 'absolute right-0 top-0 bottom-0 z-20 w-3 cursor-col-resize touch-none select-none focus-visible:outline-none';
const RESIZE_HANDLE_BAR_CLASS = `absolute right-0 top-0 bottom-0 ${TFDS_RESIZE_LINE_WIDTH_CLASS} ${TFDS_RESIZE_HANDLE_LINE_TRANSITION}`;

/* ── 卡片列表变体 ── */
const CARD_ITEM = [
  'group flex flex-col rounded-xl bg-surface shadow-list transition-shadow tfds-motion-ui-fast',
  'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-200',
].join(' ');
const CARD_ITEM_INTERACTIVE = 'cursor-pointer';
const CARD_ITEM_ACTIVE_SHADOW = 'var(--shadow-list), inset 0 0 0 1.5px var(--color-brand-500)';
const CARD_HEADER = 'flex items-start gap-3 px-4 pt-3 pb-2';
const CARD_HEADER_MAIN = 'flex min-w-0 flex-1 flex-wrap items-center gap-1';
const CARD_TITLE = 'min-w-0 truncate text-sm [font-weight:var(--font-semibold)] leading-5 text-foreground';
const CARD_TAGS = 'flex min-w-0 flex-wrap items-center gap-1';
const CARD_MESSAGE_REGION = 'flex flex-col overflow-y-auto px-4 pb-2';
const CARD_MESSAGE_REGION_REPLIED = 'h-[196px] gap-3';
const CARD_MESSAGE_REGION_GENERATING = 'h-[196px] gap-3';
const CARD_MESSAGE_REGION_EDITABLE = 'h-[155px] gap-3';
const CARD_MESSAGE_ROW_BASE = 'flex w-full';
const CARD_MESSAGE_ROW_USER = 'justify-start';
const CARD_MESSAGE_ROW_OUTGOING = 'justify-end';
const CARD_MESSAGE_BUBBLE_BASE = 'max-w-[calc(100%-24px)] rounded-lg px-2 py-1.5 text-xs leading-4 text-foreground';
const CARD_MESSAGE_BUBBLE_USER = 'rounded-tl-none bg-fill';
const CARD_MESSAGE_BUBBLE_BOT = 'rounded-tr-none bg-[image:var(--gradient-ai-fill-1)]';
const CARD_MESSAGE_BUBBLE_AGENT = 'rounded-tr-none bg-chat-outgoing';
const CARD_DIVIDER = 'h-px w-full bg-border-default';
const CARD_FOOTER_BASE = 'shrink-0';
const CARD_FOOTER_REPLIED = 'px-4 py-4 text-xs leading-4 text-[#22272759]';
const CARD_FOOTER_GENERATING = 'flex items-center gap-2 px-4 py-4 text-xs leading-4 text-[#22272759]';
const CARD_FOOTER_EDITABLE = 'flex flex-col gap-3 px-3 py-3';
const CARD_FOOTER_TEXT = 'w-full text-xs leading-4 text-foreground';
const CARD_FOOTER_BUTTON_ROW = 'flex w-full justify-end';
const TICKET_CARD = [
  'group relative rounded-xl bg-surface transition-shadow tfds-motion-ui-fast',
  'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-data-0',
].join(' ');
const TICKET_CARD_INTERACTIVE = 'cursor-pointer';
const TICKET_CARD_RICH = 'flex flex-col gap-3 overflow-hidden px-3 py-3';
const TICKET_CARD_RICH_HEAD = 'flex min-w-0 items-start gap-3';
const TICKET_CARD_TITLE_ROW_TOP = 'flex min-w-0 items-center gap-2';
const TICKET_CARD_BODY = 'flex min-w-0 flex-1 flex-col gap-1';
const TICKET_CARD_TITLE = 'min-w-0 flex-1 truncate text-sm [font-weight:var(--font-semibold)] leading-6 text-foreground';
const TICKET_CARD_TITLE_TAGS = 'flex shrink-0 items-center gap-1.5';
const TICKET_CARD_META_ROW = 'flex min-w-0 items-center gap-2 text-xs leading-4 text-foreground-muted';
const TICKET_CARD_USER = 'block max-w-[52px] shrink-0 truncate';
const TICKET_CARD_ORDER_WRAP = 'flex min-w-0 items-center gap-1';
const TICKET_CARD_ORDER = 'min-w-0 truncate';
const TICKET_CARD_TIME = 'ml-auto shrink-0 pl-2 text-foreground-muted';
const TICKET_CARD_PROGRESS = 'rounded-lg bg-blueGrey-100 px-3 py-2';
const TICKET_CARD_PROGRESS_TEXT = 'm-0 text-xs leading-5 text-foreground line-clamp-2';
const TICKET_CARD_PROGRESS_LEAD = 'inline-flex items-center align-middle leading-5';
const TICKET_CARD_PROGRESS_LABEL = 'inline-flex min-h-5 items-center align-middle leading-5';
const TICKET_CARD_PROGRESS_STACK = 'mr-1.5 inline-flex h-[14px] items-center self-center align-middle';
const TICKET_CARD_PROGRESS_STACK_ITEM = 'relative -ml-1 first:ml-0 shrink-0 align-middle';
const TICKET_CARD_META_TAGS = 'flex min-w-0 flex-wrap items-center gap-1.5';
const TICKET_CARD_SECTION = 'flex flex-col gap-4';
const TICKET_CARD_SECTION_CONTENT = 'grid grid-cols-1 gap-4';
const TICKET_CARD_SECTION_HEADER = 'flex items-center gap-1 text-xs leading-4 text-foreground-muted';
const TICKET_CARD_SECTION_HEADER_TITLE = 'text-xs [font-weight:var(--font-regular)] leading-4 text-foreground-muted';
const TICKET_CARD_SECTION_HEADER_COUNT = 'text-xs leading-4 text-foreground-muted';
const TICKET_CARD_STATUS_DOT = 'size-2 shrink-0 rounded-full bg-[#F2496F] ring-2 ring-white';
const TICKET_PROGRESS_LABEL_TEXT = '整体任务最新进展与总结：';
const TICKET_PROGRESS_PREFIXES = [
  '最新进度：',
  '最新进度:',
  '整体任务最新进展与总结：',
  '整体任务最新进展与总结:',
];

function getSectionItemCount(section) {
  return Array.isArray(section?.items) ? section.items.length : 0;
}

/** loading 占位行/卡片按分组均分，保证与真实 sections 动线一致 */
function getLoadingRowsPerSection(loadingCount, sectionIndex, sectionCount) {
  const total = Math.max(1, loadingCount);
  const count = Math.max(1, sectionCount);
  const base = Math.floor(total / count);
  const remainder = total % count;
  return Math.max(1, base + (sectionIndex < remainder ? 1 : 0));
}

function getTabItemCount(sections, tabId) {
  if (!Array.isArray(sections) || !tabId || tabId === 'all') return null;
  const matchedSection = sections.find((section) => section.id === tabId);
  return matchedSection ? getSectionItemCount(matchedSection) : 0;
}

function normalizeTicketProgressText(text) {
  const rawText = typeof text === 'string' ? text.trim() : '';
  if (!rawText) return '';

  const matchedPrefix = TICKET_PROGRESS_PREFIXES.find((prefix) => rawText.startsWith(prefix));
  return matchedPrefix ? rawText.slice(matchedPrefix.length).trim() : rawText;
}

function renderTabLabel(tab, count) {
  if (count === undefined || count === null) return tab.label;
  return `${tab.label} ${count}`;
}

function ConversationTag({ tag }) {
  return (
    <Tag
      variant={tag.variant || 'grey'}
      size="m"
      radius="md"
      fontWeight="regular"
      showIcon={Boolean(tag.iconName)}
      iconName={tag.iconName}
      className="shrink-0"
    >
      {tag.label}
    </Tag>
  );
}

function ConversationItem({ item, active, onClick }) {
  validateTagHierarchy(item.tags, item.id);
  const content = (
    <>
      {active ? <span className={ACTIVE_RAIL} aria-hidden="true" /> : null}
      <Avatar shape="round" size="s" type="image" src={item.avatarSrc} alt={item.userName} />
      <div className={ITEM_BODY}>
        <div className={ITEM_TITLE_ROW}>
          <h3 className={ITEM_TITLE}>{item.title}</h3>
          <div className={TAGS}>
            {(item.tags || []).map((tag, index) => (
              <ConversationTag key={`${item.id}-${tag.label}-${index}`} tag={tag} />
            ))}
          </div>
        </div>

        <div className={META}>
          <Tooltip content={item.userName}>
            <span className={USER}>{item.userName}</span>
          </Tooltip>
          <Icon name="file-05-stroked" size={12} aria-hidden="true" />
          <span className={ORDER}>{item.orderId}</span>
          <span className={TIME}>{item.time}</span>
        </div>
      </div>
    </>
  );

  const className = [ITEM_BASE, active ? ITEM_ACTIVE : ITEM_DEFAULT].join(' ');

  if (onClick) {
    return (
      <button type="button" className={className} onClick={() => onClick(item)} data-tfds-component="ConversationList.Item">
        {content}
      </button>
    );
  }

  return <article className={className} data-tfds-component="ConversationList.Item">{content}</article>;
}

function ConversationAvatarItem({ item, active, onClick }) {
  return (
    <button
      type="button"
      className={[
        AVATAR_ONLY_ITEM,
        active ? AVATAR_ONLY_ITEM_ACTIVE : AVATAR_ONLY_ITEM_INACTIVE,
      ].join(' ')}
      onClick={() => onClick(item)}
      aria-label={item.title}
      title={item.title}
      data-tfds-component="ConversationList.AvatarItem"
    >
      {active ? <span className={AVATAR_ONLY_ACTIVE_RAIL} aria-hidden="true" /> : null}
      <Avatar shape="round" size="s" type="image" src={item.avatarSrc} alt={item.userName} />
    </button>
  );
}

function ConversationCardTag({ tag }) {
  return <ConversationTag tag={tag} />;
}

function isPrimaryStatusTag(tag) {
  return ['red', 'green', 'orange', 'blue'].includes(tag?.variant);
}

/**
 * 标签层级硬约束兜底（dev 环境）
 * 规则参考 DESIGN_PRINCIPLES.md §4.8：
 *   1) 数组最后一个元素 = 主要状态（彩色 variant: red/orange/green/blue）
 *   2) 其余前置元素 = 必须 grey
 *   3) 单标签场景：该唯一 tag 即主要状态，必须彩色
 * 命中错配时仅 console.warn，不 throw、不修改数据，运行时不影响渲染。
 */
const __tagHierarchyWarned = new Set();
function validateTagHierarchy(tags, itemId) {
  if (process.env.NODE_ENV === 'production') return;
  if (!Array.isArray(tags) || tags.length === 0) return;
  if (__tagHierarchyWarned.has(itemId)) return;

  const last = tags[tags.length - 1];
  const lastIsPrimary = isPrimaryStatusTag(last);
  const violations = [];

  if (!lastIsPrimary) {
    violations.push(
      `最后一个 tag variant="${last?.variant}" 不是主要状态色（应为 red/orange/green/blue）`
    );
  }
  if (tags.length === 1 && !lastIsPrimary) {
    violations.push('单标签场景下该 tag 必须使用彩色 variant，不可使用 grey');
  }
  for (let i = 0; i < tags.length - 1; i += 1) {
    const t = tags[i];
    if (isPrimaryStatusTag(t)) {
      violations.push(`第 ${i} 个 tag variant="${t.variant}" 是主要状态色但被放在非末位（应排到末位或改为 grey）`);
    } else if (t?.variant && t.variant !== 'grey') {
      violations.push(`第 ${i} 个辅助 tag variant="${t.variant}" 不是 grey（辅助标签必须统一 grey）`);
    }
  }

  if (violations.length > 0) {
    __tagHierarchyWarned.add(itemId);
    // eslint-disable-next-line no-console
    console.warn(
      `[ConversationList] 列表项 "${itemId}" 的 tags 违反层级规则（详见 DESIGN_PRINCIPLES.md §4.8）：\n  - ${violations.join('\n  - ')}`,
      tags
    );
  }
}

function sortCardTags(tags) {
  if (!Array.isArray(tags) || tags.length <= 1) return Array.isArray(tags) ? tags : [];

  const statusTags = [];
  const secondaryTags = [];

  tags.forEach((tag) => {
    if (isPrimaryStatusTag(tag)) {
      statusTags.push(tag);
      return;
    }
    secondaryTags.push(tag);
  });

  return [...statusTags, ...secondaryTags];
}

function ConversationCardMessage({ message }) {
  const isUser = message.role === 'user';
  const isBot = message.role === 'bot';
  const bubbleClassName = isUser
    ? CARD_MESSAGE_BUBBLE_USER
    : (isBot ? CARD_MESSAGE_BUBBLE_BOT : CARD_MESSAGE_BUBBLE_AGENT);
  const bubbleEnterClass = messageBubbleEnterClass(isUser ? 'incoming' : 'outgoing');

  return (
    <div className={[CARD_MESSAGE_ROW_BASE, isUser ? CARD_MESSAGE_ROW_USER : CARD_MESSAGE_ROW_OUTGOING].join(' ')}>
      <div className={[
        CARD_MESSAGE_BUBBLE_BASE,
        bubbleClassName,
        bubbleEnterClass,
      ].join(' ')}>
        {message.text}
      </div>
    </div>
  );
}

function ConversationProcessingSpinner() {
  return <IconLoading size="sm" aria-hidden="true" />;
}

function buildSentCardMessage(cardId, draftText, sequence) {
  return {
    id: `${cardId}-agent-sent-${sequence}`,
    role: 'agent',
    text: draftText,
  };
}

function buildNextCardAfterSend(card, draftText, sequence) {
  return {
    ...card,
    messages: [...(card.messages || []), buildSentCardMessage(card.id, draftText, sequence)],
    draftText: '',
    status: 'replied',
  };
}

function applyCardItemOverride(item, override) {
  if (!override) return item;
  return {
    ...item,
    ...override,
  };
}

function ConversationCardFooter({ card, onSend }) {
  const draftText = typeof card.draftText === 'string' ? card.draftText.trim() : '';
  const isRepliedState = card.status === 'replied';
  const showEditableState = card.status === 'editable' && draftText.length > 0;

  if (isRepliedState) {
    return (
      <div className={[CARD_FOOTER_BASE, CARD_FOOTER_REPLIED].join(' ')}>
        已回复用户
      </div>
    );
  }

  if (!showEditableState) {
    return (
      <div className={[CARD_FOOTER_BASE, CARD_FOOTER_GENERATING].join(' ')}>
        <ConversationProcessingSpinner />
        <span>回复内容生成中</span>
      </div>
    );
  }

  return (
    <>
      <div className={CARD_DIVIDER} aria-hidden="true" />
      <div className={[CARD_FOOTER_BASE, CARD_FOOTER_EDITABLE].join(' ')}>
        <p className={CARD_FOOTER_TEXT}>{draftText}</p>
        <div className={CARD_FOOTER_BUTTON_ROW}>
          <Button
            type="button"
            variant="primary"
            size="sm"
            icon={<Icon name="send-01-stroked" size={16} aria-hidden="true" />}
            iconOnly
            className="!h-6 !w-6 !rounded-md !p-1"
            tooltip="发送回复"
            onKeyDown={(event) => {
              event.stopPropagation();
            }}
            onClick={(event) => {
              event.stopPropagation();
              if (onSend) onSend(card);
            }}
            aria-label="发送回复"
          />
        </div>
      </div>
    </>
  );
}

function buildFallbackCardMessages(item) {
  const statusSummary = (item.tags || []).map((tag) => tag.label).join(' / ');

  return [
    { id: `${item.id}-user-1`, role: 'user', text: `我想继续确认「${item.title}」的处理进展。` },
    {
      id: `${item.id}-agent-1`,
      role: 'agent',
      text: statusSummary
        ? `当前记录状态为 ${statusSummary}，我来继续帮您跟进处理。`
        : '我来继续帮您跟进这个会话的处理进展。',
    },
    { id: `${item.id}-user-2`, role: 'user', text: `对应单号是 ${item.orderId}，麻烦再帮我确认一下。` },
    { id: `${item.id}-agent-2`, role: 'agent', text: '好的，我先同步核对系统记录，并帮您整理当前可执行的处理方案。' },
    { id: `${item.id}-user-3`, role: 'user', text: '我比较担心一直没有结果，想知道大概多久能处理完。' },
    { id: `${item.id}-agent-3`, role: 'agent', text: '理解您的着急，我会继续盯进度，有更新会第一时间回复您。' },
  ];
}

function getDraftTextSeed(item) {
  const source = String(item?.id || item?.title || item?.orderId || '');
  let hash = 0;
  for (let index = 0; index < source.length; index += 1) {
    hash = (hash * 31 + source.charCodeAt(index)) % 2147483647;
  }
  return hash;
}

function buildFallbackDraftText(item) {
  const seed = getDraftTextSeed(item);
  return DEFAULT_CARD_DRAFT_TEXTS[seed % DEFAULT_CARD_DRAFT_TEXTS.length] || DEFAULT_CARD_DRAFT_TEXT;
}

function normalizeCardContent(item) {
  const override = CARD_CONTENT_OVERRIDES[item.id] || {};
  const messages = Array.isArray(item.messages) && item.messages.length > 0
    ? item.messages
    : (override.messages || buildFallbackCardMessages(item));
  const draftText = typeof item.draftText === 'string'
    ? item.draftText
    : (
      typeof override.draftText === 'string'
        ? override.draftText
        : ((item.status || override.status) === 'editable' ? buildFallbackDraftText(item) : '')
    );
  const requestedStatus = item.status || override.status || 'replied';
  const status = requestedStatus === 'editable'
    ? (draftText.trim() ? 'editable' : 'generating')
    : (requestedStatus === 'replied' ? 'replied' : 'generating');

  return {
    ...item,
    messages,
    draftText,
    status,
  };
}

function ConversationCardItem({ item, active, onClick, onSend }) {
  const card = normalizeCardContent(item);
  validateTagHierarchy(card.tags, card.id);
  const messageRegionRef = useRef(null);
  const interactive = Boolean(onClick);
  const messageRegionStateClass = card.status === 'editable'
    ? CARD_MESSAGE_REGION_EDITABLE
    : (card.status === 'replied' ? CARD_MESSAGE_REGION_REPLIED : CARD_MESSAGE_REGION_GENERATING);
  const clickProps = interactive ? {
    role: 'button',
    tabIndex: 0,
    onClick: () => onClick(item),
    onKeyDown: (event) => {
      if (event.key !== 'Enter' && event.key !== ' ') return;
      event.preventDefault();
      onClick(item);
    },
  } : {};

  useEffect(() => {
    const node = messageRegionRef.current;
    if (!node) return;
    node.scrollTop = node.scrollHeight;
  }, [active, card.id, card.status, card.messages.length]);

  return (
    <article
      className={[CARD_ITEM, interactive ? CARD_ITEM_INTERACTIVE : ''].filter(Boolean).join(' ')}
      style={active ? { boxShadow: CARD_ITEM_ACTIVE_SHADOW } : undefined}
      aria-label={card.title}
      data-tfds-component="ConversationList.CardItem"
      aria-pressed={interactive ? active : undefined}
      data-active={active ? 'true' : 'false'}
      {...clickProps}
    >
      <div className={CARD_HEADER}>
        <div className={CARD_HEADER_MAIN}>
          <h3 className={CARD_TITLE}>{card.title}</h3>
          <div className={CARD_TAGS}>
            {sortCardTags(card.tags).map((tag, index) => (
              <ConversationCardTag key={`${card.id}-${tag.label}-${index}`} tag={tag} />
            ))}
          </div>
        </div>
        <Avatar shape="round" size="s" type="image" src={card.avatarSrc} alt={card.title} />
      </div>
      <div ref={messageRegionRef} className={[CARD_MESSAGE_REGION, messageRegionStateClass].join(' ')}>
        {(card.messages || []).map((message) => (
          <ConversationCardMessage key={message.id} message={message} />
        ))}
      </div>
      <ConversationCardFooter card={card} onSend={onSend} />
    </article>
  );
}

function ConversationTicketCardProgressAgents({ agents = [] }) {
  if (!Array.isArray(agents) || agents.length === 0) return null;

  return (
    <span className={TICKET_CARD_PROGRESS_STACK} aria-hidden="true">
      {agents.slice(0, 4).map((agent, index) => (
        <span key={`${agent}-${index}`} className={TICKET_CARD_PROGRESS_STACK_ITEM}>
          {typeof agent === 'string' && ['planner', 'analysis', 'execution', 'outbound', 'alert'].includes(agent) ? (
            <AgentFamilyAvatar
              avatar={agent}
              size={14}
              className="!inline-flex align-middle ring-1 ring-white"
            />
          ) : (
            <Avatar
              shape="round"
              size="xs"
              type="image"
              src={agent}
              alt=""
              className="!size-3.5 align-middle ring-1 ring-white"
            />
          )}
        </span>
      ))}
    </span>
  );
}

function ConversationTicketCardItem({ item, active, onClick }) {
  validateTagHierarchy(item.tags, item.id);
  const interactive = Boolean(onClick);
  const clickProps = interactive ? {
    role: 'button',
    tabIndex: 0,
    onClick: () => onClick(item),
    onKeyDown: (event) => {
      if (event.key !== 'Enter' && event.key !== ' ') return;
      event.preventDefault();
      onClick(item);
    },
  } : {};
  const titleTags = Array.isArray(item.tags) ? item.tags : [];
  const metaTags = Array.isArray(item.ticketMetaTags) ? item.ticketMetaTags : [];
  const normalizedProgressText = normalizeTicketProgressText(item.ticketProgressText);
  const activeStyle = active ? { boxShadow: 'var(--shadow-list), inset 0 0 0 2px var(--color-data-0)' } : undefined;

  return (
    <article
      className={[
        TICKET_CARD,
        TICKET_CARD_RICH,
        interactive ? TICKET_CARD_INTERACTIVE : '',
      ].filter(Boolean).join(' ')}
      style={activeStyle}
      aria-label={item.title}
      data-tfds-component="ConversationList.TicketCardItem"
      aria-pressed={interactive ? active : undefined}
      data-active={active ? 'true' : 'false'}
      {...clickProps}
    >
      <div className={TICKET_CARD_RICH_HEAD}>
        <Avatar shape="round" size="s" type="image" src={item.avatarSrc} alt={item.userName} />
        <div className={TICKET_CARD_BODY}>
          <div className={TICKET_CARD_TITLE_ROW_TOP}>
            <h3 className={TICKET_CARD_TITLE}>{item.title}</h3>
            {item.ticketStatusDot ? <span className={TICKET_CARD_STATUS_DOT} aria-hidden="true" /> : null}
            <div className={TICKET_CARD_TITLE_TAGS}>
              {titleTags.map((tag, index) => (
                <ConversationTag key={`${item.id}-${tag.label}-${index}`} tag={tag} />
              ))}
            </div>
          </div>
        </div>
      </div>

      <Tooltip content={`${TICKET_PROGRESS_LABEL_TEXT}${normalizedProgressText}`}>
        <div className={TICKET_CARD_PROGRESS}>
          <p className={TICKET_CARD_PROGRESS_TEXT}>
            <span className={TICKET_CARD_PROGRESS_LEAD}>
              <ConversationTicketCardProgressAgents agents={item.ticketProgressAgents} />
              <span className={TICKET_CARD_PROGRESS_LABEL}>{TICKET_PROGRESS_LABEL_TEXT}</span>
            </span>
            {normalizedProgressText}
          </p>
        </div>
      </Tooltip>

      {metaTags.length > 0 ? (
        <div className={TICKET_CARD_META_TAGS}>
          {metaTags.map((tag, index) => (
            <ConversationTag key={`${item.id}-meta-${tag.label}-${index}`} tag={tag} />
          ))}
        </div>
      ) : null}

      <div className={TICKET_CARD_META_ROW}>
        <Tooltip content={item.userName}>
          <span className={TICKET_CARD_USER}>{item.userName}</span>
        </Tooltip>
        <span className={TICKET_CARD_ORDER_WRAP}>
          <Icon name="file-05-stroked" size={12} aria-hidden="true" />
          <span className={TICKET_CARD_ORDER}>{item.orderId}</span>
        </span>
        <span className={TICKET_CARD_TIME}>{item.time}</span>
      </div>
    </article>
  );
}

function normalizeSections(sections, cardScenario, variant) {
  if (Array.isArray(sections) && sections.length > 0) return sections;
  if (variant === 'card' && cardScenario === 'ticket') return DEFAULT_TICKET_SECTIONS;
  return DEFAULT_SECTIONS;
}

function filterSectionsByTab(sections, activeTab) {
  if (!activeTab || activeTab === 'all') return sections;
  const filteredSections = sections.filter((section) => section.id === activeTab);
  return filteredSections.length > 0 ? filteredSections : sections;
}

function getFirstItemId(sections) {
  if (!Array.isArray(sections)) return null;

  for (const section of sections) {
    const firstItemId = section?.items?.[0]?.id;
    if (firstItemId) return firstItemId;
  }

  return null;
}

function hasItem(sections, itemId) {
  if (!itemId || !Array.isArray(sections)) return false;
  return sections.some((section) => (section.items || []).some((item) => item.id === itemId));
}

function getSectionIds(sections) {
  if (!Array.isArray(sections)) return [];
  return sections.map((section) => section.id).filter(Boolean);
}

function resolveStatusTag(activeTab, sectionId) {
  if (activeTab && activeTab !== 'all') {
    return STATUS_TAG_BY_TAB[activeTab] || null;
  }

  return STATUS_TAG_BY_TAB[sectionId] || null;
}

function normalizeItemTags(tags, statusTag) {
  const resolvedTags = Array.isArray(tags) ? tags : [];

  if (!statusTag) return resolvedTags;
  if (resolvedTags.length === 0) return [statusTag];

  return resolvedTags.map((tag, index) => (
    index === resolvedTags.length - 1
      ? { ...tag, label: statusTag.label, variant: statusTag.variant }
      : tag
  ));
}

function normalizeSectionsByActiveTab(sections, activeTab) {
  if (!Array.isArray(sections)) return [];

  return sections.map((section) => ({
    ...section,
    items: (section.items || []).map((item) => ({
      ...item,
      tags: normalizeItemTags(item.tags, resolveStatusTag(activeTab, section.id)),
    })),
  }));
}

/**
 * ConversationList — 会话 / 工单侧栏列表
 * @prop {'default'|'card'} [variant] — 列表形态：默认分组列表 / 卡片列表
 * @prop {'default'|'card'} [defaultVariant='default'] — 非受控初始列表形态
 * @prop {function|null} [onVariantChange=null] — 布局切换 (nextVariant) => void
 * @prop {'im'|'ticket'} [cardScenario='im'] — 卡片列表场景：IM 场景 / 工单场景
 * @prop {string} [title='会话列表'] — 顶部标题
 * @prop {Array<{id:string,label:string,count?:number}>} [tabs] — 分段筛选项；空数组时用内置示例
 * @prop {string} [activeTab] — 受控当前筛选 tab id；不传则非受控
 * @prop {string} [defaultActiveTab='all'] — 非受控初始筛选
 * @prop {function|null} [onTabChange=null] — 筛选切换 (tabId, tab) => void
 * @prop {Array<{id:string,title:string,count?:number,items:Array}>} [sections] — 分组数据；`variant="card" cardScenario="im"` 时每个 item 读取 messages / draftText / status；`cardScenario="ticket"` 时可额外读取 ticketProgressText / ticketProgressAgents / ticketMetaTags，其中 `ticketProgressText` 只承载整体 agent 任务的最新进展与总结正文，前缀由组件统一输出
 * @prop {string} [activeItemId] — 受控当前高亮项 id；不传则非受控
 * @prop {string|null} [defaultActiveItemId=null] — 非受控初始高亮项 id；未传时默认选中当前可见第一项
 * @prop {function|null} [onItemClick=null] — 行点击 (item) => void
 * @prop {function|null} [onSend=null] — 卡片可发送态点击发送 ({ item, draftText, nextItem, sectionId }) => void
 * @prop {boolean} [showActions=true] — 是否显示搜索 / 筛选 / 文件按钮
 * @prop {boolean} [showLayoutToggle=true] — 是否显示右上角布局切换按钮
 * @prop {boolean} [resizable=true] — 是否启用组件自身右侧拖拽；嵌入已有可拖拽框架时应关闭
 * @prop {boolean} [collapsible=true] — 是否启用默认列表的纯头像收起态
 * @prop {boolean} [autoCollapseOnNarrow=true] — 是否根据外层实际宽度自动切换纯头像态
 * @prop {function|null} [onLayoutWidthRequest=null] — 嵌入外层框架时请求外层同步调整内容宽度 (contentWidth, meta) => void
 * @prop {boolean} [avatarOnlyCollapsed] — 受控纯头像收起（预览/外层框架用；undefined = 非受控，走 collapsible + ResizeObserver）
 * @prop {boolean} [loading=false] — 首屏/刷新 loading：保留标题与 tabs，列表区用与真实项 1:1 对齐的 Skeleton 原位占位
 * @prop {number} [loadingCount=8] — loading 时占位行/卡片数量
 * @prop {string} [className=''] — 根节点附加类名
 * @prop {object} [style] — 根节点内联样式（与默认 width 合并）
 */
function ConversationListDefaultVariant({
  variant,
  defaultVariant = 'default',
  onVariantChange = null,
  cardScenario = DEFAULT_CARD_SCENARIO,
  title = '会话列表',
  tabs = DEFAULT_TABS,
  activeTab,
  defaultActiveTab = 'all',
  onTabChange = null,
  sections,
  activeItemId,
  defaultActiveItemId = null,
  onItemClick = null,
  onSend = null,
  showActions = true,
  showLayoutToggle = true,
  resizable = true,
  collapsible = true,
  autoCollapseOnNarrow = true,
  onLayoutWidthRequest = null,
  avatarOnlyCollapsed,
  loading = false,
  loadingCount = 8,
  className = '',
  style,
}) {
  const rootRef = useRef(null);
  const dragStateRef = useRef(null);
  // 用户主动点"展开"后，短时间内忽略 ResizeObserver 的 auto-collapse-on-narrow，
  // 避免外层 sideWidth 还未异步同步到 ≥ 150px 之前 ResizeObserver 立刻把状态回滚到折叠态导致抖动。
  const ignoreAutoCollapseUntilRef = useRef(0);
  const sendSequenceRef = useRef(0);
  const [innerVariant, setInnerVariant] = useState(() => variant ?? defaultVariant);
  const [innerActiveTab, setInnerActiveTab] = useState(defaultActiveTab);
  const [cardItemOverrides, setCardItemOverrides] = useState({});
  const resolvedVariant = innerVariant ?? 'default';
  const isCardVariant = resolvedVariant === 'card';
  const resolvedCardScenario = cardScenario ?? DEFAULT_CARD_SCENARIO;
  const isTicketCardScenario = isCardVariant && resolvedCardScenario === 'ticket';
  const resolvedActiveTab = activeTab ?? innerActiveTab;
  const resolvedTabs = Array.isArray(tabs) && tabs.length > 0 ? tabs : DEFAULT_TABS;
  const resolvedActiveTabIndex = Math.max(0, resolvedTabs.findIndex((tab) => tab.id === resolvedActiveTab));
  const resolvedSections = useMemo(
    () => normalizeSections(sections, resolvedCardScenario, resolvedVariant),
    [resolvedCardScenario, resolvedVariant, sections]
  );
  const resolvedTabCounts = useMemo(
    () => Object.fromEntries(
      resolvedTabs.map((tab) => [tab.id, getTabItemCount(resolvedSections, tab.id)])
    ),
    [resolvedSections, resolvedTabs],
  );
  const filteredSections = useMemo(
    () => filterSectionsByTab(resolvedSections, resolvedActiveTab),
    [resolvedSections, resolvedActiveTab],
  );
  const visibleSections = useMemo(
    () => normalizeSectionsByActiveTab(filteredSections, resolvedActiveTab),
    [filteredSections, resolvedActiveTab],
  );
  const fallbackActiveItemId = useMemo(
    () => getFirstItemId(visibleSections) ?? getFirstItemId(resolvedSections),
    [visibleSections, resolvedSections],
  );
  const [innerActiveItemId, setInnerActiveItemId] = useState(() => defaultActiveItemId || null);
  const [expandedSectionIds, setExpandedSectionIds] = useState(() => getSectionIds(normalizeSections(sections)));
  const [resizedWidth, setResizedWidth] = useState(null);
  const [lastExpandedWidth, setLastExpandedWidth] = useState(DEFAULT_WIDTH);
  const [availableWidth, setAvailableWidth] = useState(DEFAULT_WIDTH);
  const [isAvatarOnly, setIsAvatarOnly] = useState(false);
  const [isResizeActive, setIsResizeActive] = useState(false);
  const resolvedActiveItemId = activeItemId ?? innerActiveItemId ?? fallbackActiveItemId;
  const avatarOnlyItems = useMemo(
    () => visibleSections.flatMap((section) => section.items || []),
    [visibleSections],
  );
  const currentListWidth = resizedWidth ?? availableWidth ?? lastExpandedWidth ?? DEFAULT_WIDTH;
  const isCardTwoColumn = isCardVariant && currentListWidth > CARD_TWO_COLUMN_THRESHOLD;
  const isCardThreeColumn = isCardVariant && currentListWidth > CARD_THREE_COLUMN_THRESHOLD;

  const handleTabClick = (tab) => {
    if (activeTab === undefined) setInnerActiveTab(tab.id);
    if (onTabChange) onTabChange(tab.id, tab);
  };

  const handleVariantToggle = useCallback(() => {
    const nextVariant = resolvedVariant === 'card' ? 'default' : 'card';
    setInnerVariant(nextVariant);
    if (!resizable && onLayoutWidthRequest) {
      const requestedWidth = nextVariant === 'card'
        ? Math.max(availableWidth, CARD_MIN_WIDTH)
        : Math.max(availableWidth, AVATAR_ONLY_THRESHOLD);
      onLayoutWidthRequest(requestedWidth, { reason: 'variant-change', variant: nextVariant });
    }
    if (onVariantChange) onVariantChange(nextVariant);
  }, [availableWidth, onLayoutWidthRequest, onVariantChange, resizable, resolvedVariant]);

  const updateResizeState = useCallback((nextRawWidth, nextMaxWidth = null) => {
    const maxWidth = nextMaxWidth ?? rootRef.current?.parentElement?.getBoundingClientRect?.().width ?? DEFAULT_WIDTH;
    const minWidth = isCardVariant ? CARD_MIN_WIDTH : AVATAR_ONLY_WIDTH;
    const clampedWidth = Math.max(minWidth, Math.min(nextRawWidth, maxWidth));

    if (isCardVariant) {
      setIsAvatarOnly(false);
      setResizedWidth(clampedWidth);
      setLastExpandedWidth(clampedWidth);
      return {
        clampedWidth,
        nextAvatarOnly: false,
      };
    }

    const nextAvatarOnly = clampedWidth < AVATAR_ONLY_THRESHOLD;

    setIsAvatarOnly(nextAvatarOnly);
    if (nextAvatarOnly) {
      setResizedWidth(AVATAR_ONLY_WIDTH);
    } else {
      setResizedWidth(clampedWidth);
      setLastExpandedWidth(clampedWidth);
    }

    return {
      clampedWidth,
      nextAvatarOnly,
    };
  }, [isCardVariant]);

  const handleResizePointerDown = useCallback((event) => {
    if (!resizable) return;
    event.preventDefault();
    setIsResizeActive(true);

    const rootWidth = rootRef.current?.getBoundingClientRect?.().width ?? lastExpandedWidth;
    const parentWidth = rootRef.current?.parentElement?.getBoundingClientRect?.().width ?? DEFAULT_WIDTH;

    dragStateRef.current = {
      startX: event.clientX,
      startWidth: rootWidth,
      maxWidth: parentWidth,
    };

    const previousUserSelect = document.body.style.userSelect;
    document.body.style.userSelect = 'none';

    const handlePointerMove = (moveEvent) => {
      if (!dragStateRef.current) return;
      const deltaX = moveEvent.clientX - dragStateRef.current.startX;
      const nextRawWidth = dragStateRef.current.startWidth + deltaX;
      updateResizeState(nextRawWidth, dragStateRef.current.maxWidth);
    };

    const stopDragging = (upEvent) => {
      const finalRawWidth = dragStateRef.current
        ? dragStateRef.current.startWidth + (upEvent.clientX - dragStateRef.current.startX)
        : rootWidth;

      updateResizeState(finalRawWidth, dragStateRef.current?.maxWidth ?? parentWidth);
      dragStateRef.current = null;
      setIsResizeActive(false);
      document.body.style.userSelect = previousUserSelect;
      window.removeEventListener('pointermove', handlePointerMove);
    };

    window.addEventListener('pointermove', handlePointerMove);
    window.addEventListener('pointerup', stopDragging, { once: true });
  }, [lastExpandedWidth, resizable, updateResizeState]);

  const handleResizeKeyDown = useCallback((event) => {
    if (!resizable) return;
    const currentWidth = isAvatarOnly
      ? AVATAR_ONLY_WIDTH
      : (resizedWidth ?? rootRef.current?.getBoundingClientRect?.().width ?? lastExpandedWidth);

    let nextWidth = currentWidth;
    if (event.key === 'ArrowLeft') nextWidth -= RESIZE_STEP;
    if (event.key === 'ArrowRight') nextWidth += RESIZE_STEP;
    if (event.key === 'Home') nextWidth = AVATAR_ONLY_WIDTH;
    if (event.key === 'End') {
      nextWidth = Math.max(lastExpandedWidth, AVATAR_ONLY_THRESHOLD);
    }
    if (nextWidth === currentWidth) return;

    event.preventDefault();
    updateResizeState(nextWidth);
  }, [isAvatarOnly, lastExpandedWidth, resizable, resizedWidth, updateResizeState]);

  const handleExpandFromAvatarOnly = useCallback(() => {
    const requestedWidth = Math.max(lastExpandedWidth, DEFAULT_WIDTH, AVATAR_ONLY_THRESHOLD);
    // 0) 在 800ms 窗口内忽略 auto-collapse-on-narrow，等外层 sideWidth 异步生效后再让观察器生效。
    ignoreAutoCollapseUntilRef.current = Date.now() + 800;
    // 1) 始终先向外申报：外层接了 onLayoutWidthRequest 即可联动整体板块宽度。
    onLayoutWidthRequest?.(requestedWidth, { reason: 'expand-from-avatar', variant: resolvedVariant });
    // 2) 直接同步内部展开态，绕开 updateResizeState 的 parentElement clamp——
    //    否则当外层容器尚处于 88px（折叠占位）瞬时会把 400 clamp 回 88，
    //    引发"展开失败 + 抖动"循环。
    setIsAvatarOnly(false);
    setResizedWidth(null);
    setLastExpandedWidth((current) => Math.max(current, requestedWidth));
  }, [lastExpandedWidth, onLayoutWidthRequest, resolvedVariant]);

  const handleCollapseToAvatarOnly = useCallback(() => {
    // 同上：始终冒泡 + 直接内部 setState，避免任何 clamp 路径回滚。
    onLayoutWidthRequest?.(AVATAR_ONLY_WIDTH, { reason: 'collapse-to-avatar', variant: resolvedVariant });
    setIsAvatarOnly(true);
    setResizedWidth(AVATAR_ONLY_WIDTH);
  }, [onLayoutWidthRequest, resolvedVariant]);

  // 仅在受控 prop 变化时同步，避免与内部「收起/展开」按钮打架（如预览平铺态传 false 时）。
  useEffect(() => {
    if (avatarOnlyCollapsed === undefined || isCardVariant) return;
    if (avatarOnlyCollapsed) {
      handleCollapseToAvatarOnly();
      return;
    }
    handleExpandFromAvatarOnly();
  }, [
    avatarOnlyCollapsed,
    handleCollapseToAvatarOnly,
    handleExpandFromAvatarOnly,
    isCardVariant,
  ]);

  const handleSectionToggle = (sectionId) => {
    setExpandedSectionIds((current) => (
      current.includes(sectionId)
        ? current.filter((id) => id !== sectionId)
        : [...current, sectionId]
    ));
  };

  useEffect(() => {
    setInnerVariant(variant ?? defaultVariant);
  }, [defaultVariant, variant]);

  useEffect(() => {
    setCardItemOverrides({});
  }, [sections]);

  useEffect(() => {
    if (avatarOnlyCollapsed !== undefined) return undefined;
    const rootNode = rootRef.current;
    if (!rootNode) return undefined;
    const observedNode = resizable ? rootNode : (rootNode.parentElement ?? rootNode);

    function syncAvatarOnlyByActualWidth() {
      const availableWidth = observedNode.getBoundingClientRect().width;
      if (!availableWidth) return;
      setAvailableWidth(availableWidth);

      if (isCardVariant) {
        setIsAvatarOnly(false);
        setResizedWidth(null);
        setLastExpandedWidth(availableWidth);
        return;
      }

      if (!autoCollapseOnNarrow || !collapsible) return;
      // 用户刚刚点了"展开"——在外层 sideWidth 异步同步前忽略 narrow 自动折叠，避免抖动回滚。
      if (Date.now() < ignoreAutoCollapseUntilRef.current) return;
      const nextAvatarOnly = availableWidth < AVATAR_ONLY_THRESHOLD;
      setIsAvatarOnly(nextAvatarOnly);
      if (!nextAvatarOnly) {
        setResizedWidth(null);
        setLastExpandedWidth((current) => Math.max(current, availableWidth));
      } else {
        setResizedWidth(AVATAR_ONLY_WIDTH);
        if (!resizable && onLayoutWidthRequest) {
          onLayoutWidthRequest(AVATAR_ONLY_WIDTH, { reason: 'auto-collapse-on-narrow', variant: resolvedVariant });
        }
      }
    }

    syncAvatarOnlyByActualWidth();
    const observer = typeof ResizeObserver !== 'undefined'
      ? new ResizeObserver(syncAvatarOnlyByActualWidth)
      : null;
    observer?.observe(observedNode);
    window.addEventListener('resize', syncAvatarOnlyByActualWidth);

    return () => {
      observer?.disconnect();
      window.removeEventListener('resize', syncAvatarOnlyByActualWidth);
    };
  }, [autoCollapseOnNarrow, avatarOnlyCollapsed, collapsible, isCardVariant, onLayoutWidthRequest, resizable, resolvedVariant]);

  useEffect(() => {
    const nextSectionIds = getSectionIds(resolvedSections);
    setExpandedSectionIds((current) => {
      const keptIds = current.filter((id) => nextSectionIds.includes(id));
      const missingIds = nextSectionIds.filter((id) => !keptIds.includes(id));
      return [...keptIds, ...missingIds];
    });
  }, [resolvedSections]);

  useEffect(() => {
    if (activeItemId !== undefined) return;
    if (!hasItem(resolvedSections, innerActiveItemId)) {
      setInnerActiveItemId(defaultActiveItemId || fallbackActiveItemId || null);
    }
  }, [activeItemId, defaultActiveItemId, fallbackActiveItemId, innerActiveItemId, resolvedSections]);

  useEffect(() => {
    if (activeItemId !== undefined) return;
    if (!hasItem(visibleSections, innerActiveItemId)) {
      setInnerActiveItemId(getFirstItemId(visibleSections) ?? fallbackActiveItemId ?? null);
    }
  }, [activeItemId, fallbackActiveItemId, innerActiveItemId, visibleSections]);

  const handleItemClick = (item) => {
    if (activeItemId === undefined) setInnerActiveItemId(item.id);
    if (onItemClick) onItemClick(item);
  };

  const handleCardSend = useCallback((card, sectionId) => {
    const draftText = typeof card?.draftText === 'string' ? card.draftText.trim() : '';
    if (!draftText) return;

    sendSequenceRef.current += 1;
    const nextItem = buildNextCardAfterSend(card, draftText, sendSequenceRef.current);

    setCardItemOverrides((current) => ({
      ...current,
      [card.id]: {
        messages: nextItem.messages,
        draftText: nextItem.draftText,
        status: nextItem.status,
      },
    }));

    if (activeItemId === undefined) setInnerActiveItemId(card.id);
    if (onSend) {
      onSend({
        item: card,
        draftText,
        nextItem,
        sectionId,
      });
    }
  }, [activeItemId, onSend]);

  const expandedWidth = resizedWidth ?? lastExpandedWidth ?? DEFAULT_WIDTH;
  const resolvedRootWidth = !isCardVariant && isAvatarOnly
    ? `${AVATAR_ONLY_WIDTH}px`
    : (style?.width ?? `${expandedWidth}px`);
  const rootStyle = {
    ...style,
    width: resolvedRootWidth,
    maxWidth: style?.maxWidth ?? '100%',
  };

  return (
    <section
      ref={rootRef}
      className={[
        ROOT,
        !isCardVariant && isAvatarOnly ? ROOT_COLLAPSED : ROOT_EXPANDED,
        className,
      ].filter(Boolean).join(' ')}
      style={rootStyle}
      aria-label={title}
      data-tfds-component="ConversationList"
      data-tfds-variant={resolvedVariant}
      aria-busy={loading || undefined}
    >
      {!isCardVariant && isAvatarOnly ? (
        <>
          <div className={AVATAR_ONLY_HEADER}>
            <Button
              type="button"
              variant="ghost-black"
              size="sm"
              icon={<Icon name="layout-right-stroked" size={16} />}
              iconOnly
              tooltip="展开会话列表"
              onClick={handleExpandFromAvatarOnly}
              aria-label="展开会话列表"
            />
          </div>
          <div className={AVATAR_ONLY_LIST}>
            {avatarOnlyItems.map((item) => (
              <ConversationAvatarItem
                key={item.id}
                item={item}
                active={item.id === resolvedActiveItemId}
                onClick={handleItemClick}
              />
            ))}
          </div>
        </>
      ) : (
        <>
          <header className={HEADER}>
            <div className={HEADER_MAIN}>
              {!isCardVariant && collapsible ? (
                <Button
                  type="button"
                  variant="ghost-black"
                  size="sm"
                  icon={<Icon name="layout-right-stroked" size={16} />}
                  iconOnly
                  tooltip="收起会话列表"
                  onClick={handleCollapseToAvatarOnly}
                  aria-label="收起会话列表"
                />
              ) : null}
              <h2 className={TITLE}>{title}</h2>
            </div>
            {showActions ? (
              <div className={ACTIONS}>
                {showLayoutToggle ? (
                  <Button
                    type="button"
                    variant="ghost-black"
                    size="sm"
                    icon={<Icon name={isCardVariant ? 'rows-01-stroked' : 'grid-01-stroked'} size={16} />}
                    iconOnly
                    tooltip={isCardVariant ? '切换为默认列表' : '切换为卡片列表'}
                    onClick={handleVariantToggle}
                    aria-label={isCardVariant ? '切换为默认列表' : '切换为卡片列表'}
                  />
                ) : null}
                <Button
                  type="button"
                  variant="ghost-black"
                  size="sm"
                  icon={<Icon name="search-lg-stroked" size={16} />}
                  iconOnly
                  tooltip="搜索会话"
                  aria-label="搜索会话"
                />
                <Button
                  type="button"
                  variant="ghost-black"
                  size="sm"
                  icon={<Icon name="filter-funnel-01-stroked" size={16} />}
                  iconOnly
                  tooltip="筛选会话"
                  aria-label="筛选会话"
                />
                <Button
                  type="button"
                  variant="ghost-black"
                  size="sm"
                  icon={<Icon name="file-05-stroked" size={16} />}
                  iconOnly
                  tooltip="查看工单文件"
                  aria-label="查看工单文件"
                />
              </div>
            ) : null}
          </header>

          <div className={TABS_WRAP}>
            <Tabs
              variant="segment"
              size="sm"
              items={resolvedTabs.map((tab) => ({ label: renderTabLabel(tab, resolvedTabCounts[tab.id]) }))}
              activeIndex={resolvedActiveTabIndex}
              onChange={(index) => {
                const nextTab = resolvedTabs[index];
                if (nextTab) handleTabClick(nextTab);
              }}
              className="max-w-full flex-wrap"
              aria-label="会话状态筛选"
            />
          </div>

          <div className={isCardVariant
            ? (
              isTicketCardScenario
                ? TICKET_CARD_LIST
                : [
                  CARD_LIST,
                  isCardThreeColumn ? CARD_LIST_THREE_COLUMN : '',
                  !isCardThreeColumn && isCardTwoColumn ? CARD_LIST_TWO_COLUMN : '',
                ].filter(Boolean).join(' ')
            )
            : LIST}
          >
            {loading ? (
              isCardVariant ? (
                isTicketCardScenario ? (
                  visibleSections.map((section, sectionIndex) => {
                    const sectionRowCount = getLoadingRowsPerSection(
                      loadingCount,
                      sectionIndex,
                      visibleSections.length,
                    );

                    return (
                      <section key={section.id} className={TICKET_CARD_SECTION} aria-hidden="true" aria-label={`${section.title} loading`}>
                        <ConversationListTicketSectionHeaderSkeleton />
                        <div className={[
                          TICKET_CARD_SECTION_CONTENT,
                          isCardThreeColumn ? CARD_LIST_THREE_COLUMN : '',
                          !isCardThreeColumn && isCardTwoColumn ? CARD_LIST_TWO_COLUMN : '',
                        ].filter(Boolean).join(' ')}>
                          {Array.from({ length: sectionRowCount }, (_, index) => (
                            <ConversationListTicketCardSkeleton key={`ticket-card-loading-${section.id}-${index}`} />
                          ))}
                        </div>
                      </section>
                    );
                  })
                ) : (
                  Array.from({ length: Math.max(1, loadingCount) }, (_, index) => (
                    <Skeleton
                      key={`conversation-list-card-loading-${index}`}
                      preset="conversation-list-card-im"
                    />
                  ))
                )
              ) : (
                visibleSections.map((section, sectionIndex) => {
                  const sectionRowCount = getLoadingRowsPerSection(
                    loadingCount,
                    sectionIndex,
                    visibleSections.length,
                  );

                  return (
                    <section key={section.id} className={SECTION} aria-hidden="true" aria-label={`${section.title} loading`}>
                      <ConversationListSectionHeaderSkeleton />
                      <div className={SECTION_CONTENT}>
                        {Array.from({ length: sectionRowCount }, (_, index) => (
                          <ConversationListItemSkeleton key={`conversation-list-row-loading-${section.id}-${index}`} />
                        ))}
                      </div>
                    </section>
                  );
                })
              )
            ) : isCardVariant ? (
              isTicketCardScenario ? (
                visibleSections.map((section) => (
                  <section key={section.id} className={TICKET_CARD_SECTION} aria-label={`${section.title}${getSectionItemCount(section)}`}>
                    <div className={TICKET_CARD_SECTION_HEADER}>
                      <span className={TICKET_CARD_SECTION_HEADER_TITLE}>
                        {TICKET_STATUS_LABELS[section.id] || section.title}
                      </span>
                      <span className={TICKET_CARD_SECTION_HEADER_COUNT}>
                        {getSectionItemCount(section)}
                      </span>
                    </div>
                    <div className={[
                      TICKET_CARD_SECTION_CONTENT,
                      isCardThreeColumn ? CARD_LIST_THREE_COLUMN : '',
                      !isCardThreeColumn && isCardTwoColumn ? CARD_LIST_TWO_COLUMN : '',
                    ].filter(Boolean).join(' ')}>
                      {(section.items || []).map((item) => (
                        <ConversationTicketCardItem
                          key={item.id}
                          item={item}
                          active={item.id === resolvedActiveItemId}
                          onClick={handleItemClick}
                        />
                      ))}
                    </div>
                  </section>
                ))
              ) : (
                visibleSections.flatMap((section) => (
                  (section.items || []).map((item) => {
                    const resolvedItem = applyCardItemOverride(item, cardItemOverrides[item.id]);
                    return (
                      <ConversationCardItem
                        key={item.id}
                        item={resolvedItem}
                        active={item.id === resolvedActiveItemId}
                        onClick={handleItemClick}
                        onSend={(card) => handleCardSend(card, section.id)}
                      />
                    );
                  })
                ))
              )
            ) : (
              visibleSections.map((section) => {
                const expanded = expandedSectionIds.includes(section.id);
                const sectionContentId = `conversation-list-section-${section.id}`;
                const sectionItemCount = getSectionItemCount(section);

                return (
                  <section key={section.id} className={SECTION} aria-label={`${section.title}${sectionItemCount}`}>
                    <button
                      type="button"
                      className={SECTION_HEADER}
                      aria-expanded={expanded}
                      aria-controls={sectionContentId}
                      onClick={() => handleSectionToggle(section.id)}
                      data-tfds-component="ConversationList.Section"
                    >
                      <span className={SECTION_TITLE}>
                        <span className="truncate">{section.title}</span>
                        <span>{sectionItemCount}</span>
                      </span>
                      <Icon
                        name="chevron-up-stroked"
                        size={16}
                        aria-hidden="true"
                        className={[SECTION_CARET, expanded ? '' : 'rotate-180'].filter(Boolean).join(' ')}
                      />
                    </button>
                    {expanded ? (
                      <div id={sectionContentId} className={SECTION_CONTENT}>
                        {(section.items || []).map((item) => (
                          <ConversationItem
                            key={item.id}
                            item={item}
                            active={item.id === resolvedActiveItemId}
                            onClick={handleItemClick}
                          />
                        ))}
                      </div>
                    ) : null}
                  </section>
                );
              })
            )}
          </div>
        </>
      )}

      {resizable && (isCardVariant || !isAvatarOnly) ? (
        <div
          className={RESIZE_HANDLE_CLASS}
          role="separator"
          aria-label="调整会话列表宽度"
          aria-orientation="vertical"
          aria-valuemin={isCardVariant ? CARD_MIN_WIDTH : AVATAR_ONLY_WIDTH}
          aria-valuenow={Math.round(isCardVariant ? currentListWidth : (isAvatarOnly ? AVATAR_ONLY_WIDTH : (resizedWidth ?? rootRef.current?.getBoundingClientRect?.().width ?? lastExpandedWidth)))}
          tabIndex={0}
          onPointerDown={handleResizePointerDown}
          onKeyDown={handleResizeKeyDown}
          onPointerEnter={() => setIsResizeActive(true)}
          onPointerLeave={() => {
            if (!dragStateRef.current) setIsResizeActive(false);
          }}
          onFocus={() => setIsResizeActive(true)}
          onBlur={() => {
            if (!dragStateRef.current) setIsResizeActive(false);
          }}
          data-tfds-component="ConversationList.ResizeHandle"
        >
          <span className={[RESIZE_HANDLE_BAR_CLASS, isResizeActive ? 'bg-brand-500' : 'bg-transparent'].join(' ')} />
        </div>
      ) : null}
    </section>
  );
}

export default function ConversationList({
  variant = 'default',
  ...props
}) {
  return <ConversationListDefaultVariant variant={variant} {...props} />;
}

export {
  DEFAULT_SECTIONS as CONVERSATION_LIST_SAMPLE_SECTIONS,
  DEFAULT_TICKET_SECTIONS as CONVERSATION_LIST_SAMPLE_TICKET_SECTIONS,
  DEFAULT_TABS as CONVERSATION_LIST_SAMPLE_TABS,
  buildFallbackDraftText as getConversationListEditableDraftText,
  resolveStatusTag as resolveConversationStatusTag,
  normalizeItemTags as normalizeConversationItemTags,
  STATUS_TAG_BY_TAB as CONVERSATION_STATUS_TAG_BY_TAB,
};
