import { Ionicons } from '@expo/vector-icons';
import * as Haptics from 'expo-haptics';
import * as ImagePicker from 'expo-image-picker';
import { LinearGradient } from 'expo-linear-gradient';
import { useLocalSearchParams } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  Alert,
  FlatList,
  Keyboard,
  Modal,
  Platform,
  StyleSheet,
  Text,
  TouchableOpacity,
  View
} from 'react-native';
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 { useColorScheme } from '@/hooks/useColorScheme';
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 { selectLatestMoodRecordByDate } from '@/store/moodSlice';
import { generateWelcomeMessage, hasRecordedMoodToday } from '@/utils/welcomeMessage';
import { Image } from 'expo-image';
import { HistoryModal } from '../../components/model/HistoryModal';
import { ActionSheet } from '../../components/ui/ActionSheet';

// 导入新的 coach 组件
import {
  CardType,
  ChatComposer,
  ChatMessage as ChatMessageComponent,
  DietInputCard,
  DietOptionsCard,
  DietPlanCard,
  WeightInputCard,
  type QuickChip,
  type SelectedImage
} from '@/components/coach';
import { AiChoiceOption, AttachmentType, ChatMessage, Role } from '@/components/coach/types';

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


// 定义路由参数类型
type CoachScreenParams = {
  name?: string;
  action?: 'diet' | 'weight' | 'mood' | 'workout';
  subAction?: 'record' | 'photo' | 'text' | 'card';
  meal?: 'breakfast' | 'lunch' | 'dinner' | 'snack';
  message?: string;
};

