import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Avatar from '../components/Avatar';
import Button from '../components/Button';
import ChatBubble from '../components/ChatBubble';
import ChatInput from '../components/ChatInput';
import Dropdown from '../components/Dropdown';
import Icon from '../components/Icon';
import Tag from '../components/Tag';
import Tooltip from '../components/Tooltip';
import { getTeamMemberByName } from '../teamMembers';

/**
 * IMConversationPattern — IM 对话片段（可交互版）
 *
 * 一个白卡里完整呈现"用户进线 → 机器人接待 → 转人工 → 客服跟进"的一组对话，
 * 用于演示 IM / 即时通讯场景里三种角色的 ChatBubble 组合用法。顶部默认展示当前线程信息元素，
 * 底部默认搭配组合输入框；输入框样式按场景判断：常规 IM 对话默认用 im-basic，若是 AI 协同型会话可切到 AI ChatInput。
 *
 * 角色 → 气泡映射（铁律）：
 *   用户   → ChatBubble variant="incoming"  avatarType="image" incomingTone="grey"
 *   机器人 → ChatBubble variant="outgoing"  avatarType="ai" outgoingTone="ai"
 *   人工   → ChatBubble variant="outgoing"  avatarType="image" outgoingTone="default" receipt="read"
 *   系统提示（接入 / 转人工）→ 居中小字，不是气泡
 */

/** IM 对话区与宿主容器四周统一边距（与 AI 对话页 CHAT_CONVERSATION_PAGE_PADDING 对齐） */
export const IM_CONVERSATION_PAGE_PADDING = 16;
/** 底部输入区：抬高层级，保证常驻吸底且不被消息滚动层遮挡 */
const IM_COMPOSER_FOOTER = 'relative z-10 w-full shrink-0';
/** 消息列与输入框之间的安全间距 */
export const IM_MESSAGE_BOTTOM_GAP = IM_CONVERSATION_PAGE_PADDING;
/** 线程顶栏：sticky 毛玻璃，消息上滚时可微弱透视 */
const IM_THREAD_HEADER_CLASS = [
  'sticky top-0 z-20 flex min-h-[64px] w-full shrink-0 items-center justify-between gap-4',
  'py-3',
  'border-b border-border-default/35',
].join(' ');
const IM_THREAD_HEADER_STYLE = {
  background: 'color-mix(in srgb, var(--color-white) 80%, transparent)',
  WebkitBackdropFilter: 'blur(20px) saturate(1.05)',
  backdropFilter: 'blur(20px) saturate(1.05)',
  boxShadow: '0 1px 0 0 color-mix(in srgb, var(--color-white) 82%, transparent)',
};
/** 不同角色 / 系统提示之间的消息组间距（等同 gap-5） */
const IM_MESSAGE_GROUP_GAP = 20;
/** 同侧连续消息组间距，与 ChatBubble 组内 `--spacing-1` / 4px 对齐 */
const IM_MESSAGE_CONSECUTIVE_GAP = 4;
const IM_MESSAGE_LIST_CLASS = 'flex min-w-0 flex-col';

const SCRIPT_DATE = '2026-04-16';
function ts(hhmm, ss = '00') {
  return `${SCRIPT_DATE} ${hhmm}:${ss}`;
}

function formatCurrentTimestamp() {
  const now = new Date();
  const hh = String(now.getHours()).padStart(2, '0');
  const mm = String(now.getMinutes()).padStart(2, '0');
  const ss = String(now.getSeconds()).padStart(2, '0');
  return `${SCRIPT_DATE} ${hh}:${mm}:${ss}`;
}

