/**
 * Skeleton — B 端骨架屏占位（内容结构预览 + 扫光动效）
 *
 * **何时用**：首屏/列表/卡片等内容异步加载、需要保留布局稳定性的占位。
 * **不用**：空白页 / 提交中 / 区块居中图形等待 → `<IconLoading />`；行内 pending / 执行中 → `<IconLoading size="sm|md" />`。
 *
 * **形状原则**：骨条必须按「槽位原位替换」对齐真实 UI 节点盒模型（行高、图标盒、Tag、Avatar、操作按钮），
 * 尺寸事实源见 `skeleton-slots.js` / `SKELETON_SLOT`；`size` 仅用于无 preset、无槽位表的自由单骨条拼装。
 *
 * @prop {'text'|'circle'|'block'|'rounded'} [variant='text'] — 基础骨条形态（preset 为空时生效）
 * @prop {'card'|'list'|'table-row'|'form'|'card-data'|'card-product'|'card-info'|'card-info2'|'card-info3'|'conversation-list-row'|'conversation-list-card-im'|'conversation-list-card-ticket'|'ai-suggestion-panel'} [preset] — 场景预设
 * @prop {object} [sceneOptions=null] — 场景参数：card-data 传 `{ hasDataIcon }`；card-product / card-info 传 `{ infoLayout }`
 * @prop {'sm'|'md'|'lg'} [size='md'] — 单骨条档位（仅 preset 为空时生效）
 * @prop {number} [count=3] — preset=list / conversation-list-row 时的行数
 * @prop {string} [width] — 自定义宽度（单骨条）
 * @prop {string} [height] — 自定义高度（block / rounded 单骨条）
 * @prop {boolean} [animated=true] — 是否启用扫光动效
 * @prop {typeof MOTION_SPEED_IDS[number]} [speed=MOTION_SPEED_BASELINE] — 循环速率档位（扫光一圈 ms，见 TOKEN_MOTION_SPEED.loop）
 * @prop {string} [className=''] — 附加类名
 */

import { getMotionSpeedCssVars, MOTION_SPEED_BASELINE, MOTION_SPEED_IDS } from '../motion-speed.js';
import {
  pickSkeletonShimmerStyle,
  resolveSkeletonShimmerSurfaceStyle,
  SKELETON_SHIMMER_LAYER,
} from '../skeleton-shimmer.js';
import {
  SKELETON_AI_BONE_FILL_STYLE,
  SKELETON_AI_SUGGESTION,
  SKELETON_CARD_PRESET_BY_TYPE,
  SKELETON_CONVERSATION_LIST,
  SKELETON_SCENE_BONES,
  SKELETON_SLOT,
  SKELETON_SLOT_GAP,
} from '../skeleton-slots.js';

export {
  SKELETON_AI_BONE_FILL_STYLE,
  SKELETON_AI_SUGGESTION,
  SKELETON_SCENE_BONES,
  SKELETON_SLOT,
  SKELETON_SLOT_GAP,
  SKELETON_CONVERSATION_LIST,
} from '../skeleton-slots.js';

const TEXT_HEIGHT = {
  sm: 'h-3',
  md: 'h-4',
  lg: 'h-5',
};

const CIRCLE_SIZE = {
  sm: 'size-6',
  md: 'size-8',
  lg: 'size-10',
};

const BLOCK_HEIGHT = {
  sm: 'h-12',
  md: 'h-16',
  lg: 'h-24',
};

const RADIUS_CLASS = {
  text: 'rounded-sm',
  circle: 'rounded-full',
  block: 'rounded-md',
  rounded: 'rounded-lg',
};

