import { Ionicons } from '@expo/vector-icons';
import { BlurView } from 'expo-blur';
import * as Haptics from 'expo-haptics';
import * as ImagePicker from 'expo-image-picker';
import { useLocalSearchParams, useRouter } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  ActivityIndicator,
  Alert,
  FlatList,
  Image,
  Keyboard,
  Modal,
  Platform,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from 'react-native';
import Markdown from 'react-native-markdown-display';
import Animated, { FadeInDown, FadeInUp, Layout } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { Colors } from '@/constants/Colors';
import { getTabBarBottomPadding } from '@/constants/TabBar';
import { useAppSelector } from '@/hooks/redux';
import { useAuthGuard } from '@/hooks/useAuthGuard';
import { useCosUpload } from '@/hooks/useCosUpload';
import { deleteConversation, getConversationDetail, listConversations, type AiConversationListItem } from '@/services/aiCoach';
import { loadAiCoachSessionCache, saveAiCoachSessionCache } from '@/services/aiCoachSession';
import { api, getAuthToken, postTextStream } from '@/services/api';
import dayjs from 'dayjs';
import { ActionSheet } from '../../components/ui/ActionSheet';

type Role = 'user' | 'assistant';

// 附件类型枚举
type AttachmentType = 'image' | 'video' | 'file';

// 附件数据结构
type MessageAttachment = {
  id: string;
  type: AttachmentType;
  url: string;
  localUri?: string;  // 本地URI，用于上传中的显示
  filename?: string;
  size?: number;
  duration?: number;  // 视频时长（秒）
  thumbnail?: string; // 视频缩略图
  width?: number;
  height?: number;
  uploadProgress?: number; // 上传进度 0-1
  uploadError?: string;    // 上传错误信息
};

// AI选择选项数据结构
type AiChoiceOption = {
  id: string;
  label: string;
  value: any;
  recommended?: boolean;
};

// 餐次类型
type MealType = 'breakfast' | 'lunch' | 'dinner' | 'snack';

// 食物确认选项数据结构（暂未使用，预留给未来功能扩展）
// type FoodConfirmationOption = {
//   id: string;
//   label: string;
//   foodName: string;
//   portion: string;
//   calories: number;
//   mealType: MealType;
//   nutritionData: {
//     proteinGrams?: number;
//     carbohydrateGrams?: number;
//     fatGrams?: number;
//     fiberGrams?: number;
//   };
// };

// AI响应数据结构
type AiResponseData = {
  content: string;
  choices?: AiChoiceOption[];
  interactionType?: 'text' | 'food_confirmation' | 'selection';
  pendingData?: any;
  context?: any;
};

// 重构后的消息数据结构
type ChatMessage = {
  id: string;
  role: Role;
  content: string;           // 文本内容
  attachments?: MessageAttachment[]; // 附件列表
  choices?: AiChoiceOption[]; // 选择选项（仅用于assistant消息）
  interactionType?: string;   // 交互类型
  pendingData?: any;         // 待确认数据
  context?: any;             // 上下文信息
};

// 卡片类型常量定义
const CardType = {
  WEIGHT_INPUT: '__WEIGHT_INPUT_CARD__',
  DIET_INPUT: '__DIET_INPUT_CARD__',
  DIET_TEXT_INPUT: '__DIET_TEXT_INPUT__',
} as const;

type CardType = typeof CardType[keyof typeof CardType];

// const COACH_AVATAR = require('@/assets/images/logo.png');