const SCRIPT = [
  { id: 's1', kind: 'system', text: '已接入AI智能客服', time: ts('14:01', '00') },

  { id: 'u1', kind: 'user', text: '我买了海底捞西单店的 2 人餐，到店以后店员说券码暂时核销不了，能帮我看下吗', time: ts('14:02', '12') },
  { id: 'b1', kind: 'bot', text: '您好，我是抖音生活服务助手，正在为您查询团购券状态…', time: ts('14:02', '25') },
  { id: 'b2', kind: 'bot', text: '请问可以提供下券码或订单号吗？支持直接复制粘贴。', time: ts('14:02', '38') },
  { id: 'b3', kind: 'bot', text: '如果不方便复制，也可以发券码截图，我会一起核对适用门店、使用时段和套餐权益。', time: ts('14:02', '52') },

  // 用户连续两条：订单号 + 券码尾号
  { id: 'u2', kind: 'user', text: 'LS20260423-HDL998877', time: ts('14:03', '04') },
  { id: 'u3', kind: 'user', text: '券码尾号 8877', time: ts('14:03', '16') },

  // AI连续两条：查券结果 + 规则解释
  { id: 'b4', kind: 'bot', text: '已查到您的订单 LS20260423-HDL998877，套餐为“海底捞火锅 2 人餐”，适用门店包含西单大悦城店。', time: ts('14:03', '28') },
  { id: 'b5', kind: 'bot', text: '当前券码状态显示“待核销”，使用时段仍有效。我先为您核对门店收银端同步状态。', time: ts('14:03', '44') },

  // 到店核销异常（AI多轮）
  { id: 'u4', kind: 'user', text: '我现在已经在店里等位了，如果一直不能核销是不是只能退款？', time: ts('14:04', '03') },
  { id: 'b6', kind: 'bot', text: '先别着急，我会优先帮您确认门店核销链路，避免影响您到店用餐。', time: ts('14:04', '18') },
  { id: 'b7', kind: 'bot', text: '如果确认为门店端同步延迟，可由商家手动核验订单；如无法履约，再为您进入退款或补偿流程。', time: ts('14:04', '36') },

  // 补偿诉求（用户单条 + AI单条）
  { id: 'u5', kind: 'user', text: '我朋友都到了，等太久体验很差，能不能给个补偿？', time: ts('14:04', '54') },
  { id: 'b8', kind: 'bot', text: '理解您的感受。若确认是核销异常导致等待，我们会协助门店给出等位补偿或套餐权益补救方案。', time: ts('14:05', '08') },

  { id: 'u6', kind: 'user', text: '那你先帮我联系门店吧，不行就转人工处理', time: ts('14:05', '26') },
  { id: 'b9', kind: 'bot', text: '好的，我已为您发起门店核销协同，预计 5 分钟内反馈。', time: ts('14:05', '42') },
  { id: 'b10', kind: 'bot', text: '如门店端仍无法确认，我会继续为您转接人工客服处理退款和补偿方案。', time: ts('14:05', '58') },

  { id: 'u7', kind: 'user', text: '转人工', time: ts('14:06', '12') },
  { id: 'b11', kind: 'bot', text: '好的，正在为您转接人工客服，请稍候…', time: ts('14:06', '20') },

  { id: 's2', kind: 'system', text: '已接入人工客服', time: ts('14:06', '32') },

  // 人工连续两条：说明 + 方案
  { id: 'a1', kind: 'agent', text: '您好，我是人工客服小语，已看到您的海底捞团购订单。门店反馈当前收银端券码同步延迟，正在手动核验。', time: ts('14:06', '48') },
  { id: 'a2', kind: 'agent', text: '我已备注您正在到店等位，并同步门店优先处理；若核销仍失败，会为您申请等位补偿或原路退款。', time: ts('14:07', '02') },

  { id: 'u8', kind: 'user', text: '好的，麻烦快一点，我这边还在等叫号', time: ts('14:07', '18') },
  { id: 'a3', kind: 'agent', text: '没问题～我会持续跟进西单店反馈。若 5 分钟内未解决，我会直接帮您升级商家值班人员处理。', time: ts('14:07', '36') },
  { id: 'u9', kind: 'user', text: '明白了，谢谢', time: ts('14:08', '04') },
  { id: 'a4', kind: 'agent', text: '不客气，也感谢您的耐心等待，祝您用餐愉快～', time: ts('14:08', '12') },
];

const LEFT_USER_AVATAR = getTeamMemberByName('程程murphy');
const RIGHT_AGENT_AVATAR = getTeamMemberByName('段然');
const DEFAULT_THREAD = {
  id: 'default-thread',
  title: '用户不认可/不理解处罚',
  tagLabel: '十万',
  userId: '218401319',
  channel: '抖音',
  duration: '00:18:57',
  userName: LEFT_USER_AVATAR?.name || '用户',
  userAvatarSrc: LEFT_USER_AVATAR?.avatarSrc,
  agentName: RIGHT_AGENT_AVATAR?.name || '客服',
  agentAvatarSrc: RIGHT_AGENT_AVATAR?.avatarSrc,
};