/** 平台预览：骨条填充 + 扫光分层（渐变在下、扫光在上） */
function resolveBoneSurfaceStyle(boneFillStyle, animated, shimmerSurface) {
  const shimmerLayer = shimmerSurface?.backgroundImage
    || (animated ? SKELETON_SHIMMER_LAYER : null);
  const shimmerSize = shimmerSurface?.backgroundSize || '240% 100%';

  if (!boneFillStyle || Object.keys(boneFillStyle).length === 0) {
    return shimmerSurface || undefined;
  }

  const { backgroundImage, backgroundColor } = boneFillStyle;

  if (backgroundImage && animated && shimmerLayer) {
    return {
      backgroundImage: `${shimmerLayer}, ${backgroundImage}`,
      backgroundSize: `${shimmerSize}, cover`,
      backgroundColor: backgroundColor || 'transparent',
    };
  }
  if (backgroundImage) {
    return { backgroundImage, backgroundColor: 'transparent' };
  }
  if (backgroundColor) {
    if (animated && shimmerLayer) {
      return {
        backgroundImage: shimmerLayer,
        backgroundSize: shimmerSize,
        backgroundColor,
      };
    }
    return { backgroundColor };
  }
  return shimmerSurface || undefined;
}

function splitSkeletonRootStyle(style) {
  if (!style) {
    return { rootStyle: undefined, boneFillStyle: undefined, shimmerStyle: undefined };
  }
  const shimmerStyle = pickSkeletonShimmerStyle(style);
  const {
    backgroundColor,
    backgroundImage,
    ...restStyle
  } = style;
  const boneFillStyle = {};
  if (backgroundImage) boneFillStyle.backgroundImage = backgroundImage;
  if (backgroundColor) boneFillStyle.backgroundColor = backgroundColor;
  const hasBoneFill = Object.keys(boneFillStyle).length > 0;
  const rootStyle = { ...restStyle, ...shimmerStyle };
  return {
    rootStyle: Object.keys(rootStyle).length > 0 ? rootStyle : undefined,
    boneFillStyle: hasBoneFill ? boneFillStyle : undefined,
    shimmerStyle: Object.keys(shimmerStyle).length > 0 ? shimmerStyle : undefined,
  };
}

function SkeletonBone({
  variant = 'text',
  size = 'md',
  animated = true,
  width,
  height,
  className = '',
  sceneSized = false,
  boneFillStyle,
  shimmerStyle,
  style,
  ...rest
}) {
  const sizeKey = TEXT_HEIGHT[size] ? size : 'md';
  const hasCustomFill = !!boneFillStyle;
  const shimmerSurface = resolveSkeletonShimmerSurfaceStyle(shimmerStyle, { animated });
  const hasCustomShimmer = Boolean(shimmerSurface);
  const shimmerClass = animated
    ? ((hasCustomFill || hasCustomShimmer) ? 'tfds-skeleton tfds-skeleton--custom-fill' : 'tfds-skeleton')
    : 'tfds-skeleton tfds-skeleton--static';
  const surfaceStyle = resolveBoneSurfaceStyle(boneFillStyle, animated, shimmerSurface);

  const dimensionClass = sceneSized
    ? ''
    : (() => {
        if (variant === 'circle') return CIRCLE_SIZE[sizeKey];
        if (variant === 'block') return [BLOCK_HEIGHT[sizeKey], width || 'w-full'].filter(Boolean).join(' ');
        if (variant === 'rounded') return [height || BLOCK_HEIGHT[sizeKey], width || 'w-full'].filter(Boolean).join(' ');
        return [TEXT_HEIGHT[sizeKey], width || 'w-full'].filter(Boolean).join(' ');
      })();

  return (
    <span
      data-tfds-component="Skeleton"
      data-tfds-variant={variant}
      aria-hidden="true"
      style={{
        ...(surfaceStyle || {}),
        ...(style || {}),
      }}
      className={[
        shimmerClass,
        'block shrink-0',
        (hasCustomFill || hasCustomShimmer) ? '' : 'bg-[var(--color-fill)]',
        RADIUS_CLASS[variant] || RADIUS_CLASS.text,
        dimensionClass,
        !sceneSized && height && variant !== 'text' ? height : '',
        className,
      ].filter(Boolean).join(' ')}
      {...rest}
    />
  );
}

function useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle }) {
  return { animated, sceneSized: true, boneFillStyle, shimmerStyle };
}

function SkeletonCardData({ hasDataIcon = false, animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const renderBone = (props) => <SkeletonBone {...boneProps} {...props} />;

  const copyBlock = (
    <div className={`flex w-full flex-col items-start ${SKELETON_SLOT_GAP.copy}`}>
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.cardTitle} w-full` })}
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.lineClamp2CardCopy} w-full` })}
    </div>
  );

  const statsBlock = (
    <div className={`flex flex-wrap items-center ${SKELETON_SLOT_GAP.stats}`}>
      {[SKELETON_SLOT.statValue, SKELETON_SLOT.statValue, SKELETON_SLOT.statValueWide].map((statClass, index) => (
        <span key={index} className="inline-flex items-center gap-2 text-xs font-normal leading-4">
          {renderBone({ variant: 'circle', className: SKELETON_SLOT.icon14 })}
          {renderBone({ variant: 'text', className: statClass })}
        </span>
      ))}
    </div>
  );

  const footerBlock = (
    <div className="flex w-full items-center justify-between gap-4">
      <div className="flex flex-wrap items-center gap-2">
        {renderBone({ variant: 'text', className: SKELETON_SLOT.tagLMid })}
        {renderBone({ variant: 'text', className: SKELETON_SLOT.tagLLong })}
      </div>
      {renderBone({ variant: 'circle', className: SKELETON_SLOT.actionCircle })}
    </div>
  );

  if (hasDataIcon) {
    return (
      <div className={[
        `flex w-full flex-1 flex-col justify-between ${SKELETON_SLOT_GAP.cardMain}`,
        className,
      ].filter(Boolean).join(' ')}>
        <div className={`flex w-full items-start ${SKELETON_SLOT_GAP.dataIconRow}`}>
          <div className={`flex min-w-0 flex-1 flex-col items-start ${SKELETON_SLOT_GAP.block}`}>
            {copyBlock}
            {statsBlock}
          </div>
          {renderBone({ variant: 'rounded', className: `${SKELETON_SLOT.dataIconBox48} shrink-0` })}
        </div>
        {footerBlock}
      </div>
    );
  }

  return (
    <div className={[
      `flex w-full flex-1 flex-col justify-between ${SKELETON_SLOT_GAP.cardMain}`,
      className,
    ].filter(Boolean).join(' ')}>
      <div className={`flex w-full flex-col items-start ${SKELETON_SLOT_GAP.block}`}>
        {copyBlock}
        {statsBlock}
      </div>
      {footerBlock}
    </div>
  );
}