export default function CoachScreen() {
  const params = useLocalSearchParams<CoachScreenParams>();
  const insets = useSafeAreaInsets();

  const { isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard();
  // 为了让页面更贴近品牌主题与更亮的观感，这里使用亮色系配色
  const colorScheme = useColorScheme();
  const theme = Colors[colorScheme ?? 'light'];
  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<SelectedImage[]>([]);
  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 today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD format
  const todayMoodRecord = useAppSelector(selectLatestMoodRecordByDate(today));
  const hasRecordedMoodTodayValue = hasRecordedMoodToday(todayMoodRecord?.checkinDate);

  // 转换用户配置文件数据类型以匹配欢迎消息函数的需求
  const transformedUserProfile = userProfile ? {
    name: userProfile.name,
    weight: userProfile.weight ? Number(userProfile.weight) : undefined,
    height: userProfile.height ? Number(userProfile.height) : undefined,
    pilatesPurposes: userProfile.pilatesPurposes
  } : undefined;

  const chips: QuickChip[] = 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() },
    { key: 'dietPlan', label: '#饮食方案', action: () => insertDietPlanCard() },
    // {
    //   key: 'mood',
    //   label: '#记心情',
    //   action: () => {
    //     if (Platform.OS === 'ios') {
    //       Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
    //     }
    //     pushIfAuthedElseLogin('/mood/calendar');
    //   }
    // },
  ], [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);
  }, []);
  // 使用 ref 存储最新值以避免依赖项导致的死循环
  const latestValuesRef = useRef({
    transformedUserProfile,
    paramsName: params?.name || 'Seal',
    hasRecordedMoodTodayValue
  });

  // 更新 ref 的值
  useEffect(() => {
    latestValuesRef.current = {
      transformedUserProfile,
      paramsName: params?.name || 'Seal',
      hasRecordedMoodTodayValue
    };
  }, [transformedUserProfile, params?.name, hasRecordedMoodTodayValue]);

  // 初始化欢迎消息
  const initializeWelcomeMessage = useCallback(() => {
    const { transformedUserProfile, paramsName, hasRecordedMoodTodayValue } = latestValuesRef.current;
    const welcomeData = generateWelcomeMessage({
      userProfile: transformedUserProfile,
      hasRecordedMoodToday: hasRecordedMoodTodayValue
    });

    const welcomeMessage: ChatMessage = {
      id: 'm_welcome',
      role: 'assistant',
      content: welcomeData.content,
      choices: welcomeData.choices,
      interactionType: welcomeData.interactionType,
    };
    setMessages([welcomeMessage]);
  }, []); // 空依赖项，通过 ref 获取最新值

  // 启动页面时尝试恢复当次应用会话缓存
  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 - 100);
            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]);

  // 处理路由参数动作
  useEffect(() => {
    // 确保用户已登录且消息已加载
    if (!isLoggedIn || messages.length === 0) return;

    // 检查是否有动作参数
    if (params.action) {
      const executeAction = async () => {
        try {
          switch (params.action) {
            case 'diet':
              if (params.subAction === 'card') {
                // 插入饮食记录卡片
                insertDietInputCard();
              } else if (params.subAction === 'record' && params.message) {
                // 直接发送预设的饮食记录消息
                const mealPrefix = params.meal ? `${getMealDisplayName(params.meal)}` : '';
                const message = `#记饮食：${mealPrefix}${decodeURIComponent(params.message)}`;
                await sendStream(message);
              }
              break;

            case 'weight':
              if (params.subAction === 'card') {
                // 插入体重记录卡片
                insertWeightInputCard();
              } else if (params.subAction === 'record' && params.message) {
                // 直接发送预设的体重记录消息
                const message = `#记体重：${decodeURIComponent(params.message)}`;
                await sendStream(message);
              }
              break;

            case 'mood':
              // 跳转到心情记录页面
              pushIfAuthedElseLogin('/mood/calendar');
              break;

            default:
              console.warn('未知的动作类型:', params.action);
          }
        } catch (error) {
          console.error('执行路由动作失败:', error);
        }
      };

      // 延迟执行，确保页面已完全加载
      const timer = setTimeout(executeAction, 500);
      return () => clearTimeout(timer);
    }
  }, [params.action, params.subAction, params.meal, params.message, isLoggedIn, messages.length]);

  // 获取餐次显示名称
  const getMealDisplayName = (meal: string): string => {
    const mealNames: Record<string, string> = {
      breakfast: '早餐',
      lunch: '午餐',
      dinner: '晚餐',
      snack: '加餐'
    };
    return mealNames[meal] || '';
  };

  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);
      if (mapped.length) {
        setMessages(mapped);
      } else {
        const welcomeData = generateWelcomeMessage({
          userProfile: transformedUserProfile,
          hasRecordedMoodToday: hasRecordedMoodTodayValue
        });
        setMessages([{
          id: 'm_welcome',
          role: 'assistant',
          content: welcomeData.content,
          choices: welcomeData.choices,
          interactionType: welcomeData.interactionType,
        }]);
      }
      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);
              const welcomeData = generateWelcomeMessage({
                userProfile: transformedUserProfile,
                hasRecordedMoodToday: hasRecordedMoodTodayValue
              });
              setMessages([{
                id: 'm_welcome',
                role: 'assistant',
                content: welcomeData.content,
                choices: welcomeData.choices,
                interactionType: welcomeData.interactionType,
              }]);
            }
            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[] = []) {
    console.log('[SEND_STREAM] 开始发送消息:', { text, imageUrls });

    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,
    };

    console.log('[SEND_STREAM] 请求体:', { body });
    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,
    }));

    console.log('[AI_CHAT][ui] 构建用户消息:', {
      userMsgId,
      text,
      imageUrls,
      attachments: attachments.length > 0 ? attachments : undefined
    });

    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 = await 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 renderItem({ item }: { item: ChatMessage }) {
    const isUser = item.role === 'user';

    // 处理特殊卡片类型
    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 '';
        }
      })();


      return (
        <Animated.View
          entering={FadeInDown.springify().damping(18)}
          layout={Layout.springify().damping(18)}
          style={[styles.row, { justifyContent: 'flex-start' }]}
        >
          <WeightInputCard
            cardId={cardId}
            weightInputs={weightInputs}
            onWeightInputChange={(id, value) => setWeightInputs(prev => ({ ...prev, [id]: value }))}
            onSaveWeight={(id) => handleSubmitWeight(weightInputs[id], id)}
          />
        </Animated.View>
      );
    }

    if (item.content?.startsWith(CardType.DIET_INPUT)) {
      return (
        <Animated.View
          entering={FadeInDown.springify().damping(18)}
          layout={Layout.springify().damping(18)}
          style={[styles.row, { justifyContent: 'flex-start' }]}
        >
          <DietOptionsCard
            cardId={item.id}
            onSelectOption={(cardId, optionId) => {
              if (optionId === 'text') {
                handleDietTextInput(cardId);
              } else if (optionId === 'photo') {
                handleDietPhotoInput(cardId);
              }
            }}
          />
        </Animated.View>
      );
    }

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

      return (
        <Animated.View
          entering={FadeInDown.springify().damping(18)}
          layout={Layout.springify().damping(18)}
          style={[styles.row, { justifyContent: 'flex-start' }]}
        >
          <DietInputCard
            cardId={cardId}
            dietTextInputs={dietTextInputs}
            onDietTextInputChange={(id, value) => setDietTextInputs(prev => ({ ...prev, [id]: value }))}
            onSubmitDietText={(id) => handleSubmitDietText(dietTextInputs[id], id)}
            onBackToDietOptions={handleBackToDietOptions}
            onShowDietPhotoActionSheet={(id) => {
              setCurrentCardId(id);
              setShowDietPhotoActionSheet(true);
            }}
          />
        </Animated.View>
      );
    }

    if (item.content?.startsWith(CardType.DIET_PLAN)) {
      return (
        <Animated.View
          entering={FadeInDown.springify().damping(18)}
          layout={Layout.springify().damping(18)}
          style={[styles.row, { justifyContent: 'flex-start' }]}
        >
          <DietPlanCard
            onGeneratePlan={() => {
              console.log('跳转到饮食方案详情');
            }}
          />
        </Animated.View>
      );
    }

    // 普通消息使用 ChatMessageComponent
    return (
      <Animated.View
        entering={isUser ? FadeInUp.springify().damping(18) : FadeInDown.springify().damping(18)}
        layout={Layout.springify().damping(18)}
      >
        <ChatMessageComponent
          message={item}
          onPreviewImage={setPreviewImageUri}
          onChoiceSelect={(messageId, choiceId) => {
            const choice = item.choices?.find(c => c.id === choiceId);
            if (choice) {
              handleChoiceSelection(choice, item);
            }
          }}
          selectedChoices={selectedChoices}
          pendingChoiceConfirmation={pendingChoiceConfirmation}
          isStreaming={isStreaming && pendingAssistantIdRef.current === item.id}
          onCancelStream={cancelCurrentRequest}
        />
      </Animated.View>
    );
  }



  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);
  }

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

  // 计算BMI
  function calculateBMI(weight: number, height: number): number {
    if (!weight || !height || weight <= 0 || height <= 0) return 0;
    const heightInMeters = height / 100;
    return Number((weight / (heightInMeters * heightInMeters)).toFixed(1));
  }

  // 获取BMI状态
  function getBMIStatus(bmi: number): { status: string; color: string } {
    if (bmi < 18.5) return { status: '偏瘦', color: '#87CEEB' };
    if (bmi < 24) return { status: '正常', color: '#90EE90' };
    if (bmi < 28) return { status: '偏胖', color: '#FFD700' };
    return { status: '肥胖', color: '#FFA07A' };
  }

  // 计算每日推荐摄入热量
  function calculateDailyCalories(weight: number, height: number, age: number, gender: string = 'female'): number {
    if (!weight || !height || !age) return 1376; // 默认值

    // 使用Harris-Benedict公式计算基础代谢率
    let bmr: number;
    if (gender === 'male') {
      bmr = 88.362 + (13.397 * weight) + (4.799 * height) - (5.677 * age);
    } else {
      bmr = 447.593 + (9.247 * weight) + (3.098 * height) - (4.330 * age);
    }

    // 考虑活动水平，这里使用轻度活动的系数1.375
    return Math.round(bmr * 1.375);
  }

  // 计算营养素分配
  function calculateNutritionDistribution(calories: number) {
    // 碳水化合物 50%，蛋白质 15%，脂肪 35%
    const carbCalories = calories * 0.5;
    const proteinCalories = calories * 0.15;
    const fatCalories = calories * 0.35;

    return {
      carbs: Math.round(carbCalories / 4), // 1g碳水 = 4卡路里
      protein: Math.round(proteinCalories / 4), // 1g蛋白质 = 4卡路里
      fat: Math.round(fatCalories / 9), // 1g脂肪 = 9卡路里
    };
  }

  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 {
      console.log('[DIET] 开始上传图片:', { uri: asset.uri, name: asset.fileName });

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

      console.log('[DIET] 图片上传成功:', { url });

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

      // 发送包含图片的饮食记录消息，图片通过 imageUrls 参数传递
      const dietMsg = `#记饮食：请分析这张食物照片的营养成分和热量`;
      console.log('[DIET] 发送饮食记录消息:', { dietMsg, imageUrls: [url] });
      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}>
      {/* 背景渐变 */}
      <LinearGradient
        colors={['#fafaff', '#f4f3ff']} // 使用紫色主题的浅色渐变
        style={styles.gradientBackground}
        start={{ x: 0, y: 0 }}
        end={{ x: 1, y: 1 }}
      />

      {/* 装饰性圆圈 */}
      <View style={styles.decorativeCircle1} />
      <View style={styles.decorativeCircle2} />
      {/* 顶部标题区域，显示教练名称、新建会话和历史按钮 */}
      <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);
        }}
      >
        <View style={styles.headerLeft}>
          <Text style={[styles.headerTitle, { color: theme.text }]}>海豹管家</Text>

          {/* 使用次数显示 */}
          <TouchableOpacity
            style={styles.usageCountContainer}
            onPress={() => {
            }}
          >
            <Image
              source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/icons/icon-profile-fish.png' }}
              style={styles.usageIcon}
              cachePolicy="memory-disk"
            />
            <Text style={styles.usageText}>
              {userProfile?.isVip ? '不限' : `${userProfile?.freeUsageCount || 0}/${userProfile?.maxUsageCount || 0}`}
            </Text>
          </TouchableOpacity>
        </View>

        <View style={styles.headerActions}>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={startNewConversation}
            style={[styles.headerActionButton, { backgroundColor: `${theme.primary}20` }]} // 20% opacity
          >
            <Ionicons name="add-outline" size={18} color={theme.primary} />
          </TouchableOpacity>
          <TouchableOpacity
            accessibilityRole="button"
            onPress={openHistory}
            style={[styles.headerActionButton, { backgroundColor: `${theme.primary}20` }]} // 20% opacity
          >
            <Ionicons name="time-outline" size={18} color={theme.primary} />
          </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>

      <View
        style={[{
          position: 'absolute',
          left: 0,
          right: 0,
          bottom: keyboardOffset,
          paddingBottom: getTabBarBottomPadding() + 10
        }]}
        onLayout={(e) => {
          const h = e.nativeEvent.layout.height;
          if (h && Math.abs(h - composerHeight) > 0.5) setComposerHeight(h);
        }}
      >
        <ChatComposer
          input={input}
          onInputChange={setInput}
          onSend={() => send(input)}
          onPickImages={pickImages}
          onCancelRequest={cancelCurrentRequest}
          selectedImages={selectedImages}
          onRemoveImage={removeSelectedImage}
          onPreviewImage={setPreviewImageUri}
          isSending={isSending}
          isStreaming={isStreaming}
          chips={chips}
        />
      </View>

      {!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>
      )}

      <HistoryModal
        visible={historyVisible}
        onClose={() => setHistoryVisible(false)}
        historyLoading={historyLoading}
        historyItems={historyItems}
        historyPage={historyPage}
        onRefreshHistory={refreshHistory}
        onSelectConversation={handleSelectConversation}
        onDeleteConversation={confirmDeleteConversation}
      />
      <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,
  },
  gradientBackground: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    opacity: 0.6,
  },
  decorativeCircle1: {
    position: 'absolute',
    top: -20,
    right: -20,
    width: 60,
    height: 60,
    borderRadius: 30,
    backgroundColor: '#7a5af8', // 紫色主题
    opacity: 0.08,
  },
  decorativeCircle2: {
    position: 'absolute',
    bottom: -15,
    left: -15,
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: '#7a5af8', // 紫色主题
    opacity: 0.04,
  },
  headerLeft: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 12,
  },
  headerTitle: {
    fontSize: 20,
    fontWeight: '800',
  },
  headerActions: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  headerActionButton: {
    width: 32,
    height: 32,
    borderRadius: 16,
    alignItems: 'center',
    justifyContent: 'center',
    shadowColor: '#7a5af8',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 2,
  },
  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: '#7a5af899' // 紫色主题 60% opacity
  },
  dietOptionsContainer: {
    gap: 8,
  },
  dietOptionBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 12,
    borderRadius: 12,
    backgroundColor: 'rgba(255,255,255,0.9)',
    borderWidth: 1,
    borderColor: '#7a5af84d', // 紫色主题 30% opacity
  },
  dietOptionIconContainer: {
    width: 40,
    height: 40,
    borderRadius: 20,
    backgroundColor: '#7a5af833', // 紫色主题 20% opacity
    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: '#7a5af899', // 紫色主题 60% opacity
    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(122,90,248,0.08)' // 使用紫色主题的浅色背景
  },
  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,
  },
  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,
  },
  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,
    width: '100%',
  },
  choiceButton: {
    backgroundColor: 'rgba(255,255,255,0.9)',
    borderWidth: 1,
    borderColor: '#7a5af84d', // 紫色主题 30% opacity
    borderRadius: 12,
    padding: 12,
    width: '100%',
    minWidth: 0,
  },
  choiceButtonRecommended: {
    borderColor: '#7a5af899', // 紫色主题 60% opacity
    backgroundColor: '#7a5af81a', // 紫色主题 10% opacity
  },
  choiceButtonSelected: {
    borderColor: '#19b36e', // success[500]
    backgroundColor: '#19b36e33', // 20% opacity
    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',
    width: '100%',
  },
  choiceLabel: {
    fontSize: 15,
    fontWeight: '600',
    color: '#192126',
    flex: 1,
    flexWrap: 'wrap',
  },
  choiceLabelRecommended: {
    color: '#19b36e', // success[500]
  },
  choiceLabelSelected: {
    color: '#19b36e', // success[500]
    fontWeight: '700',
  },
  choiceLabelDisabled: {
    color: '#687076',
  },
  choiceStatusContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  recommendedBadge: {
    backgroundColor: '#7a5af8cc', // 紫色主题 80% opacity
    borderRadius: 6,
    paddingHorizontal: 8,
    paddingVertical: 2,
  },
  recommendedText: {
    fontSize: 12,
    fontWeight: '700',
    color: '#19b36e', // success[500]
  },
  selectedBadge: {
    backgroundColor: '#19b36e', // success[500]
    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',
  },

  // 饮食方案卡片样式
  dietPlanContainer: {
    backgroundColor: 'rgba(255,255,255,0.95)',
    borderRadius: 16,
    padding: 16,
    gap: 16,
    borderWidth: 1,
    borderColor: '#7a5af833', // 紫色主题 20% opacity
  },
  dietPlanHeader: {
    gap: 4,
  },
  dietPlanTitleContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },
  dietPlanTitle: {
    fontSize: 18,
    fontWeight: '800',
    color: '#192126',
  },
  dietPlanSubtitle: {
    fontSize: 12,
    fontWeight: '600',
    color: '#687076',
    letterSpacing: 1,
  },
  profileSection: {
    gap: 12,
  },
  sectionTitle: {
    fontSize: 14,
    fontWeight: '700',
    color: '#192126',
  },
  profileDataRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 16,
  },
  avatarContainer: {
    alignItems: 'center',
  },
  profileStats: {
    flexDirection: 'row',
    flex: 1,
    justifyContent: 'space-around',
  },
  statItem: {
    alignItems: 'center',
    gap: 4,
  },
  statValue: {
    fontSize: 20,
    fontWeight: '800',
    color: '#192126',
  },
  statLabel: {
    fontSize: 12,
    color: '#687076',
  },
  bmiSection: {
    gap: 12,
  },
  bmiHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  bmiStatusBadge: {
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
  },
  bmiStatusText: {
    fontSize: 12,
    fontWeight: '700',
    color: '#FFFFFF',
  },
  bmiValue: {
    fontSize: 32,
    fontWeight: '800',
    color: '#192126',
    textAlign: 'center',
  },
  bmiScale: {
    flexDirection: 'row',
    height: 8,
    borderRadius: 4,
    overflow: 'hidden',
    gap: 1,
  },
  bmiBar: {
    flex: 1,
    height: '100%',
  },
  bmiLabels: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    paddingHorizontal: 4,
  },
  bmiLabel: {
    fontSize: 11,
    color: '#687076',
  },
  collapsibleSection: {
    paddingVertical: 8,
    borderBottomWidth: 1,
    borderBottomColor: 'rgba(0,0,0,0.06)',
  },
  collapsibleHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  caloriesSection: {
    gap: 12,
  },
  caloriesHeader: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
  },
  caloriesValue: {
    fontSize: 18,
    fontWeight: '800',
    color: '#19b36e', // success[500]
  },
  nutritionGrid: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    gap: 16,
  },
  nutritionItem: {
    alignItems: 'center',
    gap: 8,
  },
  nutritionValue: {
    fontSize: 24,
    fontWeight: '800',
    color: '#192126',
  },
  nutritionLabelRow: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
  },
  nutritionLabel: {
    fontSize: 12,
    color: '#687076',
  },
  nutritionNote: {
    fontSize: 12,
    color: '#687076',
    lineHeight: 16,
    textAlign: 'center',
    marginTop: 8,
  },
  dietPlanButton: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 8,
    backgroundColor: '#19b36e', // success[500]
    paddingVertical: 12,
    paddingHorizontal: 16,
    borderRadius: 12,
    marginTop: 8,
  },
  dietPlanButtonText: {
    fontSize: 14,
    fontWeight: '700',
    color: '#FFFFFF',
  },
  usageCountContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 4,
    paddingHorizontal: 8,
    paddingVertical: 4,
    borderRadius: 12,
    backgroundColor: 'rgba(122,90,248,0.08)', // 紫色主题浅色背景
  },
  usageIcon: {
    width: 16,
    height: 16,
  },
  usageText: {
    fontSize: 12,
    fontWeight: '600',
    color: '#7a5af8', // 紫色主题文字颜色
  },
});

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;