const THREAD_ACTIONS = [
  { id: 'participants', label: '查看参与人', iconName: 'users-01-stroked' },
  { id: 'minimize', label: '收起会话', iconName: 'minus-circle-stroked' },
  { id: 'forward', label: '转发会话', iconName: 'share-06-stroked' },
  { id: 'resolve', label: '完成处理', iconName: 'check-circle-stroked' },
];
const THREAD_ACTION_BUTTON_SIZE = 36;
const THREAD_ACTION_GAP = 8;
const THREAD_ACTION_FULL_WIDTH =
  THREAD_ACTIONS.length * THREAD_ACTION_BUTTON_SIZE
  + (THREAD_ACTIONS.length - 1) * THREAD_ACTION_GAP;

function getAttachmentSummary(attachments = []) {
  if (!attachments.length) return '';
  return attachments
    .map((file) => file?.name || '图片')
    .filter(Boolean)
    .map((name) => `[图片] ${name}`)
    .join('\n');
}

function getMessageGroupTopGap(prevItem, currentItem) {
  if (!prevItem || !currentItem) return 0;
  if (prevItem.kind === 'system' || currentItem.kind === 'system') {
    return IM_MESSAGE_GROUP_GAP;
  }
  if (prevItem.kind === currentItem.kind) {
    return IM_MESSAGE_CONSECUTIVE_GAP;
  }
  return IM_MESSAGE_GROUP_GAP;
}

function groupConversation(items) {
  return items.reduce((groups, item) => {
    if (item.kind === 'system') {
      groups.push(item);
      return groups;
    }

    const last = groups[groups.length - 1];
    if (last && last.kind === item.kind && Array.isArray(last.messages)) {
      last.messages.push(item.text);
      last.timestamps.push(item.time);
      last.ids.push(item.id);
      return groups;
    }

    groups.push({
      id: item.id,
      kind: item.kind,
      messages: [item.text],
      timestamps: [item.time],
      ids: [item.id],
    });
    return groups;
  }, []);
}

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

function sortThreadHeaderTags(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];
}

/**
 * @param {{
 *  asCard?: boolean,
 *  maxWidth?: number | string | null,
 *  showComposer?: boolean,
 *  composerVariant?: 'auto' | 'im-basic' | 'default',
 *  composerPlaceholder?: string,
 *  onSend?: (text: string, ctx?: unknown) => void,
 *  showThreadHeader?: boolean,
 *  thread?: {
 *    id?: string,
 *    title?: string,
 *    tags?: Array<{ label:string, variant?:string, iconName?:string }>,
 *    tagLabel?: string,
 *    userId?: string,
 *    channel?: string,
 *    duration?: string,
 *    userName?: string,
 *    userAvatarSrc?: string,
 *    agentName?: string,
 *    agentAvatarSrc?: string,
 *  },
 *  messages?: Array<{ id:string, kind:'system'|'user'|'bot'|'agent', text:string, time:string }>,
 *  autoSendSignal?: { seed: number, text: string } | null,
 *  pagePadding?: number | null — 根容器 inset；默认 16。嵌入客服工作台等分栏场景传 0，与右侧 InfoDisplayPanel 顶底对齐。
 * }} props
 */