export default function CoachScreen() {
  const router = useRouter();
  const params = useLocalSearchParams<{ name?: string }>();
  const insets = useSafeAreaInsets();

  const { isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard();
  // 为了让页面更贴近品牌主题与更亮的观感，这里使用亮色系配色
  const theme = Colors.light;
  const botName = (params?.name || 'Bot').toString();
  const [input, setInput] = useState('');
  const [isSending, setIsSending] = useState(false);
  const [isStreaming, setIsStreaming] = useState(false);
  const [conversationId, setConversationId] = useState<string | undefined>(undefined);
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [historyVisible, setHistoryVisible] = useState(false);
  const [historyLoading, setHistoryLoading] = useState(false);
  const [historyPage, setHistoryPage] = useState(1);
  const [historyTotal] = useState(0);
  const [historyItems, setHistoryItems] = useState<AiConversationListItem[]>([]);
  // 添加请求序列号，用于防止过期响应
  const requestSequenceRef = useRef<number>(0);
  const activeRequestIdRef = useRef<string | null>(null);
  const listRef = useRef<FlatList<ChatMessage>>(null);
  const [isAtBottom, setIsAtBottom] = useState(true);
  const didInitialScrollRef = useRef(false);
  const [composerHeight, setComposerHeight] = useState<number>(80);
  const shouldAutoScrollRef = useRef(false);
  const [keyboardOffset, setKeyboardOffset] = useState(0);
  const [headerHeight, setHeaderHeight] = useState<number>(60);
  const pendingAssistantIdRef = useRef<string | null>(null);
  const [selectedImages, setSelectedImages] = useState<{
    id: string;
    localUri: string;
    width?: number;
    height?: number;
    progress: number;
    uploadedKey?: string;
    uploadedUrl?: string;
    error?: string;
  }[]>([]);
  const [previewImageUri, setPreviewImageUri] = useState<string | null>(null);
  const [dietTextInputs, setDietTextInputs] = useState<Record<string, string>>({});
  const [weightInputs, setWeightInputs] = useState<Record<string, string>>({});
  const [showDietPhotoActionSheet, setShowDietPhotoActionSheet] = useState(false);
  const [currentCardId, setCurrentCardId] = useState<string | null>(null);
  const [selectedChoices, setSelectedChoices] = useState<Record<string, string>>({});  // messageId -> choiceId
  const [pendingChoiceConfirmation, setPendingChoiceConfirmation] = useState<Record<string, boolean>>({});  // messageId -> loading

  const planDraft = useAppSelector((s) => s.trainingPlan?.draft);
  const checkin = useAppSelector((s) => s.checkin || {});

  const userProfile = useAppSelector((s) => s.user?.profile);
  const { upload } = useCosUpload();

  // 生成个性化欢迎消息
  const generateWelcomeMessage = useCallback(() => {
    const hour = new Date().getHours();
    const name = userProfile?.name || '朋友';
    const botName = (params?.name || '海豹助手').toString();

    // 时段问候
    let timeGreeting = '';
    if (hour >= 5 && hour < 9) {
      timeGreeting = '早上好';
    } else if (hour >= 9 && hour < 12) {
      timeGreeting = '上午好';
    } else if (hour >= 12 && hour < 14) {
      timeGreeting = '中午好';
    } else if (hour >= 14 && hour < 18) {
      timeGreeting = '下午好';
    } else if (hour >= 18 && hour < 22) {
      timeGreeting = '晚上好';
    } else {
      timeGreeting = '夜深了';
    }

    // 欢迎消息模板
    const welcomeMessages = [
      {
        condition: () => hour >= 5 && hour < 9,
        messages: [
          `${timeGreeting}，${name}！我是${botName}，你的专属健康管理助手。新的一天开始了，让我们一起为你的健康目标努力吧！`,
          `${timeGreeting}！早晨是制定健康计划的最佳时机，我是${botName}，可以帮你管理营养摄入、运动计划和生活作息。`,
          `${timeGreeting}，${name}！作为你的海豹助手，我很高兴能陪伴你的健康之旅。无论是饮食营养、健身锻炼还是生活管理，我都能为你提供专业建议。`
        ]
      },
      {
        condition: () => hour >= 9 && hour < 12,
        messages: [
          `${timeGreeting}，${name}！我是${botName}，你的智能健康顾问。上午是身体代谢最活跃的时候，有什么健康目标需要我帮你规划吗？`,
          `${timeGreeting}！工作忙碌的上午，别忘了关注身体健康。我是${botName}，可以为你提供营养建议、运动指导和压力管理方案。`,
          `${timeGreeting}，${name}！作为你的健康伙伴${botName}，我想说：每一个健康的选择都在塑造更好的你。今天想从哪个方面开始呢？`
        ]
      },
      {
        condition: () => hour >= 12 && hour < 14,
        messages: [
          `${timeGreeting}，${name}！午餐时间很关键呢，合理的营养搭配能为下午提供充足能量。我是${botName}，可以为你分析饮食营养和热量管理。`,
          `${timeGreeting}！忙碌的上午结束了，该关注一下身体需求啦。我是你的健康助手${botName}，无论是饮食调整、运动安排还是休息建议，都可以找我。`,
          `${timeGreeting}，${name}！午间是调整状态的好时机。作为你的海豹助手，我建议关注饮食均衡和适度放松～`
        ]
      },
      {
        condition: () => hour >= 14 && hour < 18,
        messages: [
          `${timeGreeting}，${name}！下午是身体活动的黄金时段，适合安排一些运动。我是${botName}，可以为你制定个性化的健身计划和身材管理方案。`,
          `${timeGreeting}！午后时光，正是关注整体健康的好时机。我是你的健康管家${botName}，从营养摄入到运动锻炼，我都能为你提供科学指导。`,
          `${timeGreeting}，${name}！下午时光，身心健康同样重要。作为你的智能健康顾问${botName}，我在这里支持你的每一个健康目标。`
        ]
      },
      {
        condition: () => hour >= 18 && hour < 22,
        messages: [
          `${timeGreeting}，${name}！忙碌了一天，现在是时候关注身心平衡了。我是${botName}，可以为你提供放松建议、营养补充和恢复方案。`,
          `${timeGreeting}！夜幕降临，这是一天中最适合总结和调整的时刻。我是你的健康伙伴${botName}，让我们一起回顾今天的健康表现，规划明天的目标。`,
          `${timeGreeting}，${name}！晚间时光属于你自己，也是关爱身体的珍贵时间。作为你的海豹助手，我想陪你聊聊如何更好地管理健康生活。`
        ]
      },
      {
        condition: () => hour >= 22 || hour < 5,
        messages: [
          `${timeGreeting}，${name}！优质睡眠是健康的基石呢。我是${botName}，如果需要睡眠优化建议或放松技巧，随时可以问我。`,
          `夜深了，${name}。充足的睡眠对身体恢复和新陈代谢都很重要。我是你的健康助手${botName}，有什么关于睡眠健康的问题都可以咨询我。`,
          `夜深了，愿你能拥有高质量的睡眠。我是${botName}，明天我们继续在健康管理的路上同行。晚安，${name}！`
        ]
      }
    ];

    // 特殊情况的消息
    const specialMessages = [
      {
        condition: () => !userProfile?.weight && !userProfile?.height,
        message: `你好，${name}！我是${botName}，你的智能健康管理助手。我注意到你还没有完善健康档案，不如先聊聊你的健康目标和身体状况，这样我能为你制定更个性化的健康方案。`
      },
      {
        condition: () => userProfile && (!userProfile.pilatesPurposes || userProfile.pilatesPurposes.length === 0),
        message: `${timeGreeting}，${name}！作为你的海豹助手，我想更好地了解你的健康需求。告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧～`
      }
    ];

    // 检查特殊情况
    for (const special of specialMessages) {
      if (special.condition()) {
        return special.message;
      }
    }

    // 根据时间选择合适的消息组
    const timeGroup = welcomeMessages.find(group => group.condition());
    if (timeGroup) {
      const messages = timeGroup.messages;
      return messages[Math.floor(Math.random() * messages.length)];
    }

    // 默认消息
    return `你好，我是${botName}，你的智能健康管理助手。可以向我咨询营养摄入、身材管理、健身锻炼、生活管理等各方面的健康问题～`;
  }, [userProfile, params?.name]);

  const chips = useMemo(() => [
    // { key: 'posture', label: '体态评估', action: () => router.push('/ai-posture-assessment') },
    // { key: 'plan', label: 'AI制定训练计划', action: () => handleQuickPlan() },
    // { key: 'analyze', label: '分析运动记录', action: () => handleAnalyzeRecords() },
    { key: 'weight', label: '#记体重', action: () => insertWeightInputCard() },
    { key: 'diet', label: '#记饮食', action: () => insertDietInputCard() },
  ], [router, planDraft, checkin]);

  const scrollToEnd = useCallback(() => {
    requestAnimationFrame(() => {
      listRef.current?.scrollToEnd({ animated: true });
    });
  }, []);

  const handleScroll = useCallback((e: any) => {
    try {
      const { contentOffset, contentSize, layoutMeasurement } = e.nativeEvent || {};
      if (!contentOffset || !contentSize || !layoutMeasurement) return;

      const paddingToBottom = 60;
      const distanceFromBottom = (contentSize.height || 0) - ((layoutMeasurement.height || 0) + (contentOffset.y || 0));
      setIsAtBottom(distanceFromBottom <= paddingToBottom);
    } catch (error) {
      console.warn('[AI_CHAT] Scroll handling error:', error);
    }
  }, []);

  useEffect(() => {
    // 初次进入或恢复时，保持最新消息可见
    const timer = setTimeout(scrollToEnd, 100);
    return () => clearTimeout(timer);
  }, []);
  // 初始化欢迎消息
  const initializeWelcomeMessage = useCallback(() => {
    const welcomeMessage: ChatMessage = {
      id: 'm_welcome',
      role: 'assistant',
      content: generateWelcomeMessage(),
    };
    setMessages([welcomeMessage]);
  }, [generateWelcomeMessage]);

  // 启动页面时尝试恢复当次应用会话缓存
  useEffect(() => {
    let isMounted = true;

    (async () => {
      try {
        const cached = await loadAiCoachSessionCache();
        if (isMounted && cached && Array.isArray(cached.messages) && cached.messages.length > 0) {
          setConversationId(cached.conversationId);
          // 确保缓存的消息符合新的 ChatMessage 结构
          const validMessages = cached.messages
            .filter(msg => msg && typeof msg === 'object' && msg.role && msg.content)
            .map(msg => ({
              ...msg,
              // 确保 attachments 字段存在，对于旧的缓存消息可能没有这个字段
              attachments: (msg as any).attachments || undefined,
            })) as ChatMessage[];
          setMessages(validMessages);
          setTimeout(() => {
            if (isMounted) scrollToEnd();
          }, 100);
        } else {
          // 没有缓存时显示欢迎消息
          if (isMounted) {
            initializeWelcomeMessage();
          }
        }
      } catch (error) {
        console.warn('[AI_CHAT] Failed to load session cache:', error);
        // 出错时也显示欢迎消息
        if (isMounted) {
          initializeWelcomeMessage();
        }
      }
    })();

    return () => {
      isMounted = false;
    };
  }, [initializeWelcomeMessage]);

  // 会话变动时，轻量防抖写入缓存（在本次应用生命周期内可跨页面恢复；下次冷启动会被根布局清空）
  const saveCacheTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  useEffect(() => {
    if (saveCacheTimerRef.current) {
      clearTimeout(saveCacheTimerRef.current);
    }

    // 只有在有实际消息内容时才保存缓存
    if (messages.length > 1 || (messages.length === 1 && messages[0].id !== 'm_welcome')) {
      saveCacheTimerRef.current = setTimeout(() => {
        const validMessages = messages.filter(msg => msg && msg.role && msg.content);
        saveAiCoachSessionCache({
          conversationId,
          messages: validMessages,
          updatedAt: Date.now()
        }).catch((error) => {
          console.warn('[AI_CHAT] Failed to save session cache:', error);
        });
      }, 300);
    }

    return () => {
      if (saveCacheTimerRef.current) {
        clearTimeout(saveCacheTimerRef.current);
        saveCacheTimerRef.current = null;
      }
    };
  }, [messages, conversationId]);


  // 取消对 messages.length 的全局监听滚动，改为在"消息实际追加完成"后再判断与滚动，避免突兀与多次触发

  useEffect(() => {
    // 输入区高度变化时，若用户在底部则轻柔跟随一次
    if (isAtBottom) {
      const id = setTimeout(scrollToEnd, 100);
      return () => clearTimeout(id);
    }
  }, [composerHeight, isAtBottom]);

  // 键盘事件：在键盘弹出时，将输入区与悬浮按钮一起上移，避免遮挡
  useEffect(() => {
    let showSub: any = null;
    let hideSub: any = null;

    if (Platform.OS === 'ios') {
      showSub = Keyboard.addListener('keyboardWillChangeFrame', (e: any) => {
        try {
          if (e?.endCoordinates?.height) {
            const height = Math.max(0, e.endCoordinates.height - insets.bottom);
            setKeyboardOffset(height);
          }
        } catch (error) {
          console.warn('[KEYBOARD] iOS keyboard event error:', error);
          setKeyboardOffset(0);
        }
      });
      hideSub = Keyboard.addListener('keyboardWillHide', () => {
        setKeyboardOffset(0);
      });
    } else {
      showSub = Keyboard.addListener('keyboardDidShow', (e: any) => {
        try {
          if (e?.endCoordinates?.height) {
            setKeyboardOffset(Math.max(0, e.endCoordinates.height));
          }
        } catch (error) {
          console.warn('[KEYBOARD] Android keyboard event error:', error);
          setKeyboardOffset(0);
        }
      });
      hideSub = Keyboard.addListener('keyboardDidHide', () => {
        setKeyboardOffset(0);
      });
    }

    return () => {
      try {
        showSub?.remove?.();
      } catch (error) {
        console.warn('[KEYBOARD] Error removing keyboard show listener:', error);
      }
      try {
        hideSub?.remove?.();
      } catch (error) {
        console.warn('[KEYBOARD] Error removing keyboard hide listener:', error);
      }
    };
  }, [insets.bottom]);

  const streamAbortRef = useRef<{ abort: () => void } | null>(null);

  // 组件卸载时清理流式请求和定时器
  useEffect(() => {
    return () => {
      try {
        if (streamAbortRef.current) {
          streamAbortRef.current.abort();
          streamAbortRef.current = null;
        }
      } catch (error) {
        console.warn('[AI_CHAT] Error aborting stream on unmount:', error);
      }

      if (saveCacheTimerRef.current) {
        clearTimeout(saveCacheTimerRef.current);
        saveCacheTimerRef.current = null;
      }
    };
  }, []);

  function ensureConversationId(): string {
    if (conversationId && conversationId.trim()) return conversationId;
    // 延迟生成会话ID，只在请求成功开始时才生成
    return '';
  }

  function createNewConversationId(): string {
    const cid = `mobile-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
    setConversationId(cid);
    try { console.log('[AI_CHAT][ui] create new conversationId', cid); } catch { }
    return cid;
  }

  function convertToServerMessages(history: ChatMessage[]): { role: 'user' | 'assistant' | 'system'; content: string }[] {
    // 仅映射 user/assistant 消息；系统提示由后端自动注入
    return history
      .filter((m) => m.role === 'user' || m.role === 'assistant')
      .map((m) => ({ role: m.role, content: m.content }));
  }

  async function openHistory() {
    if (isStreaming || isSending) {
      cancelCurrentRequest();
    }
    setHistoryVisible(true);
    await refreshHistory(1);
  }

  async function refreshHistory(page = 1) {
    try {
      setHistoryLoading(true);
      const resp = await listConversations(page, 20);
      setHistoryPage(resp.page);
      // setHistoryTotal(resp.total); // 临时注释，因为当前未使用
      setHistoryItems(resp.items || []);
    } catch (e) {
      Alert.alert('错误', (e as any)?.message || '获取会话列表失败');
    } finally {
      setHistoryLoading(false);
    }
  }

  function startNewConversation() {
    if (isStreaming || isSending) {
      cancelCurrentRequest();
    }

    // 清理当前会话状态
    setConversationId(undefined);
    setSelectedImages([]);
    setDietTextInputs({});
    setWeightInputs({});
    setSelectedChoices({});
    setPendingChoiceConfirmation({});

    // 创建新的欢迎消息
    initializeWelcomeMessage();

    // 清理本地缓存
    saveAiCoachSessionCache({
      conversationId: undefined,
      messages: [],
      updatedAt: Date.now()
    }).catch((error) => {
      console.warn('[AI_CHAT] Failed to clear session cache:', error);
    });

    setTimeout(scrollToEnd, 100);
  }

  async function handleSelectConversation(id: string) {
    try {
      if (isStreaming || isSending) {
        cancelCurrentRequest();
      }
      const detail = await getConversationDetail(id);
      if (!detail || !(detail as any).messages) {
        Alert.alert('提示', '会话不存在或已删除');
        return;
      }
      const mapped: ChatMessage[] = (detail.messages || [])
        .filter((m) => m.role === 'user' || m.role === 'assistant')
        .map((m, idx) => ({
          id: `${m.role}_${idx}_${Date.now()}`,
          role: m.role as Role,
          content: m.content || '',
          // 对于历史消息，暂时不包含附件信息，因为服务器端可能还没有返回附件数据
          // 如果将来服务器支持返回附件信息，可以在这里添加映射逻辑
          attachments: undefined,
        }));
      setConversationId(detail.conversationId);
      setMessages(mapped.length ? mapped : [{ id: 'm_welcome', role: 'assistant', content: generateWelcomeMessage() }]);
      setHistoryVisible(false);
      setTimeout(scrollToEnd, 0);
    } catch (e) {
      Alert.alert('错误', (e as any)?.message || '加载会话失败');
    }
  }

  function confirmDeleteConversation(id: string) {
    Alert.alert('删除会话', '删除后将无法恢复，确定要删除该会话吗？', [
      { text: '取消', style: 'cancel' },
      {
        text: '删除', style: 'destructive', onPress: async () => {
          try {
            await deleteConversation(id);
            if (conversationId === id) {
              setConversationId(undefined);
              setMessages([{ id: 'm_welcome', role: 'assistant', content: generateWelcomeMessage() }]);
            }
            await refreshHistory(historyPage);
          } catch (e) {
            Alert.alert('错误', (e as any)?.message || '删除失败');
          }
        }
      }
    ]);
  }

  async function sendStreamWithConfirmation(text: string, selectedChoiceId: string, confirmationData: any) {
    // 发送确认选择的特殊请求
    const historyForServer = convertToServerMessages(messages);
    const cid = ensureConversationId();
    const body = {
      conversationId: cid || undefined,
      messages: [...historyForServer, { role: 'user' as const, content: text }],
      selectedChoiceId,
      confirmationData,
      stream: false, // 确认阶段使用非流式
    };

    await sendRequestInternal(body, text);
  }

  async function sendStream(text: string, imageUrls: string[] = []) {
    const historyForServer = convertToServerMessages(messages);
    const cid = ensureConversationId(); // 可能返回空字符串
    const body = {
      conversationId: cid || undefined, // 如果没有现有会话ID，传undefined让服务端生成
      messages: [...historyForServer, { role: 'user' as const, content: text }],
      imageUrls: imageUrls.length > 0 ? imageUrls : undefined,
      stream: true,
    };

    await sendRequestInternal(body, text, imageUrls);
  }

  function cancelCurrentRequest() {
    try {
      console.log('[AI_CHAT][ui] User cancelled request');

      // 增加请求序列号，使后续响应失效
      requestSequenceRef.current += 1;

      // 清除活跃请求ID
      activeRequestIdRef.current = null;

      // 中断网络请求
      if (streamAbortRef.current) {
        streamAbortRef.current.abort();
        streamAbortRef.current = null;
      }

      // 清理状态
      setIsSending(false);
      setIsStreaming(false);

      // 移除正在生成中的助手消息
      if (pendingAssistantIdRef.current) {
        setMessages((prev) => prev.filter(msg => msg.id !== pendingAssistantIdRef.current));
        pendingAssistantIdRef.current = null;
      }

      // 触觉反馈
      Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);

      console.log('[AI_CHAT][ui] Request cancelled, sequence incremented to:', requestSequenceRef.current);

    } catch (error) {
      console.warn('[AI_CHAT] Error cancelling request:', error);
    }
  }

  async function sendRequestInternal(body: any, text: string, imageUrls: string[] = []) {
    const tokenExists = !!getAuthToken();

    // 生成当前请求的序列号和ID
    const currentSequence = ++requestSequenceRef.current;
    const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    activeRequestIdRef.current = requestId;

    try {
      console.log('[AI_CHAT][ui] send start', {
        requestId,
        sequence: currentSequence,
        tokenExists,
        conversationId,
        textPreview: text.slice(0, 50),
        imageUrls,
        stream: body.stream
      });
    } catch { }

    // 验证请求是否仍然有效的函数
    const isRequestValid = () => {
      const isValid = activeRequestIdRef.current === requestId && requestSequenceRef.current === currentSequence;
      if (!isValid) {
        console.log('[AI_CHAT][ui] Request invalidated', {
          requestId,
          currentActive: activeRequestIdRef.current,
          sequence: currentSequence,
          currentSequence: requestSequenceRef.current
        });
      }
      return isValid;
    };

    // 终止上一次未完成的流
    if (streamAbortRef.current) {
      try { console.log('[AI_CHAT][ui] abort previous stream'); } catch { }
      try { streamAbortRef.current.abort(); } catch { }
      streamAbortRef.current = null;
    }

    // 在 UI 中先放置占位回答，随后持续增量更新
    const assistantId = `a_${Date.now()}`;
    const userMsgId = `u_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;

    // 构建包含附件的用户消息
    const attachments = imageUrls.map((url, index) => ({
      id: `img_${Date.now()}_${index}`,
      type: 'image' as AttachmentType,
      url,
    }));

    const userMsg: ChatMessage = {
      id: userMsgId,
      role: 'user',
      content: text,
      attachments: attachments.length > 0 ? attachments : undefined,
    };
    shouldAutoScrollRef.current = isAtBottom;
    setMessages((m) => [...m, userMsg, { id: assistantId, role: 'assistant', content: '' }]);
    pendingAssistantIdRef.current = assistantId;

    setIsSending(true);
    setIsStreaming(true);

    // 如果是非流式请求，直接调用API并处理响应
    if (!body.stream) {
      try {
        const response = await api.post<{ conversationId?: string; data?: AiResponseData; text?: string }>('/api/ai-coach/chat', body);

        setIsSending(false);
        setIsStreaming(false);

        // 处理响应
        if (response.data) {
          // 结构化响应（可能包含选择选项）
          const assistantMsg: ChatMessage = {
            id: assistantId,
            role: 'assistant',
            content: response.data.content,
            choices: response.data.choices,
            interactionType: response.data.interactionType,
            pendingData: response.data.pendingData,
            context: response.data.context,
          };

          setMessages((prev) => prev.map((msg) =>
            msg.id === assistantId ? assistantMsg : msg
          ));
        } else if (response.text) {
          // 简单文本响应
          setMessages((prev) => prev.map((msg) =>
            msg.id === assistantId ? { ...msg, content: response.text || '（空响应）' } : msg
          ));
        }

        if (response.conversationId && !conversationId) {
          setConversationId(response.conversationId);
        }

        pendingAssistantIdRef.current = null;
        return;
      } catch (e: any) {
        setIsSending(false);
        setIsStreaming(false);
        pendingAssistantIdRef.current = null;
        setMessages((prev) => prev.map((msg) =>
          msg.id === assistantId ? { ...msg, content: '抱歉，请求失败，请稍后再试。' } : msg
        ));
        throw e;
      }
    }

    let receivedAnyChunk = false;

    const updateAssistantContent = (delta: string) => {
      setMessages((prev) => {
        const next = prev.map((msg) => {
          if (msg.id === assistantId) {
            return { ...msg, content: msg.content + delta };
          }
          return msg;
        });
        return next;
      });
    };

    const onChunk = (chunk: string) => {
      // 验证请求是否仍然有效
      if (!isRequestValid()) {
        console.log('[AI_CHAT][api] Ignoring chunk from invalidated request');
        return;
      }

      receivedAnyChunk = true;
      const atBottomNow = isAtBottom;

      // 尝试解析是否为JSON结构化数据（可能是确认选项）
      try {
        const parsed = JSON.parse(chunk);
        if (parsed && parsed.data && parsed.data.choices) {
          // 再次验证请求有效性
          if (!isRequestValid()) return;

          // 处理结构化响应（包含选择选项）
          const assistantMsg: ChatMessage = {
            id: assistantId,
            role: 'assistant',
            content: parsed.data.content,
            choices: parsed.data.choices,
            interactionType: parsed.data.interactionType,
            pendingData: parsed.data.pendingData,
            context: parsed.data.context,
          };

          setMessages((prev) => prev.map((msg) =>
            msg.id === assistantId ? assistantMsg : msg
          ));

          // 处理conversationId - 只在请求有效时设置
          if (parsed.conversationId && !conversationId) {
            setConversationId(parsed.conversationId);
            console.log('[AI_CHAT][ui] Set conversationId from structured response:', parsed.conversationId);
          }

          // 结束流式状态
          setIsSending(false);
          setIsStreaming(false);
          streamAbortRef.current = null;
          pendingAssistantIdRef.current = null;
          activeRequestIdRef.current = null;
          return;
        }
      } catch {
        // 不是JSON，继续作为普通文本处理
      }

      updateAssistantContent(chunk);
      if (atBottomNow) {
        // 在底部时，持续开启自动滚动，并主动触发一次滚动以避免极小增量未触发 onContentSizeChange 的情况
        shouldAutoScrollRef.current = true;
        setTimeout(scrollToEnd, 0);
      }
      try { console.log('[AI_CHAT][api] chunk', { requestId, length: chunk.length, preview: chunk.slice(0, 40) }); } catch { }
    };

    const onEnd = (cidFromHeader?: string) => {
      // 验证请求是否仍然有效
      if (!isRequestValid()) {
        console.log('[AI_CHAT][api] Ignoring end from invalidated request');
        return;
      }

      setIsSending(false);
      setIsStreaming(false);
      streamAbortRef.current = null;
      if (cidFromHeader && !conversationId) {
        setConversationId(cidFromHeader);
        console.log('[AI_CHAT][ui] Set conversationId from header:', cidFromHeader);
      }
      pendingAssistantIdRef.current = null;
      activeRequestIdRef.current = null;
      try { console.log('[AI_CHAT][api] end', { requestId, cidFromHeader, hadChunks: receivedAnyChunk }); } catch { }
    };

    const onError = async (err: any) => {
      try { console.warn('[AI_CHAT][api] error', { requestId, error: err }); } catch { }

      // 如果是用户主动取消，不需要处理错误
      if (err?.name === 'AbortError' || err?.message?.includes('abort')) {
        console.log('[AI_CHAT][api] Request was aborted by user');
        return;
      }

      // 验证请求是否仍然有效
      if (!isRequestValid()) {
        console.log('[AI_CHAT][api] Ignoring error from invalidated request');
        return;
      }

      setIsSending(false);
      setIsStreaming(false);
      streamAbortRef.current = null;
      pendingAssistantIdRef.current = null;
      activeRequestIdRef.current = null;

      // 流式失败时的降级：尝试一次性非流式
      try {
        // 再次验证请求有效性
        if (!isRequestValid()) return;

        const bodyNoStream = { ...body, stream: false };
        try { console.log('[AI_CHAT][fallback] try non-stream', { requestId }); } catch { }
        const resp = await api.post<{ conversationId?: string; text: string }>('/api/ai-coach/chat', bodyNoStream);

        // 最终验证请求有效性
        if (!isRequestValid()) return;

        const textCombined = (resp as any)?.text ?? '';
        if ((resp as any)?.conversationId && !conversationId) {
          setConversationId((resp as any).conversationId);
        }
        setMessages((prev) => prev.map((msg) => msg.id === assistantId ? { ...msg, content: textCombined || '（空响应）' } : msg));
      } catch (e2: any) {
        // 如果也是取消操作，同样不处理
        if (e2?.name === 'AbortError' || e2?.message?.includes('abort')) {
          return;
        }
        // 验证请求有效性
        if (!isRequestValid()) return;

        setMessages((prev) => prev.map((msg) => msg.id === assistantId ? { ...msg, content: '抱歉，请求失败，请稍后再试。' } : msg));
        try { console.warn('[AI_CHAT][fallback] non-stream error', { requestId, error: e2 }); } catch { }
      }
    };

    try {
      const controller = postTextStream('/api/ai-coach/chat', body, { onChunk, onEnd, onError }, { timeoutMs: 120000 });
      streamAbortRef.current = controller;
    } catch (e) {
      onError(e);
    }
  }

  async function send(text: string) {
    if (!isLoggedIn) {
      pushIfAuthedElseLogin('/auth/login');
      return;
    }
    if (isSending) return;
    const trimmed = text.trim();
    if (!trimmed && selectedImages.length === 0) return;

    // 检查是否有图片还在上传中
    const uploadingImages = selectedImages.filter(img => !img.uploadedUrl && !img.error);
    if (uploadingImages.length > 0) {
      Alert.alert('请稍等', '图片正在上传中，请等待上传完成后再发送');
      return;
    }

    // 检查是否有上传失败的图片
    const failedImages = selectedImages.filter(img => img.error);
    if (failedImages.length > 0) {
      Alert.alert('上传失败', '部分图片上传失败，请重新选择或删除失败的图片');
      return;
    }

    try {
      const imageUrls = selectedImages.map(img => img.uploadedUrl).filter(Boolean) as string[];
      setInput('');
      setSelectedImages([]);
      await sendStream(trimmed, imageUrls);
    } catch (e: any) {
      Alert.alert('发送失败', e?.message || '消息发送失败，请稍后重试');
    }
  }


  const uploadImage = useCallback(async (img: any) => {
    if (!img?.localUri || !img?.id) {
      console.warn('[AI_CHAT] Invalid image data for upload:', img);
      return;
    }

    try {
      const { url } = await upload(
        { uri: img.localUri, name: img.id, type: 'image/jpeg' },
        { prefix: 'images/chat' }
      );

      if (url) {
        setSelectedImages((prev) => prev.map((it) =>
          it.id === img.id ? { ...it, uploadedUrl: url, progress: 1, error: undefined } : it
        ));
      } else {
        throw new Error('上传返回空URL');
      }
    } catch (e: any) {
      console.error('[AI_CHAT] Image upload failed:', e);
      setSelectedImages((prev) => prev.map((it) =>
        it.id === img.id ? { ...it, error: e?.message || '上传失败', progress: 0 } : it
      ));
    }
  }, [upload]);

  const pickImages = useCallback(async () => {
    try {
      const result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ['images'],
        allowsMultipleSelection: true,
        selectionLimit: 4,
        quality: 0.9,
      } as any);

      if ((result as any).canceled) return;

      const assets = (result as any).assets || [];
      if (!Array.isArray(assets) || assets.length === 0) {
        console.warn('[AI_CHAT] No valid assets returned from image picker');
        return;
      }

      const next = assets
        .filter(a => a && a.uri) // 过滤无效的资源
        .map((a: any) => ({
          id: `${a.assetId || a.fileName || Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
          localUri: a.uri,
          width: a.width,
          height: a.height,
          progress: 0,
        }));

      if (next.length === 0) {
        Alert.alert('错误', '未选择有效的图片');
        return;
      }

      setSelectedImages((prev) => {
        const merged = [...prev, ...next];
        return merged.slice(0, 4);
      });

      setTimeout(scrollToEnd, 100);

      // 立即开始上传新选择的图片
      for (const img of next) {
        uploadImage(img);
      }
    } catch (e: any) {
      console.error('[AI_CHAT] Image picker error:', e);
      Alert.alert('错误', e?.message || '选择图片失败');
    }
  }, [scrollToEnd, uploadImage]);

  const removeSelectedImage = useCallback((id: string) => {
    setSelectedImages((prev) => prev.filter((it) => it.id !== id));
  }, []);

  // 渲染单个附件
  function renderAttachment(attachment: MessageAttachment, isUser: boolean) {
    const { type, url, localUri, uploadProgress, uploadError, width, height, filename } = attachment;

    if (type === 'image') {
      const imageUri = url || localUri;
      if (!imageUri) return null;

      return (
        <View key={attachment.id} style={styles.attachmentContainer}>
          <TouchableOpacity
            accessibilityRole="imagebutton"
            onPress={() => setPreviewImageUri(imageUri)}
            style={styles.imageAttachment}
          >
            <Image
              source={{ uri: imageUri }}
              style={[
                styles.attachmentImage,
                width && height ? { aspectRatio: width / height } : {}
              ]}
              resizeMode="cover"
            />
            {uploadProgress !== undefined && uploadProgress < 1 && (
              <View style={styles.attachmentProgressOverlay}>
                <Text style={styles.attachmentProgressText}>
                  {Math.round(uploadProgress * 100)}%
                </Text>
              </View>
            )}
            {uploadError && (
              <View style={styles.attachmentErrorOverlay}>
                <Text style={styles.attachmentErrorText}>上传失败</Text>
              </View>
            )}
          </TouchableOpacity>
        </View>
      );
    }

    if (type === 'video') {
      // 视频附件的实现
      return (
        <View key={attachment.id} style={styles.attachmentContainer}>
          <TouchableOpacity style={styles.videoAttachment}>
            <View style={styles.videoPlaceholder}>
              <Ionicons name="play-circle" size={48} color="rgba(255,255,255,0.9)" />
              <Text style={styles.videoFilename}>{filename || '视频文件'}</Text>
            </View>
          </TouchableOpacity>
        </View>
      );
    }

    if (type === 'file') {
      // 文件附件的实现
      return (
        <View key={attachment.id} style={styles.attachmentContainer}>
          <TouchableOpacity style={styles.fileAttachment}>
            <Ionicons name="document-outline" size={24} color="#687076" />
            <Text style={styles.fileFilename} numberOfLines={1}>
              {filename || 'unknown_file'}
            </Text>
          </TouchableOpacity>
        </View>
      );
    }

    return null;
  }

  // 渲染所有附件
  function renderAttachments(attachments: MessageAttachment[], isUser: boolean) {
    if (!attachments || attachments.length === 0) return null;

    return (
      <View style={styles.attachmentsContainer}>
        {attachments.map(attachment => renderAttachment(attachment, isUser))}
      </View>
    );
  }

  function renderItem({ item }: { item: ChatMessage }) {
    const isUser = item.role === 'user';
    return (
      <Animated.View
        entering={isUser ? FadeInUp.springify().damping(18) : FadeInDown.springify().damping(18)}
        layout={Layout.springify().damping(18)}
        style={[styles.row, { justifyContent: isUser ? 'flex-end' : 'flex-start' }]}
      >
        <View
          style={[
            styles.bubble,
            {
              backgroundColor: isUser ? theme.primary : 'rgba(187,242,70,0.16)',
              borderTopLeftRadius: isUser ? 16 : 6,
              borderTopRightRadius: isUser ? 6 : 16,
              maxWidth: isUser ? '82%' : '90%',
            },
          ]}
        >
          {renderBubbleContent(item)}
          {renderAttachments(item.attachments || [], isUser)}
        </View>

      </Animated.View>
    );
  }

  function renderBubbleContent(item: ChatMessage) {
    if (!item.content?.trim() && isStreaming && pendingAssistantIdRef.current === item.id) {
      return (
        <View style={styles.streamingContainer}>
          <Text style={[styles.bubbleText, { color: '#687076' }]}>正在思考…</Text>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={cancelCurrentRequest}
            style={styles.cancelStreamBtn}
          >
            <Ionicons name="stop-circle" size={20} color="#FF4444" />
            <Text style={styles.cancelStreamText}>取消</Text>
          </TouchableOpacity>
        </View>
      );
    }

    if (item.content?.startsWith(CardType.WEIGHT_INPUT)) {
      const cardId = item.id;
      const preset = (() => {
        try {
          const m = item.content.split('\n')?.[1];
          const v = parseFloat(m || '');
          return isNaN(v) ? '' : String(v);
        } catch {
          return '';
        }
      })();

      // 初始化输入值（如果还没有的话）
      const currentValue = weightInputs[cardId] ?? preset;

      return (
        <View style={{ gap: 8 }}>
          <Text style={[styles.bubbleText, { color: '#192126', fontWeight: '700' }]}>记录今日体重</Text>
          <View style={styles.weightRow}>
            <TextInput
              placeholder="例如 60.5"
              keyboardType="decimal-pad"
              value={currentValue}
              placeholderTextColor={'#687076'}
              style={styles.weightInput}
              onChangeText={(text) => setWeightInputs(prev => ({ ...prev, [cardId]: text }))}
              onSubmitEditing={(e) => handleSubmitWeight(e.nativeEvent.text, cardId)}
              returnKeyType="done"
              submitBehavior="blurAndSubmit"
            />
            <Text style={styles.weightUnit}>kg</Text>
            <TouchableOpacity
              accessibilityRole="button"
              style={styles.weightSaveBtn}
              onPress={() => handleSubmitWeight(currentValue, cardId)}
            >
              <Text style={{ color: '#192126', fontWeight: '700' }}>记录</Text>
            </TouchableOpacity>
          </View>
          <Text style={{ color: '#687076', fontSize: 12 }}>按回车或点击保存，即可将该体重同步到账户并发送到对话。</Text>
        </View>
      );
    }

    if (item.content?.startsWith(CardType.DIET_INPUT)) {
      return (
        <View style={{ gap: 12 }}>
          <Text style={[styles.bubbleText, { color: '#192126', fontWeight: '700' }]}>记录今日饮食</Text>
          <Text style={{ color: '#687076', fontSize: 14 }}>请选择记录方式：</Text>

          <View style={styles.dietOptionsContainer}>
            <TouchableOpacity
              accessibilityRole="button"
              style={styles.dietOptionBtn}
              onPress={() => handleDietTextInput(item.id)}
            >
              <View style={styles.dietOptionIconContainer}>
                <Ionicons name="create-outline" size={20} color="#192126" />
              </View>
              <View style={styles.dietOptionTextContainer}>
                <Text style={styles.dietOptionTitle}>文字记录</Text>
                <Text style={styles.dietOptionDesc}>输入吃了什么、大概多少克</Text>
              </View>
            </TouchableOpacity>

            <TouchableOpacity
              accessibilityRole="button"
              style={styles.dietOptionBtn}
              onPress={() => handleDietPhotoInput(item.id)}
            >
              <View style={styles.dietOptionIconContainer}>
                <Ionicons name="camera-outline" size={20} color="#192126" />
              </View>
              <View style={styles.dietOptionTextContainer}>
                <Text style={styles.dietOptionTitle}>拍照识别</Text>
                <Text style={styles.dietOptionDesc}>拍摄食物照片进行AI分析</Text>
              </View>
            </TouchableOpacity>
          </View>

          <Text style={{ color: '#687076', fontSize: 12 }}>选择合适的方式记录您的饮食，海豹助手会根据您的饮食情况给出专业的营养建议。</Text>
        </View>
      );
    }

    if (item.content?.startsWith(CardType.DIET_TEXT_INPUT)) {
      const cardId = item.content.split('\n')?.[1] || '';
      const currentText = dietTextInputs[cardId] || '';

      return (
        <View style={{ gap: 8 }}>
          <View style={styles.dietInputHeader}>
            <Text style={[styles.bubbleText, { color: '#192126', fontWeight: '700' }]}>文字记录饮食</Text>
            <TouchableOpacity
              accessibilityRole="button"
              onPress={() => handleBackToDietOptions(cardId)}
              style={styles.dietBackBtn}
            >
              <Ionicons name="arrow-back" size={16} color="#687076" />
            </TouchableOpacity>
          </View>

          <TextInput
            placeholder="例如：午餐吃了一碗米饭(150g)、红烧肉(100g)、青菜(80g)"
            placeholderTextColor={'#687076'}
            style={styles.dietTextInput}
            multiline
            numberOfLines={3}
            value={currentText}
            onChangeText={(text) => setDietTextInputs(prev => ({ ...prev, [cardId]: text }))}
            returnKeyType="done"
          />

          <TouchableOpacity
            accessibilityRole="button"
            style={[styles.dietSubmitBtn, { opacity: currentText.trim() ? 1 : 0.5 }]}
            disabled={!currentText.trim()}
            onPress={() => handleSubmitDietText(currentText, cardId)}
          >
            <Text style={{ color: '#192126', fontWeight: '700' }}>发送记录</Text>
          </TouchableOpacity>

          <Text style={{ color: '#687076', fontSize: 12 }}>详细描述您的饮食内容和分量，有助于海豹助手给出更精准的营养分析和建议。</Text>
        </View>
      );
    }

    // 在流式回复过程中显示取消按钮
    if (isStreaming && pendingAssistantIdRef.current === item.id && item.content?.trim()) {
      return (
        <View style={{ gap: 8 }}>
          <Markdown style={markdownStyles} mergeStyle>
            {item.content}
          </Markdown>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={cancelCurrentRequest}
            style={styles.cancelStreamBtn}
          >
            <Ionicons name="stop-circle" size={16} color="#FF4444" />
            <Text style={styles.cancelStreamText}>停止生成</Text>
          </TouchableOpacity>
        </View>
      );
    }

    // 检查是否有选择选项需要显示
    if (item.choices && item.choices.length > 0 && item.interactionType === 'food_confirmation') {
      return (
        <View style={{ gap: 12 }}>
          <Markdown style={markdownStyles} mergeStyle>
            {item.content || ''}
          </Markdown>
          <View style={styles.choicesContainer}>
            {item.choices.map((choice) => {
              const isSelected = selectedChoices[item.id] === choice.id;
              const isAnySelected = selectedChoices[item.id] != null;
              const isPending = pendingChoiceConfirmation[item.id];
              const isDisabled = isAnySelected && !isSelected;

              return (
                <TouchableOpacity
                  key={choice.id}
                  accessibilityRole="button"
                  disabled={isDisabled || isPending}
                  style={[
                    styles.choiceButton,
                    choice.recommended && styles.choiceButtonRecommended,
                    isSelected && styles.choiceButtonSelected,
                    isDisabled && styles.choiceButtonDisabled,
                  ]}
                  onPress={() => {
                    if (!isDisabled && !isPending) {
                      Haptics.selectionAsync();
                      handleChoiceSelection(choice, item);
                    }
                  }}
                >
                  <View style={styles.choiceContent}>
                    <Text style={[
                      styles.choiceLabel,
                      choice.recommended && styles.choiceLabelRecommended,
                      isSelected && styles.choiceLabelSelected,
                      isDisabled && styles.choiceLabelDisabled,
                    ]}>
                      {choice.label}
                    </Text>
                    <View style={styles.choiceStatusContainer}>
                      {choice.recommended && !isSelected && (
                        <View style={styles.recommendedBadge}>
                          <Text style={styles.recommendedText}>推荐</Text>
                        </View>
                      )}
                      {isSelected && isPending && (
                        <ActivityIndicator size="small" color="#2D5016" />
                      )}
                      {isSelected && !isPending && (
                        <View style={styles.selectedBadge}>
                          <Text style={styles.selectedText}>已选择</Text>
                        </View>
                      )}
                    </View>
                  </View>
                </TouchableOpacity>
              );
            })}
          </View>
        </View>
      );
    }

    return (
      <Markdown style={markdownStyles} mergeStyle>
        {item.content || ''}
      </Markdown>
    );
  }

  function insertWeightInputCard() {
    const id = `wcard_${Date.now()}`;
    const preset = userProfile?.weight ? Number(userProfile.weight) : undefined;
    const payload = `${CardType.WEIGHT_INPUT}\n${preset ?? ''}`;
    setMessages((prev) => [...prev, { id, role: 'assistant', content: payload }]);
    setTimeout(scrollToEnd, 100);
  }

  async function handleSubmitWeight(text?: string, cardId?: string) {
    const val = parseFloat(String(text ?? '').trim());
    if (isNaN(val) || val <= 0 || val > 500) {
      Alert.alert('请输入有效体重', '请填写合理的公斤数，例如 60.5');
      return;
    }

    try {
      // 清理该卡片的输入状态
      if (cardId) {
        setWeightInputs(prev => {
          const { [cardId]: _, ...rest } = prev;
          return rest;
        });

        // 移除体重输入卡片
        setMessages((prev) => prev.filter(msg => msg.id !== cardId));
      }

      // 在对话中插入"确认消息"并发送给教练
      const textMsg = `#记体重：\n\n${val} kg`;
      await sendStream(textMsg);
    } catch (e: any) {
      console.error('[AI_CHAT] Error handling weight submission:', e);
      Alert.alert('保存失败', e?.message || '请稍后重试');
    }
  }

  function insertDietInputCard() {
    const id = `dcard_${Date.now()}`;
    const payload = `${CardType.DIET_INPUT}\n${id}`;
    setMessages((prev) => [...prev, { id, role: 'assistant', content: payload }]);
    setTimeout(scrollToEnd, 100);
  }

  function handleDietTextInput(cardId: string) {
    // 替换当前的饮食选择卡片为文字输入卡片
    const payload = `${CardType.DIET_TEXT_INPUT}\n${cardId}`;
    setMessages((prev) => prev.map(msg =>
      msg.id === cardId
        ? { ...msg, content: payload }
        : msg
    ));
    setTimeout(scrollToEnd, 100);
  }

  function handleDietPhotoInput(cardId: string) {
    console.log('[DIET] handleDietPhotoInput called with cardId:', cardId);
    setCurrentCardId(cardId);
    setShowDietPhotoActionSheet(true);
  }

  async function handleCameraPhoto() {
    try {
      const permissionResult = await ImagePicker.requestCameraPermissionsAsync();
      if (permissionResult.status !== 'granted') {
        Alert.alert('权限不足', '需要相机权限以拍摄食物照片');
        return;
      }

      const result = await ImagePicker.launchCameraAsync({
        mediaTypes: ['images'],
        allowsEditing: true,
        quality: 0.9,
        aspect: [4, 3],
      });

      if (!result.canceled && result.assets?.[0]) {
        await processSelectedImage(result.assets[0]);
      }
    } catch (e: any) {
      console.error('[DIET] 拍照失败:', e);
      Alert.alert('拍照失败', e?.message || '拍照失败，请重试');
    }
  }

  async function handleLibraryPhoto() {
    try {
      const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
      if (permissionResult.status !== 'granted') {
        Alert.alert('权限不足', '需要相册权限以选择食物照片');
        return;
      }

      const result = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ['images'],
        allowsEditing: true,
        quality: 0.9,
        aspect: [4, 3],
      });

      if (!result.canceled && result.assets?.[0]) {
        await processSelectedImage(result.assets[0]);
      }
    } catch (e: any) {
      console.error('[DIET] 选择照片失败:', e);
      Alert.alert('选择照片失败', e?.message || '选择照片失败，请重试');
    }
  }

  async function processSelectedImage(asset: ImagePicker.ImagePickerAsset) {
    if (!currentCardId) return;

    try {
      // 上传图片
      const { url } = await upload(
        { uri: asset.uri, name: `diet-${Date.now()}.jpg`, type: 'image/jpeg' },
        { prefix: 'images/diet' }
      );

      // 移除饮食选择卡片
      setMessages((prev) => prev.filter(msg => msg.id !== currentCardId));

      // 发送包含图片的饮食记录消息，图片通过 imageUrls 参数传递
      const dietMsg = `#记饮食：请分析这张食物照片的营养成分和热量`;
      await sendStream(dietMsg, [url]);
    } catch (uploadError) {
      console.error('[DIET] 图片上传失败:', uploadError);
      Alert.alert('上传失败', '图片上传失败，请重试');
    }
  }

  function handleBackToDietOptions(cardId: string) {
    // 返回到饮食选择界面
    const payload = `${CardType.DIET_INPUT}\n${cardId}`;
    setMessages((prev) => prev.map(msg =>
      msg.id === cardId
        ? { ...msg, content: payload }
        : msg
    ));
    setTimeout(scrollToEnd, 100);
  }

  async function handleSubmitDietText(text: string, cardId: string) {
    const trimmedText = text.trim();
    if (!trimmedText) {
      Alert.alert('请输入饮食内容', '请描述您吃了什么食物和大概的分量');
      return;
    }

    try {
      // 移除饮食输入卡片
      setMessages((prev) => prev.filter(msg => msg.id !== cardId));

      // 清理输入状态
      setDietTextInputs(prev => {
        const { [cardId]: _, ...rest } = prev;
        return rest;
      });

      // 发送饮食记录消息
      const dietMsg = `记录了今日饮食：${trimmedText}`;
      await sendStream(dietMsg);
    } catch (e: any) {
      console.error('[DIET] 提交饮食记录失败:', e);
      Alert.alert('提交失败', e?.message || '提交失败，请重试');
    }
  }

  async function handleChoiceSelection(choice: AiChoiceOption, message: ChatMessage) {
    try {
      console.log('[CHOICE] Selection:', { choiceId: choice.id, messageId: message.id });

      // 检查是否已经选择过
      if (selectedChoices[message.id] != null) {
        console.log('[CHOICE] Already selected, ignoring');
        return;
      }

      // 立即设置选中状态，防止重复点击
      setSelectedChoices(prev => ({ ...prev, [message.id]: choice.id }));
      setPendingChoiceConfirmation(prev => ({ ...prev, [message.id]: true }));

      // 构建确认请求
      const confirmationText = `我选择记录${choice.label}`;

      try {
        // 发送确认消息，包含选择的数据
        await sendStreamWithConfirmation(confirmationText, choice.id, {
          selectedOption: choice.value,
          imageUrl: message.pendingData?.imageUrl
        });

        // 发送成功后，清除pending状态但保持选中状态
        setPendingChoiceConfirmation(prev => ({ ...prev, [message.id]: false }));

        // 成功反馈
        Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);

      } catch (e: any) {
        console.error('[CHOICE] Selection failed:', e);

        // 发送失败时，重置状态允许重新选择
        setSelectedChoices(prev => {
          const { [message.id]: _, ...rest } = prev;
          return rest;
        });
        setPendingChoiceConfirmation(prev => {
          const { [message.id]: _, ...rest } = prev;
          return rest;
        });

        Alert.alert('选择失败', e?.message || '选择失败，请重试');

        // 失败反馈
        Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);
      }

    } catch (e: any) {
      console.error('[CHOICE] Selection failed:', e);
      Alert.alert('选择失败', e?.message || '选择失败，请重试');
    }
  }

  return (
    <View style={[styles.screen, { backgroundColor: theme.background }]}>
      {/* 顶部标题区域，显示教练名称、新建会话和历史按钮 */}
      <View
        style={[styles.header, { paddingTop: insets.top + 10 }]}
        onLayout={(e) => {
          const h = e.nativeEvent.layout.height;
          if (h && Math.abs(h - headerHeight) > 0.5) setHeaderHeight(h);
        }}
      >
        <Text style={[styles.headerTitle, { color: theme.text }]}>{botName}</Text>
        <View style={styles.headerActions}>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={startNewConversation}
            style={[styles.headerActionButton, { backgroundColor: 'rgba(187,242,70,0.2)' }]}
          >
            <Ionicons name="add-outline" size={18} color={theme.onPrimary} />
          </TouchableOpacity>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={openHistory}
            style={[styles.headerActionButton, { backgroundColor: 'rgba(187,242,70,0.2)' }]}
          >
            <Ionicons name="time-outline" size={18} color={theme.onPrimary} />
          </TouchableOpacity>
        </View>
      </View>

      {/* 消息列表容器 - 设置固定高度避免输入框重叠 */}
      <View style={{
        flex: 1,
        marginBottom: composerHeight + keyboardOffset
      }}>
        <FlatList
          ref={listRef}
          data={messages}
          keyExtractor={(m) => m.id}
          renderItem={renderItem}
          onLayout={() => {
            // 确保首屏布局后也尝试滚动
            if (!didInitialScrollRef.current) {
              didInitialScrollRef.current = true;
              setTimeout(scrollToEnd, 100);
            }
          }}
          contentContainerStyle={{
            paddingHorizontal: 14,
            paddingTop: 8,
            paddingBottom: 16
          }}
          onContentSizeChange={() => {
            // 首次内容变化强制滚底，其余仅在接近底部时滚动
            if (!didInitialScrollRef.current) {
              didInitialScrollRef.current = true;
              setTimeout(scrollToEnd, 100);
              return;
            }
            if (shouldAutoScrollRef.current) {
              shouldAutoScrollRef.current = false;
              setTimeout(scrollToEnd, 50);
            }
          }}
          onScroll={handleScroll}
          scrollEventThrottle={16}
          showsVerticalScrollIndicator={false}
        />
      </View>

      <BlurView
        intensity={18}
        tint={'light'}
        style={[styles.composerWrap, { paddingBottom: getTabBarBottomPadding() + 10, bottom: keyboardOffset }]}
        onLayout={(e) => {
          const h = e.nativeEvent.layout.height;
          if (h && Math.abs(h - composerHeight) > 0.5) setComposerHeight(h);
        }}
      >
        <ScrollView
          horizontal
          showsHorizontalScrollIndicator={false}
          decelerationRate="fast"
          snapToAlignment="start"
          style={styles.chipsRowScroll}
          contentContainerStyle={{ paddingHorizontal: 6, gap: 8 }}
        >
          {chips.map((c) => (
            <TouchableOpacity key={c.key} style={[styles.chip, { borderColor: 'rgba(187,242,70,0.35)', backgroundColor: 'rgba(187,242,70,0.12)' }]} onPress={c.action}>
              <Text style={[styles.chipText, { color: '#192126' }]}>{c.label}</Text>
            </TouchableOpacity>
          ))}
        </ScrollView>

        {!!selectedImages.length && (
          <ScrollView
            horizontal
            showsHorizontalScrollIndicator={false}
            style={styles.imagesRow}
            contentContainerStyle={{ paddingHorizontal: 6, gap: 8 }}
          >
            {selectedImages.map((img) => (
              <View key={img.id} style={styles.imageThumbWrap}>
                <TouchableOpacity accessibilityRole="imagebutton" onPress={() => setPreviewImageUri(img.uploadedUrl || img.localUri)}>
                  <Image source={{ uri: img.uploadedUrl || img.localUri }} style={styles.imageThumb} />
                </TouchableOpacity>
                {!!(img.progress > 0 && img.progress < 1) && (
                  <View style={styles.imageProgressOverlay}>
                    <Text style={styles.imageProgressText}>{Math.round((img.progress || 0) * 100)}%</Text>
                  </View>
                )}
                {img.error && (
                  <View style={styles.imageErrorOverlay}>
                    <TouchableOpacity
                      accessibilityRole="button"
                      onPress={() => uploadImage(img)}
                      style={styles.imageRetryBtn}
                    >
                      <Ionicons name="refresh" size={12} color="#fff" />
                    </TouchableOpacity>
                  </View>
                )}
                <TouchableOpacity accessibilityRole="button" onPress={() => removeSelectedImage(img.id)} style={styles.imageRemoveBtn}>
                  <Ionicons name="close" size={12} color="#fff" />
                </TouchableOpacity>
              </View>
            ))}
          </ScrollView>
        )}

        <View style={[styles.inputRow, { borderColor: 'rgba(187,242,70,0.35)', backgroundColor: 'rgba(187,242,70,0.08)' }]}>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={pickImages}
            style={[styles.mediaBtn, { backgroundColor: 'rgba(187,242,70,0.16)' }]}
          >
            <Ionicons name="image-outline" size={18} color={'#192126'} />
          </TouchableOpacity>
          <TextInput
            placeholder="问我任何健康相关的问题，如营养、健身、生活管理等..."
            placeholderTextColor={theme.textMuted}
            style={[styles.input, { color: '#192126' }]}
            value={input}
            onChangeText={setInput}
            multiline
            onSubmitEditing={() => send(input)}
            submitBehavior="blurAndSubmit"
          />
          <TouchableOpacity
            accessibilityRole="button"
            disabled={(!input.trim() && selectedImages.length === 0) && !isSending}
            onPress={() => {
              if (isSending || isStreaming) {
                cancelCurrentRequest();
              } else {
                send(input);
              }
            }}
            style={[
              styles.sendBtn,
              {
                backgroundColor: (isSending || isStreaming) ? '#FF4444' : theme.primary,
                opacity: ((input.trim() || selectedImages.length > 0) || (isSending || isStreaming)) ? 1 : 0.5
              }
            ]}
          >
            {isSending ? (
              <Ionicons name="stop" size={18} color="#fff" />
            ) : isStreaming ? (
              <Ionicons name="stop" size={18} color="#fff" />
            ) : (
              <Ionicons name="arrow-up" size={18} color={theme.onPrimary} />
            )}
          </TouchableOpacity>
        </View>
      </BlurView>

      {!isAtBottom && (
        <TouchableOpacity
          accessibilityRole="button"
          onPress={scrollToEnd}
          style={[styles.scrollToBottomFab, {
            bottom: composerHeight + keyboardOffset + 10,
            backgroundColor: theme.primary
          }]}
        >
          <Ionicons name="chevron-down" size={18} color={theme.onPrimary} />
        </TouchableOpacity>
      )}

      <Modal transparent visible={historyVisible} animationType="fade" onRequestClose={() => setHistoryVisible(false)}>
        <TouchableOpacity activeOpacity={1} style={styles.modalBackdrop} onPress={() => setHistoryVisible(false)}>
          <View style={[styles.modalSheet, { backgroundColor: '#FFFFFF' }]}>
            <View style={styles.modalHeader}>
              <Text style={styles.modalTitle}>历史会话</Text>
              <TouchableOpacity accessibilityRole="button" onPress={() => refreshHistory(historyPage)} style={styles.modalRefreshBtn}>
                <Ionicons name="refresh" size={16} color="#192126" />
              </TouchableOpacity>
            </View>
            {historyLoading ? (
              <View style={{ paddingVertical: 20, alignItems: 'center' }}>
                <ActivityIndicator />
                <Text style={{ marginTop: 8, color: '#687076' }}>加载中...</Text>
              </View>
            ) : (
              <ScrollView style={{ maxHeight: 360 }}>
                {historyItems.length === 0 ? (
                  <Text style={{ padding: 16, color: '#687076' }}>暂无会话</Text>
                ) : (
                  historyItems.map((it) => (
                    <View key={it.conversationId} style={styles.historyRow}>
                      <TouchableOpacity
                        style={{ flex: 1 }}
                        onPress={() => handleSelectConversation(it.conversationId)}
                      >
                        <Text style={styles.historyTitle} numberOfLines={1}>{it.title || '未命名会话'}</Text>
                        <Text style={styles.historyMeta}>
                          {dayjs(it.lastMessageAt || it.createdAt).format('YYYY/MM/DD HH:mm')}
                        </Text>
                      </TouchableOpacity>
                      <TouchableOpacity accessibilityRole="button" onPress={() => confirmDeleteConversation(it.conversationId)} style={styles.historyDeleteBtn}>
                        <Ionicons name="trash-outline" size={16} color="#FF4444" />
                      </TouchableOpacity>
                    </View>
                  ))
                )}
              </ScrollView>
            )}
            <View style={styles.modalFooter}>
              <TouchableOpacity accessibilityRole="button" onPress={() => setHistoryVisible(false)} style={styles.modalCloseBtn}>
                <Text style={{ color: '#192126', fontWeight: '600' }}>关闭</Text>
              </TouchableOpacity>
            </View>
          </View>
        </TouchableOpacity>
      </Modal>
      <Modal transparent visible={!!previewImageUri} animationType="fade" onRequestClose={() => setPreviewImageUri(null)}>
        <TouchableOpacity activeOpacity={1} style={styles.previewBackdrop} onPress={() => setPreviewImageUri(null)}>
          <View style={styles.previewBox}>
            {previewImageUri ? (
              <Image source={{ uri: previewImageUri }} style={styles.previewImage} resizeMode="contain" />
            ) : null}
          </View>
        </TouchableOpacity>
      </Modal>
      <ActionSheet
        visible={showDietPhotoActionSheet}
        onClose={() => setShowDietPhotoActionSheet(false)}
        title="选择图片来源"
        options={[
          { id: 'camera', title: '拍照', onPress: handleCameraPhoto },
          { id: 'library', title: '从相册选择', onPress: handleLibraryPhoto },
        ]}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  screen: {
    flex: 1,
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingHorizontal: 16,
    paddingBottom: 10,
  },
  headerTitle: {
    fontSize: 20,
    fontWeight: '800',
  },
  headerActions: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  headerActionButton: {
    width: 32,
    height: 32,
    borderRadius: 16,
    alignItems: 'center',
    justifyContent: 'center',
  },
  historyButton: {
    width: 32,
    height: 32,
    borderRadius: 16,
    alignItems: 'center',
    justifyContent: 'center',
  },
  row: {
    flexDirection: 'row',
    alignItems: 'flex-end',
    gap: 8,
    marginVertical: 6,
  },
  avatar: {
    width: 28,
    height: 28,
    borderRadius: 14,
    alignItems: 'center',
    justifyContent: 'center',
  },
  avatarText: {
    color: '#192126',
    fontSize: 12,
    fontWeight: '800',
  },
  bubble: {
    paddingHorizontal: 12,
    paddingVertical: 10,
    borderRadius: 16,
  },
  bubbleText: {
    fontSize: 15,
    lineHeight: 22,
  },
  weightRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  weightInput: {
    flex: 1,
    height: 36,
    borderWidth: 1,
    borderColor: 'rgba(0,0,0,0.08)',
    borderRadius: 8,
    paddingHorizontal: 10,
    backgroundColor: 'rgba(255,255,255,0.9)',
    color: '#192126',
  },
  weightUnit: {
    color: '#192126',
    fontWeight: '700',
  },
  weightSaveBtn: {
    height: 36,
    paddingHorizontal: 12,
    borderRadius: 8,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(187,242,70,0.6)'
  },
  dietOptionsContainer: {
    gap: 8,
  },
  dietOptionBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    borderRadius: 12,
    backgroundColor: 'rgba(255,255,255,0.9)',
    borderWidth: 1,
    borderColor: 'rgba(187,242,70,0.3)',
  },
  dietOptionIconContainer: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: 'rgba(187,242,70,0.2)',
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 12,
  },
  dietOptionTextContainer: {
    flex: 1,
  },
  dietOptionTitle: {
    fontSize: 15,
    fontWeight: '700',
    color: '#192126',
  },
  dietOptionDesc: {
    fontSize: 13,
    color: '#687076',
    marginTop: 2,
  },
  dietInputHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  dietBackBtn: {
    width: 28,
    height: 28,
    borderRadius: 14,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.06)',
  },
  dietTextInput: {
    minHeight: 80,
    borderWidth: 1,
    borderColor: 'rgba(0,0,0,0.08)',
    borderRadius: 12,
    paddingHorizontal: 12,
    paddingVertical: 10,
    backgroundColor: 'rgba(255,255,255,0.9)',
    color: '#192126',
    fontSize: 15,
    textAlignVertical: 'top',
  },
  dietSubmitBtn: {
    height: 40,
    paddingHorizontal: 16,
    borderRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(187,242,70,0.6)',
    alignSelf: 'flex-end',
  },
  // markdown 基础样式承载容器的字体尺寸保持与气泡一致
  composerWrap: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    paddingTop: 8,
    paddingHorizontal: 10,
    borderTopWidth: 0,
  },
  chipsRow: {
    flexDirection: 'row',
    gap: 8,
    paddingHorizontal: 6,
    marginBottom: 8,
  },
  chipsRowScroll: {
    marginBottom: 8,
  },
  chip: {
    paddingHorizontal: 10,
    height: 34,
    borderRadius: 18,
    borderWidth: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'transparent',
  },
  chipText: {
    fontSize: 13,
    fontWeight: '600',
  },
  imagesRow: {
    maxHeight: 92,
    marginBottom: 8,
  },
  imageThumbWrap: {
    width: 72,
    height: 72,
    borderRadius: 12,
    overflow: 'hidden',
    position: 'relative',
    backgroundColor: 'rgba(0,0,0,0.06)'
  },
  imageThumb: {
    width: '100%',
    height: '100%'
  },
  imageRemoveBtn: {
    position: 'absolute',
    right: 4,
    top: 4,
    width: 20,
    height: 20,
    borderRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.45)'
  },
  imageProgressOverlay: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.35)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  imageProgressText: {
    color: '#fff',
    fontWeight: '700'
  },
  imageErrorOverlay: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundColor: 'rgba(255,0,0,0.35)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  imageRetryBtn: {
    width: 24,
    height: 24,
    borderRadius: 12,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.6)'
  },
  inputRow: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 8,
    borderWidth: 1,
    borderRadius: 16,
    backgroundColor: 'rgba(0,0,0,0.04)'
  },
  mediaBtn: {
    width: 40,
    height: 40,
    borderRadius: 12,
    alignItems: 'center',
    justifyContent: 'center',
    marginRight: 6,
  },
  input: {
    flex: 1,
    fontSize: 15,
    maxHeight: 120,
    minHeight: 40,
    paddingHorizontal: 8,
    paddingVertical: 6,
    textAlignVertical: 'center',
  },
  sendBtn: {
    width: 40,
    height: 40,
    borderRadius: 20,
    alignItems: 'center',
    justifyContent: 'center',
  },
  scrollToBottomFab: {
    position: 'absolute',
    right: 16,
    width: 40,
    height: 40,
    borderRadius: 20,
    alignItems: 'center',
    justifyContent: 'center',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.15,
    shadowRadius: 4,
    elevation: 2,
  },
  modalBackdrop: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.35)',
    padding: 16,
    justifyContent: 'flex-end',
  },
  modalSheet: {
    borderTopLeftRadius: 16,
    borderTopRightRadius: 16,
    paddingHorizontal: 12,
    paddingTop: 10,
    paddingBottom: 12,
  },
  modalHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    paddingHorizontal: 4,
    paddingBottom: 8,
  },
  modalTitle: {
    fontSize: 16,
    fontWeight: '800',
    color: '#192126',
  },
  modalRefreshBtn: {
    width: 28,
    height: 28,
    borderRadius: 14,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.06)'
  },
  historyRow: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingVertical: 10,
    paddingHorizontal: 8,
    borderRadius: 10,
  },
  historyTitle: {
    fontSize: 15,
    color: '#192126',
    fontWeight: '600',
  },
  historyMeta: {
    marginTop: 2,
    fontSize: 12,
    color: '#687076',
  },
  historyDeleteBtn: {
    width: 28,
    height: 28,
    borderRadius: 14,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(255,68,68,0.08)'
  },
  modalFooter: {
    paddingTop: 8,
    alignItems: 'flex-end',
  },
  modalCloseBtn: {
    paddingHorizontal: 14,
    paddingVertical: 8,
    borderRadius: 10,
    backgroundColor: 'rgba(0,0,0,0.06)'
  },
  previewBackdrop: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.85)',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 16,
  },
  previewBox: {
    width: '100%',
    height: '80%',
    borderRadius: 12,
    overflow: 'hidden',
  },
  previewImage: {
    width: '100%',
    height: '100%',
  },
  // 附件相关样式
  attachmentsContainer: {
    marginTop: 8,
    gap: 6,
  },
  attachmentContainer: {
    marginBottom: 4,
  },
  imageAttachment: {
    borderRadius: 12,
    overflow: 'hidden',
    position: 'relative',
  },
  attachmentImage: {
    width: '100%',
    minHeight: 120,
    maxHeight: 200,
    borderRadius: 12,
  },
  attachmentProgressOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.4)',
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: 12,
  },
  attachmentProgressText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '600',
  },
  attachmentErrorOverlay: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(255,0,0,0.4)',
    alignItems: 'center',
    justifyContent: 'center',
    borderRadius: 12,
  },
  attachmentErrorText: {
    color: '#fff',
    fontSize: 12,
    fontWeight: '600',
  },
  videoAttachment: {
    borderRadius: 12,
    overflow: 'hidden',
    backgroundColor: 'rgba(0,0,0,0.1)',
  },
  videoPlaceholder: {
    height: 120,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.6)',
  },
  videoFilename: {
    color: '#fff',
    fontSize: 12,
    marginTop: 4,
    textAlign: 'center',
  },
  fileAttachment: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    backgroundColor: 'rgba(0,0,0,0.06)',
    borderRadius: 8,
    gap: 8,
  },
  fileFilename: {
    flex: 1,
    fontSize: 14,
    color: '#192126',
  },
  // 选择选项相关样式
  choicesContainer: {
    gap: 8,
  },
  choiceButton: {
    backgroundColor: 'rgba(255,255,255,0.9)',
    borderWidth: 1,
    borderColor: 'rgba(187,242,70,0.3)',
    borderRadius: 12,
    padding: 12,
  },
  choiceButtonRecommended: {
    borderColor: 'rgba(187,242,70,0.6)',
    backgroundColor: 'rgba(187,242,70,0.1)',
  },
  choiceButtonSelected: {
    borderColor: '#2D5016',
    backgroundColor: 'rgba(187,242,70,0.2)',
    borderWidth: 2,
  },
  choiceButtonDisabled: {
    backgroundColor: 'rgba(0,0,0,0.05)',
    borderColor: 'rgba(0,0,0,0.1)',
    opacity: 0.5,
  },
  choiceContent: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  choiceLabel: {
    fontSize: 15,
    fontWeight: '600',
    color: '#192126',
    flex: 1,
  },
  choiceLabelRecommended: {
    color: '#2D5016',
  },
  choiceLabelSelected: {
    color: '#2D5016',
    fontWeight: '700',
  },
  choiceLabelDisabled: {
    color: '#687076',
  },
  choiceStatusContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  recommendedBadge: {
    backgroundColor: 'rgba(187,242,70,0.8)',
    borderRadius: 6,
    paddingHorizontal: 8,
    paddingVertical: 2,
  },
  recommendedText: {
    fontSize: 12,
    fontWeight: '700',
    color: '#2D5016',
  },
  selectedBadge: {
    backgroundColor: '#2D5016',
    borderRadius: 6,
    paddingHorizontal: 8,
    paddingVertical: 2,
  },
  selectedText: {
    fontSize: 12,
    fontWeight: '700',
    color: '#FFFFFF',
  },
  // 流式回复相关样式
  streamingContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    gap: 12,
  },
  cancelStreamBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
    backgroundColor: 'rgba(255,68,68,0.1)',
    borderWidth: 1,
    borderColor: 'rgba(255,68,68,0.3)',
  },
  cancelStreamText: {
    fontSize: 12,
    fontWeight: '600',
    color: '#FF4444',
  },
});

const markdownStyles = {
  body: {
    color: '#192126',
    fontSize: 15,
    lineHeight: 22,
  },
  paragraph: {
    marginTop: 2,
    marginBottom: 2,
  },
  bullet_list: {
    marginVertical: 4,
  },
  ordered_list: {
    marginVertical: 4,
  },
  list_item: {
    flexDirection: 'row',
  },
  code_inline: {
    backgroundColor: 'rgba(0,0,0,0.06)',
    borderRadius: 4,
    paddingHorizontal: 4,
    paddingVertical: 2,
  },
  code_block: {
    backgroundColor: 'rgba(0,0,0,0.06)',
    borderRadius: 8,
    paddingHorizontal: 8,
    paddingVertical: 6,
  },
  fence: {
    backgroundColor: 'rgba(0,0,0,0.06)',
    borderRadius: 8,
    paddingHorizontal: 8,
    paddingVertical: 6,
  },
  heading1: { fontSize: 20, fontWeight: '800', marginVertical: 6 },
  heading2: { fontSize: 18, fontWeight: '800', marginVertical: 6 },
  heading3: { fontSize: 16, fontWeight: '800', marginVertical: 6 },
  link: { color: '#246BFD' },
} as const;