function SkeletonCardProduct({ infoLayout = 'default', animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const renderBone = (props) => <SkeletonBone {...boneProps} {...props} />;

  const titleRowGap = infoLayout === 'icon-right' ? 'gap-2' : 'gap-3';
  const copyNode = (
    <div className={`flex h-14 min-w-0 flex-1 flex-col justify-center ${SKELETON_SLOT_GAP.copy}`}>
      <div className={`flex min-w-0 items-center ${titleRowGap}`}>
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.cardTitle} min-w-0 flex-1` })}
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.tagLMid} shrink-0` })}
      </div>
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.cardCopy} w-full` })}
    </div>
  );

  const imageNode = renderBone({ variant: 'rounded', className: `${SKELETON_SLOT.productImage56} shrink-0` });

  return (
    <div className={[
      infoLayout === 'icon-right'
        ? `flex w-full flex-row-reverse items-center ${SKELETON_SLOT_GAP.productRow}`
        : `flex w-full items-center ${SKELETON_SLOT_GAP.productRow}`,
      className,
    ].filter(Boolean).join(' ')}>
      {imageNode}
      {copyNode}
    </div>
  );
}

function SkeletonCardInfo({ infoLayout = 'icon-right', animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const renderBone = (props) => <SkeletonBone {...boneProps} {...props} />;

  const iconNode = renderBone({ variant: 'rounded', className: `${SKELETON_SLOT.iconBox48} shrink-0` });
  const titleRowGap = infoLayout === 'icon-right' ? 'gap-2' : 'gap-2';
  const copyNode = (
    <div className={[
      'flex min-w-0 flex-col',
      infoLayout === 'icon-right' ? 'w-full' : 'flex-1',
      SKELETON_SLOT_GAP.copy,
    ].join(' ')}>
      <div className={`flex min-w-0 flex-wrap items-center ${titleRowGap}`}>
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.cardTitle} min-w-0 flex-initial` })}
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.tagLWide} shrink-0 self-center` })}
      </div>
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.lineClamp2Leading5} w-full min-w-0` })}
    </div>
  );
  const footerNode = (
    <div className="flex w-full min-w-0 flex-row flex-wrap items-center gap-x-5 gap-y-2">
      <span className="inline-flex min-h-4 items-center gap-2">
        {renderBone({ variant: 'circle', className: SKELETON_SLOT.avatarXxs })}
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.textXsLeading4} w-16` })}
      </span>
      <div className="flex min-w-0 flex-1 flex-wrap items-center justify-end gap-x-5 gap-y-2">
        {['w-12', 'w-10', 'w-12'].map((widthClass, index) => (
          <span key={index} className="inline-flex h-4 items-center gap-2">
            {renderBone({ variant: 'circle', className: SKELETON_SLOT.icon14 })}
            {renderBone({ variant: 'text', className: `${SKELETON_SLOT.textXsLeading4} ${widthClass}` })}
          </span>
        ))}
      </div>
    </div>
  );

  if (infoLayout === 'icon-right') {
    return (
      <div className={[`flex w-full flex-col ${SKELETON_SLOT_GAP.infoBody}`, className].filter(Boolean).join(' ')}>
        <div className={`grid w-full min-w-0 grid-cols-[minmax(0,1fr)_3rem] items-start gap-x-6 gap-y-2`}>
          <div className="col-start-1 row-start-1">{copyNode}</div>
          <div className="col-start-2 row-start-1 justify-self-end">{iconNode}</div>
        </div>
        {footerNode}
      </div>
    );
  }

  return (
    <div className={[`flex w-full flex-col ${SKELETON_SLOT_GAP.infoBody}`, className].filter(Boolean).join(' ')}>
      <div className={`flex w-full items-start ${SKELETON_SLOT_GAP.infoIcon}`}>
        {iconNode}
        {copyNode}
      </div>
      {footerNode}
    </div>
  );
}

function SkeletonCardInfo2({ animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const renderBone = (props) => <SkeletonBone {...boneProps} {...props} />;

  return (
    <div className={[
      `relative z-10 flex min-h-0 w-full flex-1 flex-col justify-between ${SKELETON_SLOT_GAP.infoBody}`,
      className,
    ].filter(Boolean).join(' ')}>
      <div className="flex items-start gap-4">
        {renderBone({ variant: 'rounded', className: SKELETON_SLOT.iconBox48 })}
      </div>
      <div className={`flex min-w-0 flex-col ${SKELETON_SLOT_GAP.copy}`}>
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.cardTitle} w-2/3` })}
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.lineClamp2CardCopy} w-full` })}
      </div>
      <div className="flex items-center justify-between gap-4">
        {renderBone({ variant: 'text', className: SKELETON_SLOT.tagLWide })}
        {renderBone({ variant: 'circle', className: SKELETON_SLOT.actionCircle })}
      </div>
    </div>
  );
}

function SkeletonCardInfo3({ animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const renderBone = (props) => <SkeletonBone {...boneProps} {...props} />;

  const metaItem = (textWidth) => (
    <span className="inline-flex min-w-0 items-center gap-1">
      {renderBone({ variant: 'circle', className: SKELETON_SLOT.icon14 })}
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.textXsLeading4} ${textWidth}` })}
    </span>
  );

  return (
    <div className={[`flex w-full flex-col ${SKELETON_SLOT_GAP.copy}`, className].filter(Boolean).join(' ')}>
      <div className="flex items-start justify-between gap-2">
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.lineClamp2Leading6} min-w-0 flex-1` })}
        {renderBone({ variant: 'text', className: `${SKELETON_SLOT.tagStatus} shrink-0` })}
      </div>
      {renderBone({ variant: 'text', className: `${SKELETON_SLOT.lineClamp2Leading22} w-full` })}
      <div className="flex min-w-0 flex-wrap items-center gap-3">
        {metaItem('w-10')}
        {metaItem('w-28')}
      </div>
    </div>
  );
}

function SkeletonCard({ animated, className, boneFillStyle, shimmerStyle }) {
  const [cover, title, subtitle] = SKELETON_SCENE_BONES.card.bones;
  return (
    <div className={['flex w-full max-w-[var(--size-card-width,400px)] flex-col gap-4', className].filter(Boolean).join(' ')}>
      <SkeletonBone variant={cover.variant} animated={animated} sceneSized boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className={cover.className} />
      <SkeletonBone variant={title.variant} animated={animated} sceneSized boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className={title.className} />
      <SkeletonBone variant={subtitle.variant} animated={animated} sceneSized boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className={subtitle.className} />
    </div>
  );
}

function SkeletonConversationListRow({ animated, count, className, boneFillStyle, shimmerStyle }) {
  const rows = Math.max(1, count ?? 3);
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={[shell.listWrap, className].filter(Boolean).join(' ')} aria-hidden="true">
      {Array.from({ length: rows }, (_, index) => (
        <ConversationListItemSkeleton
          key={index}
          animated={animated}
          boneFillStyle={boneFillStyle}
          shimmerStyle={shimmerStyle}
        />
      ))}
    </div>
  );
}

/** 单条默认列表项骨架 — 与 ConversationList.Item DOM 1:1 */
export function ConversationListItemSkeleton({
  animated = true,
  className = '',
  boneFillStyle,
  shimmerStyle,
}) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={[shell.item, className].filter(Boolean).join(' ')} data-tfds-component="ConversationList.ItemSkeleton">
      <SkeletonBone variant="circle" {...boneProps} className={SKELETON_SLOT.avatarS} />
      <div className={shell.itemBody}>
        <div className={shell.titleRow}>
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationTitle} />
          <div className={shell.tags}>
            <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMMid} />
            <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMSm} />
          </div>
        </div>
        <div className={shell.meta}>
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationUser} />
          <SkeletonBone variant="circle" {...boneProps} className={SKELETON_SLOT.icon12} />
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationOrder} />
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationTime} />
        </div>
      </div>
    </div>
  );
}

/** 默认列表分组标题骨架 — 与 ConversationList.Section header h-5 1:1 */
export function ConversationListSectionHeaderSkeleton({
  animated = true,
  boneFillStyle,
  shimmerStyle,
}) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={shell.sectionHeader} aria-hidden="true" data-tfds-component="ConversationList.SectionSkeleton">
      <span className={shell.sectionTitle}>
        <SkeletonBone variant="text" {...boneProps} className={`${SKELETON_SLOT.textXsLeading4} w-14`} />
        <SkeletonBone variant="text" {...boneProps} className={`${SKELETON_SLOT.textXsLeading4} w-3`} />
      </span>
      <SkeletonBone variant="rounded" {...boneProps} className="size-4 shrink-0 rounded-sm" />
    </div>
  );
}

function SkeletonConversationListCardIm({ animated, className, boneFillStyle, shimmerStyle }) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={[shell.cardShell, className].filter(Boolean).join(' ')} aria-hidden="true" data-tfds-component="ConversationList.CardItemSkeleton">
      <div className={shell.cardHeader}>
        <div className={shell.cardHeaderMain}>
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.cardTitleLeading5} />
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMMid} />
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMSm} />
        </div>
        <SkeletonBone variant="circle" {...boneProps} className={SKELETON_SLOT.avatarS} />
      </div>
      <div className={shell.cardMessage}>
        <div className={shell.cardMessageRowUser}>
          <SkeletonBone variant="rounded" {...boneProps} className="h-8 w-[72%] max-w-[calc(100%-24px)] rounded-lg rounded-tl-none" />
        </div>
        <div className={shell.cardMessageRowOutgoing}>
          <SkeletonBone variant="rounded" {...boneProps} className="h-8 w-[62%] max-w-[calc(100%-24px)] rounded-lg rounded-tr-none" />
        </div>
        <div className={shell.cardMessageRowUser}>
          <SkeletonBone variant="rounded" {...boneProps} className="h-8 w-[48%] max-w-[calc(100%-24px)] rounded-lg rounded-tl-none" />
        </div>
      </div>
      <div className={shell.cardFooter}>
        <SkeletonBone variant="text" {...boneProps} className={`${SKELETON_SLOT.textXsLeading4} w-2/3`} />
      </div>
    </div>
  );
}

function SkeletonConversationListCardTicket({ animated, className, boneFillStyle, shimmerStyle }) {
  return (
    <ConversationListTicketCardSkeleton
      animated={animated}
      className={className}
      boneFillStyle={boneFillStyle}
      shimmerStyle={shimmerStyle}
    />
  );
}

/** 工单卡片列表项骨架 — 与 ConversationList.TicketCardItem DOM 1:1 */
export function ConversationListTicketCardSkeleton({
  animated = true,
  className = '',
  boneFillStyle,
  shimmerStyle,
}) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={[shell.ticketShell, className].filter(Boolean).join(' ')} aria-hidden="true" data-tfds-component="ConversationList.TicketCardItemSkeleton">
      <div className={shell.ticketHead}>
        <SkeletonBone variant="circle" {...boneProps} className={SKELETON_SLOT.avatarS} />
        <div className={shell.ticketBody}>
          <div className={shell.ticketTitleRow}>
            <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationTitle} />
            <SkeletonBone variant="circle" {...boneProps} className="size-2 shrink-0 rounded-full" />
            <div className={shell.ticketTitleTags}>
              <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMMid} />
              <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMSm} />
            </div>
          </div>
        </div>
      </div>
      <div className={shell.ticketProgress}>
        <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.ticketProgressClamp2} />
      </div>
      <div className={shell.ticketMetaTags}>
        <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMSm} />
        <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.tagMMid} />
      </div>
      <div className={shell.ticketMetaRow}>
        <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.ticketUser} />
        <span className={shell.orderWrap}>
          <SkeletonBone variant="circle" {...boneProps} className={SKELETON_SLOT.icon12} />
          <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationOrder} />
        </span>
        <SkeletonBone variant="text" {...boneProps} className={SKELETON_SLOT.conversationTime} />
      </div>
    </div>
  );
}

/** 工单卡片分组标题骨架 — 与 TICKET_CARD_SECTION_HEADER 1:1 */
export function ConversationListTicketSectionHeaderSkeleton({
  animated = true,
  boneFillStyle,
  shimmerStyle,
}) {
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });
  const shell = SKELETON_CONVERSATION_LIST;

  return (
    <div className={shell.ticketSectionHeader} aria-hidden="true" data-tfds-component="ConversationList.TicketSectionSkeleton">
      <SkeletonBone variant="text" {...boneProps} className={`${SKELETON_SLOT.textXsLeading4} w-12`} />
      <SkeletonBone variant="text" {...boneProps} className={`${SKELETON_SLOT.textXsLeading4} w-3`} />
    </div>
  );
}

/** @deprecated 使用 SkeletonConversationListRow（布局已对齐 ConversationList.Item） */
function SkeletonList({ animated, count, className, boneFillStyle, shimmerStyle }) {
  return (
    <SkeletonConversationListRow
      animated={animated}
      count={count}
      className={className}
      boneFillStyle={boneFillStyle}
      shimmerStyle={shimmerStyle}
    />
  );
}

function SkeletonTableRow({ animated, className, boneFillStyle, shimmerStyle }) {
  const bones = SKELETON_SCENE_BONES['table-row'].bones;
  const boneProps = useSkeletonBoneProps({ animated, boneFillStyle, shimmerStyle });

  return (
    <div className={['flex w-full items-center gap-4', className].filter(Boolean).join(' ')}>
      {bones.map((bone, index) => (
        <SkeletonBone
          key={`${bone.ref}-${index}`}
          variant={bone.variant}
          {...boneProps}
          className={bone.className}
        />
      ))}
    </div>
  );
}

/** AI 推荐内容面板 loading — Input / Select / TextArea 下方推荐区原位占位 */
export function AiSuggestionPanelSkeleton({
  count = 1,
  animated = true,
  speed = MOTION_SPEED_BASELINE,
  className = '',
  style,
  boneFillStyle,
  shimmerStyle,
}) {
  const rows = Math.max(1, Math.min(5, count));
  const speedStyle = getMotionSpeedCssVars(speed);
  const { rootStyle: previewRootStyle, boneFillStyle: styleBoneFill, shimmerStyle: styleShimmer } = splitSkeletonRootStyle(style);
  const resolvedBoneFill = boneFillStyle || styleBoneFill || SKELETON_AI_BONE_FILL_STYLE;
  const resolvedShimmer = shimmerStyle || styleShimmer;
  const boneProps = useSkeletonBoneProps({
    animated,
    boneFillStyle: resolvedBoneFill,
    shimmerStyle: resolvedShimmer,
  });
  const rootStyle = previewRootStyle ? { ...speedStyle, ...previewRootStyle } : speedStyle;

  return (
    <div
      className={[SKELETON_AI_SUGGESTION.listWrap, className].filter(Boolean).join(' ')}
      style={{ ...SKELETON_AI_SUGGESTION.listSurface, ...rootStyle }}
      data-tfds-component="Skeleton"
      data-tfds-preset="ai-suggestion-panel"
      aria-busy="true"
      aria-hidden="true"
    >
      {Array.from({ length: rows }, (_, index) => (
        <div key={index} className={SKELETON_AI_SUGGESTION.itemWrap}>
          <SkeletonBone
            variant="text"
            {...boneProps}
            className={[
              SKELETON_AI_SUGGESTION.lineBone,
              SKELETON_AI_SUGGESTION.lineWidthByIndex[index % SKELETON_AI_SUGGESTION.lineWidthByIndex.length],
            ].join(' ')}
          />
        </div>
      ))}
    </div>
  );
}

function SkeletonAiSuggestionPanel(props) {
  return <AiSuggestionPanelSkeleton {...props} />;
}

function SkeletonForm({ size, animated, className, boneFillStyle, shimmerStyle }) {
  return (
    <div className={['flex w-full max-w-[360px] flex-col gap-4', className].filter(Boolean).join(' ')}>
      <div className="flex flex-col gap-2">
        <SkeletonBone variant="text" size="sm" animated={animated} boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className="w-24" />
        <SkeletonBone variant="block" size={size} animated={animated} boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className="h-9 w-full" />
      </div>
      <div className="flex flex-col gap-2">
        <SkeletonBone variant="text" size="sm" animated={animated} boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className="w-20" />
        <SkeletonBone variant="block" size={size} animated={animated} boneFillStyle={boneFillStyle} shimmerStyle={shimmerStyle} className="h-9 w-full" />
      </div>
    </div>
  );
}

const PRESET_RENDERERS = {
  card: SkeletonCard,
  list: SkeletonList,
  'conversation-list-row': SkeletonConversationListRow,
  'conversation-list-card-im': SkeletonConversationListCardIm,
  'conversation-list-card-ticket': SkeletonConversationListCardTicket,
  'table-row': SkeletonTableRow,
  form: SkeletonForm,
  'card-data': SkeletonCardData,
  'card-product': SkeletonCardProduct,
  'card-info': SkeletonCardInfo,
  'card-info2': SkeletonCardInfo2,
  'card-info3': SkeletonCardInfo3,
  'ai-suggestion-panel': SkeletonAiSuggestionPanel,
};

function resolveCardPresetSceneProps(preset, sceneOptions = {}) {
  if (preset === 'card-data') {
    return { hasDataIcon: sceneOptions.hasDataIcon === true };
  }
  if (preset === 'card-product' || preset === 'card-info') {
    return { infoLayout: sceneOptions.infoLayout === 'default' ? 'default' : 'icon-right' };
  }
  return {};
}

/** Card loading 内容区 — 与 Card.jsx 各 type 槽位 1:1，由 Card `loading` 调用 */
export function CardLoadingSkeleton({
  type = 'data',
  infoLayout = 'icon-right',
  hasDataIcon = false,
  animated = true,
  speed = MOTION_SPEED_BASELINE,
  className = '',
  style,
}) {
  const resolvedType = SKELETON_CARD_PRESET_BY_TYPE[type] ? type : 'data';
  const preset = SKELETON_CARD_PRESET_BY_TYPE[resolvedType] || 'card-data';
  const PresetView = PRESET_RENDERERS[preset];
  const speedStyle = getMotionSpeedCssVars(speed);
  const { rootStyle: previewRootStyle, boneFillStyle, shimmerStyle } = splitSkeletonRootStyle(style);
  const rootStyle = previewRootStyle ? { ...speedStyle, ...previewRootStyle } : speedStyle;
  const sceneProps = {
    animated,
    className: undefined,
    boneFillStyle,
    shimmerStyle,
    ...resolveCardPresetSceneProps(preset, { infoLayout, hasDataIcon }),
  };

  return (
    <div
      data-tfds-component="Skeleton"
      data-tfds-preset={preset}
      className={['flex min-h-0 w-full flex-1 flex-col', className].filter(Boolean).join(' ') || undefined}
      style={rootStyle}
      aria-hidden="true"
    >
      <PresetView {...sceneProps} />
    </div>
  );
}

export default function Skeleton({
  variant = 'text',
  preset = null,
  size = 'md',
  count = 3,
  width,
  height,
  animated = true,
  speed = MOTION_SPEED_BASELINE,
  sceneOptions = null,
  className = '',
  style,
  ...rest
}) {
  const resolvedPreset = preset && PRESET_RENDERERS[preset] ? preset : null;
  const speedStyle = getMotionSpeedCssVars(speed);
  const { rootStyle: previewRootStyle, boneFillStyle, shimmerStyle } = splitSkeletonRootStyle(style);
  const rootStyle = previewRootStyle ? { ...speedStyle, ...previewRootStyle } : speedStyle;

  if (resolvedPreset) {
    const PresetView = PRESET_RENDERERS[resolvedPreset];
    const presetProps = {
      animated,
      className: undefined,
      boneFillStyle,
      shimmerStyle,
      ...resolveCardPresetSceneProps(resolvedPreset, sceneOptions || {}),
    };
    if (resolvedPreset === 'list' || resolvedPreset === 'conversation-list-row' || resolvedPreset === 'ai-suggestion-panel') {
      presetProps.count = count;
    }
    if (resolvedPreset === 'ai-suggestion-panel') presetProps.speed = speed;
    if (resolvedPreset === 'form') presetProps.size = size;

    return (
      <div
        data-tfds-component="Skeleton"
        data-tfds-preset={resolvedPreset}
        className={['w-full', className].filter(Boolean).join(' ') || undefined}
        style={rootStyle}
        {...rest}
      >
        <PresetView {...presetProps} />
      </div>
    );
  }

  const resolvedVariant = variant || 'text';

  return (
    <SkeletonBone
      variant={resolvedVariant}
      size={size}
      animated={animated}
      width={width}
      height={height}
      className={className}
      boneFillStyle={boneFillStyle}
      shimmerStyle={shimmerStyle}
      style={rootStyle}
      {...rest}
    />
  );
}