export default function IMConversationPattern({
  asCard = false,
  maxWidth = null,
  showComposer = true,
  composerVariant = 'auto',
  composerPlaceholder,
  onSend = () => {},
  showThreadHeader = true,
  thread,
  messages,
  className = '',
  style,
  composerPrefill = null,
  autoSendSignal = null,
  pagePadding,
} = {}) {
  const [runtimeMessages, setRuntimeMessages] = useState([]);
  const scrollRef = useRef(null);
  const resolvedThread = useMemo(
    () => ({
      ...DEFAULT_THREAD,
      ...(thread || {}),
    }),
    [thread],
  );
  const baseMessages = Array.isArray(messages) && messages.length > 0 ? messages : SCRIPT;
  const groupedItems = useMemo(
    () => groupConversation([...baseMessages, ...runtimeMessages]),
    [baseMessages, runtimeMessages],
  );
  const resolvedComposerVariant =
    composerVariant === 'auto'
      ? 'im-basic'
      : composerVariant === 'default'
        ? 'default'
        : 'im-basic';
  const resolvedComposerPlaceholder =
    composerPlaceholder
    || (resolvedComposerVariant === 'default' ? '继续协同处理当前会话…' : '请输入消息…');

  const resolvedPagePadding = pagePadding ?? IM_CONVERSATION_PAGE_PADDING;
  const resolvedMessageBottomGap = resolvedPagePadding > 0
    ? IM_MESSAGE_BOTTOM_GAP
    : IM_CONVERSATION_PAGE_PADDING;

  const cardStyle = asCard
    ? {
        background: 'var(--color-white, #FFFFFF)',
        borderRadius: 'inherit',
        boxSizing: 'border-box',
      }
    : {};

  const maxWidthStyle =
    maxWidth == null
      ? {}
      : {
          maxWidth: typeof maxWidth === 'number' ? `${maxWidth}px` : String(maxWidth),
          marginLeft: 'auto',
          marginRight: 'auto',
        };

  useEffect(() => {
    setRuntimeMessages([]);
  }, [resolvedThread.id]);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return undefined;
    const frame = window.requestAnimationFrame(() => {
      el.scrollTo({
        top: el.scrollHeight,
        behavior: runtimeMessages.length > 0 ? 'smooth' : 'auto',
      });
    });
    return () => window.cancelAnimationFrame(frame);
  }, [baseMessages, runtimeMessages.length]);

  const handleSend = useCallback((text, ctx) => {
    const content = (text || '').trim() || getAttachmentSummary(ctx?.attachments);
    if (!content) return;

    setRuntimeMessages((prev) => [
      ...prev,
      {
        id: `runtime-agent-${Date.now()}-${prev.length}`,
        kind: 'agent',
        text: content,
        time: formatCurrentTimestamp(),
      },
    ]);
    onSend?.(content, ctx);
  }, [onSend]);

  /* 外部 autoSendSignal 触发：把推荐回复直接作为人工客服消息追加到对话 */
  useEffect(() => {
    if (!autoSendSignal || !autoSendSignal.seed) return;
    const content = (autoSendSignal.text || '').trim();
    if (!content) return;
    setRuntimeMessages((prev) => [
      ...prev,
      {
        id: `runtime-agent-auto-${autoSendSignal.seed}-${prev.length}`,
        kind: 'agent',
        text: content,
        time: formatCurrentTimestamp(),
      },
    ]);
    onSend?.(content, { source: 'trust-mode' });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [autoSendSignal?.seed]);

  return (
    <div
      className={[
        'tfds-page-im-conversation flex h-full min-h-0 w-full min-w-0 flex-1 flex-col overflow-hidden',
        className,
      ].filter(Boolean).join(' ')}
      style={{
        flex: '1 0 auto',
        alignSelf: 'stretch',
        background: 'var(--color-white, #FFFFFF)',
        boxSizing: 'border-box',
        ...(resolvedPagePadding > 0
          ? {
              paddingLeft: resolvedPagePadding,
              paddingRight: resolvedPagePadding,
              paddingBottom: resolvedPagePadding,
            }
          : {}),
        ...maxWidthStyle,
        ...cardStyle,
        ...style,
      }}
    >
      <div
        ref={scrollRef}
        className="relative z-0 flex min-h-0 flex-1 min-w-0 flex-col overflow-y-auto overflow-x-hidden"
        style={{ paddingBottom: showComposer ? resolvedMessageBottomGap : undefined }}
      >
        {showThreadHeader && <IMThreadHeader thread={resolvedThread} />}
        <div className={IM_MESSAGE_LIST_CLASS}>
          {groupedItems.map((item, index) => {
            const prevItem = index > 0 ? groupedItems[index - 1] : null;
            const marginTop = index === 0 ? 0 : getMessageGroupTopGap(prevItem, item);
            return (
              <div
                key={item.id}
                className="min-w-0"
                style={marginTop > 0 ? { marginTop } : undefined}
              >
                {renderMessage(item, resolvedThread)}
              </div>
            );
          })}
        </div>
      </div>

      {showComposer && (
        <div className={IM_COMPOSER_FOOTER}>
          <ChatInput
            variant={resolvedComposerVariant}
            autoReplyOnSend={false}
            placeholder={resolvedComposerPlaceholder}
            acceptFiles={resolvedComposerVariant === 'im-basic' ? 'image/*' : '*'}
            onSend={handleSend}
            prefillText={composerPrefill?.text || ''}
            prefillSeed={composerPrefill?.seed || 0}
          />
        </div>
      )}
    </div>
  );
}

function IMThreadHeader({ thread }) {
  const headerRef = useRef(null);
  const infoRef = useRef(null);
  const actionBarRef = useRef(null);
  const moreButtonRef = useRef(null);
  const [visibleActionCount, setVisibleActionCount] = useState(THREAD_ACTIONS.length);
  const [actionBarWidth, setActionBarWidth] = useState(THREAD_ACTION_FULL_WIDTH);
  const [overflowOpen, setOverflowOpen] = useState(false);
  const hiddenActions = THREAD_ACTIONS.slice(visibleActionCount);
  const rawHeaderTags = Array.isArray(thread.tags) && thread.tags.length > 0
    ? thread.tags
    : (thread.tagLabel ? [{ label: thread.tagLabel, variant: 'white' }] : []);
  const headerTags = sortThreadHeaderTags(rawHeaderTags);

  useEffect(() => {
    const headerEl = headerRef.current;
    const infoEl = infoRef.current;
    if (!headerEl || !infoEl) return undefined;

    const updateVisibleActions = () => {
      const headerWidth = headerEl.getBoundingClientRect().width;
      const infoWidth = Math.ceil(Math.max(
        infoEl.getBoundingClientRect().width,
        infoEl.scrollWidth,
      ));
      const availableWidth = Math.max(
        THREAD_ACTION_BUTTON_SIZE,
        headerWidth - infoWidth - 16,
      );
      const nextActionBarWidth = Math.min(availableWidth, THREAD_ACTION_FULL_WIDTH);
      setActionBarWidth(nextActionBarWidth);

      if (nextActionBarWidth >= THREAD_ACTION_FULL_WIDTH) {
        setVisibleActionCount(THREAD_ACTIONS.length);
        return;
      }

      let nextVisibleCount = 0;
      for (let count = THREAD_ACTIONS.length - 1; count >= 0; count -= 1) {
        const itemCount = count + 1; // visible actions + more button
        const neededWidth =
          itemCount * THREAD_ACTION_BUTTON_SIZE
          + Math.max(0, itemCount - 1) * THREAD_ACTION_GAP;
        if (nextActionBarWidth >= neededWidth) {
          nextVisibleCount = count;
          break;
        }
      }
      setVisibleActionCount(nextVisibleCount);
    };

    updateVisibleActions();
    const observer = new ResizeObserver(updateVisibleActions);
    observer.observe(headerEl);
    observer.observe(infoEl);
    return () => observer.disconnect();
  }, []);

  useEffect(() => {
    if (visibleActionCount >= THREAD_ACTIONS.length) {
      setOverflowOpen(false);
    }
  }, [visibleActionCount]);

  const overflowItems = useMemo(
    () => hiddenActions.map((action) => ({
      id: action.id,
      value: action.id,
      label: action.label,
      iconName: action.iconName,
      onClick: () => setOverflowOpen(false),
    })),
    [hiddenActions],
  );

  return (
    <div
      ref={headerRef}
      className={IM_THREAD_HEADER_CLASS}
      style={IM_THREAD_HEADER_STYLE}
      data-tfds-im-thread-header="true"
    >
      <div ref={infoRef} className="flex min-w-0 items-center gap-3">
        <Avatar
          size="s"
          type="image"
          src={thread.userAvatarSrc}
          alt={`${thread.userName || '用户'}头像`}
          className="ring-1 ring-border-default/30"
        />

        <div className="flex min-w-0 flex-col justify-center gap-1">
          <div className="flex min-w-0 items-center gap-2">
            <h2 className="m-0 truncate text-sm leading-5 tracking-[-0.01em] text-foreground [font-weight:var(--font-semibold)]">
              {thread.title}
            </h2>
            {headerTags.map((tag, index) => (
              <Tag
                key={`${tag.label}-${index}`}
                variant={tag.variant || 'grey'}
                size="m"
                radius="md"
                fontWeight="regular"
                showIcon={Boolean(tag.iconName)}
                iconName={tag.iconName}
                className="shrink-0"
              >
                {tag.label}
              </Tag>
            ))}
          </div>

          <div className="flex min-w-0 items-center gap-2 text-xs leading-4 text-foreground-muted">
            <MetaItem iconName="user-01-stroked" label={thread.userId} tooltip="会话ID" />
            <MetaDivider />
            <MetaItem iconName="phone-01-stroked" label={thread.channel} tooltip="沟通渠道" />
            <MetaDivider />
            <MetaItem iconName="clock-stroked" label={thread.duration} tooltip="沟通时长" />
          </div>
        </div>
      </div>

      <div
        ref={actionBarRef}
        className="relative flex min-w-9 shrink-0 items-center justify-end gap-2 overflow-visible"
        style={{ width: `${actionBarWidth}px` }}
      >
        {THREAD_ACTIONS.slice(0, visibleActionCount).map((action) => (
          <ThreadActionButton key={action.id} action={action} />
        ))}
        {hiddenActions.length > 0 ? (
          <Dropdown
            className="inline-flex shrink-0"
            open={overflowOpen}
            onOpenChange={setOverflowOpen}
            panelAlign="end"
            selectionIndicator="none"
            showIcon
            matchTriggerWidth={false}
            minWidth={148}
            items={overflowItems}
            panelClassName="tfds-im-action-overflow-menu"
            trigger={(
              <ThreadActionButton
                ref={moreButtonRef}
                action={{ id: 'more', label: '更多操作', iconName: 'dots-horizontal-stroked' }}
                ariaExpanded={overflowOpen}
              />
            )}
          />
        ) : null}
      </div>
    </div>
  );
}

function ThreadActionButton({ action, ariaExpanded, onClick, ref }) {
  return (
    <Button
      ref={ref}
      type="button"
      variant="ghost-black"
      size="md"
      iconOnly
      tooltip={action.label}
      aria-label={action.label}
      aria-expanded={ariaExpanded}
      onClick={onClick}
      icon={<Icon name={action.iconName} size="sm" aria-hidden="true" />}
    />
  );
}

function MetaItem({ iconName, label, tooltip }) {
  return (
    <Tooltip content={tooltip} placement="top" triggerClassName="inline-flex min-w-0 shrink-0">
      <span className="inline-flex min-w-0 shrink-0 items-center justify-center gap-1">
        <Icon name={iconName} size="xs" aria-hidden="true" />
        <span className="truncate">{label}</span>
      </span>
    </Tooltip>
  );
}

function MetaDivider() {
  return (
    <span
      aria-hidden="true"
      className="h-2.5 w-px shrink-0 bg-border-default"
    />
  );
}

function renderMessage(m, thread) {
  if (m.kind === 'system') {
    return <SystemNote key={m.id} text={m.text} time={m.time} />;
  }
  if (m.kind === 'user') {
    return (
      <ChatBubble
        key={m.id}
        variant="incoming"
        avatarType="image"
        avatarSrc={thread.userAvatarSrc}
        avatarAlt={`${thread.userName || '用户'}头像`}
        incomingTone="grey"
        messages={m.messages}
        timestamps={m.timestamps}
      />
    );
  }
  if (m.kind === 'bot') {
    return (
      <ChatBubble
        key={m.id}
        variant="outgoing"
        avatarType="ai"
        outgoingTone="ai"
        messages={m.messages}
        timestamps={m.timestamps}
      />
    );
  }
  return (
    <ChatBubble
      key={m.id}
      variant="outgoing"
      avatarType="image"
      avatarSrc={thread.agentAvatarSrc}
      avatarAlt={`${thread.agentName || '客服'}头像`}
      outgoingTone="default"
      receipt="read"
      messages={m.messages}
      timestamps={m.timestamps}
    />
  );
}

function formatSystemTime(value) {
  if (typeof value !== 'string') return value;
  const parts = value.trim().split(' ');
  const hhmmss = parts.length >= 2 ? parts[1] : parts[0];
  if (!hhmmss) return value;
  const hhmm = hhmmss.split(':').slice(0, 2).join(':');
  return hhmm || value;
}

function SystemNote({ text, time }) {
  return (
    <div
      className="flex w-full items-center justify-center gap-2 text-xs"
      style={{ color: 'var(--foreground-muted, #667085)', padding: '4px 0' }}
    >
      <span>{formatSystemTime(time)}</span>
      <span>·</span>
      <span>{text}</span>
    </div>
  );
}

/**
 * 平台模板预览：全宽撑满预览帧 + 吸底输入，无外框描边。
 */
export function IMConversationPagePreview() {
  return (
    <IMConversationPattern
      style={{
        height: '100%',
        minHeight: 0,
        flex: '1 0 auto',
        alignSelf: 'stretch',
      }}
    />
  );
}
