
import React, { useState, useRef, useEffect, useCallback } from 'react';
import { useLocation } from 'react-router-dom';

// AI 创作对话框样式优化版 v12：白色极简高级风格，选项按钮、标题、头像与关键字统一使用 #8b5cf6。

import {
  Layout,
  Button,
  Input,
  Select,
  message,
  Space,
  Typography,
  Tooltip,
  Popconfirm,
  Modal,
  App,
} from 'antd';

import bg1 from '../assets/bg1.png';
import bg2 from '../assets/bg2.png';
import bg3 from '../assets/bg3.png';
import text from '../assets/testb.png';

import UploadSelector from '../components/UploadSelector';



import {
  getParameters, createGenerationTask, getgen_list, getEngine, uploadImage,uploadAudio,
  uploadVideo, getCreditRatios, deleteHistory, calculateCredits
} from '../api';

import { useAppStore } from '../store/useAppStore';
import { PrivatePortraitAssetPicker } from '../components/privatePortrait';
import type { PrivatePortraitLibraryType, PrivatePortraitSelectableAsset, UploadResourceHistoryItem } from '../types';

import {
  PlusOutlined,
  MenuUnfoldOutlined,
  MenuFoldOutlined,
  SendOutlined,
  DeleteOutlined,
  CloseOutlined,
  RobotOutlined,
  LoadingOutlined,
  PictureOutlined,
  VideoCameraOutlined,
  CaretDownOutlined,
  SwapOutlined,
  WarningOutlined,
  SettingOutlined,
  LayoutOutlined,
  ArrowUpOutlined,
  DownloadOutlined,
  ReloadOutlined,
  AudioOutlined,
  PauseOutlined,

} from '@ant-design/icons';

const { Header, Sider, Content } = Layout;
// 解构Input组件
const { TextArea } = Input;
// 解构Select组件
const { Option } = Select;
// 解构Typography组件
const { Text } = Typography;


interface MediaReference {
  name: string;
  type: 'image' | 'video' | 'audio';
  url: string;
  duration?: number;
  role?: string;
  label?: string;
  source?: string;
  private_asset_id?: string;
  remote_asset_id?: string;
  upload_resource_id?: string;
}


interface Message {
  id: string;
  original_prompt: string;
  gen_type: string;
  idempotency_key: string;
  media_references?: MediaReference[];
  image_size?: string;
  image_proportion?: string;
  image_px?: string;
  duration?: number;
  ratio?: string;
  resolution?: string;
  timestamp?: string;
  engine_id: string;
}


interface Conversation {
  id: string;
  title: string;
  lastMessage: string;
  timestamp: string;
  messages: any;
}


const mockUpload = (file: File): Promise<{ url: string }> => {
  return new Promise((resolve) => {
    setTimeout(() => {
      // 使用URL.createObjectURL创建本地文件预览URL
      const url = URL.createObjectURL(file);
      resolve({ url });
    }, 500);
  });
};




const AIChatPage: React.FC = () => {
  // ==================== 状态定义 ====================
  const { message: antdMessage } = App.useApp();
  const location = useLocation();

  const [collapsed, setCollapsed] = useState<boolean>(false);

  const [currentConversationId, setCurrentConversationId] = useState<string | null>('1');

  const [conversations, setConversations] = useState<Conversation[]>([
  ]);

  // 从 store 读取生成配置状态（包括输入框内容）
  const {
    mediaType,
    countType,
    selectedRatio,
    selectedResolution,
    width,
    height,
    videoDuration,
    videoAspectRatio,
    videoResolution,
    engineOptions,
    enginesele,
    inputValue,
    setMediaType,
    setCountType,
    setSelectedRatio,
    setSelectedResolution,
    setWidth,
    setHeight,
    setVideoDuration,
    setVideoAspectRatio,
    setVideoResolution,
    setEngineOptions,
    setEnginesele,
    setInputValue,
    currentMedia,
    setCurrentMedia,
  } = useAppStore();

  // 获取当前选中引擎的媒体上传限制
  const currentEngineList = mediaType === 'image' ? enginesele?.image : enginesele?.video;
  const currentEngine = currentEngineList?.find((e: any) => e.id === countType);
  const maxImageCount = currentEngine?.maxImageCount ?? 4;
  const maxVideoCount = currentEngine?.maxVideoCount ?? 1;

  const [uploading, setUploading] = useState<boolean>(false);

  const [loading, setLoading] = useState<boolean>(false);

  const [referenceMode, setReferenceMode] = useState<'universal' | 'first_last_frame'>('universal');
  const [firstFrame, setFirstFrame] = useState<MediaReference | null>(null);
  const [lastFrame, setLastFrame] = useState<MediaReference | null>(null);
  const [uploadTarget, setUploadTarget] = useState<'first' | 'last' | null>(null);
  const [referenceModeDropdownVisible, setReferenceModeDropdownVisible] = useState(false);
  const [privateAssetPickerOpen, setPrivateAssetPickerOpen] = useState(false);
  const [privateAssetPickerLibraryType, setPrivateAssetPickerLibraryType] = useState<PrivatePortraitLibraryType>('real_person');
  const [mediaStackHovered, setMediaStackHovered] = useState(false);
  const mediaStackCloseTimerRef = useRef<number | null>(null);
  const openMediaStackTray = useCallback(() => {
    if (mediaStackCloseTimerRef.current) {
      window.clearTimeout(mediaStackCloseTimerRef.current);
      mediaStackCloseTimerRef.current = null;
    }
    setMediaStackHovered(true);
  }, []);
  const closeMediaStackTray = useCallback(() => {
    if (mediaStackCloseTimerRef.current) {
      window.clearTimeout(mediaStackCloseTimerRef.current);
    }
    mediaStackCloseTimerRef.current = window.setTimeout(() => {
      setMediaStackHovered(false);
      mediaStackCloseTimerRef.current = null;
    }, 260);
  }, []);

  // @ 提及相关状态
  const [mentionVisible, setMentionVisible] = useState(false);
  const mentionInputRef = useRef<any>(null);
  const [mentionPosition, setMentionPosition] = useState({ top: 0, left: 0 });

  // 数字转中文数字（一、二、三、四）
  const numberToChinese = (num: number): string => {
    const map = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
    if (num <= 10) return map[num];
    if (num < 20) return '十' + map[num % 10];
    if (num < 100) {
      const tens = Math.floor(num / 10);
      const ones = num % 10;
      return map[tens] + '十' + (ones ? map[ones] : '');
    }
    return String(num);
  };

  // 根据媒体列表生成标签（图片一、图片二、视频一、视频二...）
  const generateMediaLabels = (media: { type: 'image' | 'video' | 'audio' }[]) => {
    let imgCount = 0;
    let vidCount = 0;
    let audCount = 0;
    return media.map((m) => {
      if (m.type === 'image') {
        imgCount++;
        return `图片${imgCount}`;
      } else if (m.type === 'video') {
        vidCount++;
        return `视频${vidCount}`;
      } else {
        audCount++;
        return `音频${audCount}`;
      }
    });
  };

  const [previewVisible, setPreviewVisible] = useState<boolean>(false);
  const [previewUrl, setPreviewUrl] = useState<string>('');
  const [previewType, setPreviewType] = useState<'image' | 'video'>('image');
  const videoRef = useRef<HTMLVideoElement>(null);

  useEffect(() => {
    if (previewVisible && previewType === 'video') {
      const playVideo = () => {
        if (videoRef.current) {
          videoRef.current.play().catch(() => {});
        }
      };
      
      if (videoRef.current) {
        if (videoRef.current.readyState >= 2) {
          playVideo();
        } else {
          videoRef.current.addEventListener('loadedmetadata', playVideo);
        }
      }
      
      const timer = setTimeout(playVideo, 300);
      
      return () => {
        clearTimeout(timer);
        if (videoRef.current) {
          videoRef.current.removeEventListener('loadedmetadata', playVideo);
          videoRef.current.pause();
        }
      };
    } else {
      if (videoRef.current) {
        videoRef.current.pause();
      }
    }
  }, [previewVisible, previewType]);

  // 提示词展开状态
  const [expandedPrompts, setExpandedPrompts] = useState<Set<string>>(new Set());

  // 从URL中提取exp时间戳（支持相对路径和完整URL）
  const extractExpTimestamp = (url: string): number | null => {
    if (!url) return null;

    try {
      // 尝试作为完整URL解析
      const urlObj = new URL(url);
      const expStr = urlObj.searchParams.get('exp');
      if (expStr) {
        return parseInt(expStr, 10);
      }
      return null;
    } catch {
      // 如果完整URL解析失败，尝试解析相对路径中的查询参数
      try {
        // 查找 ? 后面的部分
        const queryStart = url.indexOf('?');
        if (queryStart !== -1) {
          const queryString = url.substring(queryStart + 1);
          const params = new URLSearchParams(queryString);
          const expStr = params.get('exp');
          if (expStr) {
            return parseInt(expStr, 10);
          }
        }
        return null;
      } catch {
        return null;
      }
    }
  };

  // 检查媒体是否过期
  const isMediaExpired = (url: string): boolean => {
    const expTimestamp = extractExpTimestamp(url);
    if (!expTimestamp) {
      return false; // 没有exp参数，视为不过期
    }
    const currentTimestamp = Math.floor(Date.now() / 1000);
    return currentTimestamp > expTimestamp;
  };

  // 附件预览弹窗状态（独立弹窗）
  const [attachmentPreviewVisible, setAttachmentPreviewVisible] = useState<boolean>(false);
  const [attachmentPreviewUrl, setAttachmentPreviewUrl] = useState<string>('');
  const [attachmentPreviewType, setAttachmentPreviewType] = useState<'image' | 'video' | 'audio'>('image');
  const [attachmentPreviewName, setAttachmentPreviewName] = useState<string>('');
  const attachmentPreviewVideoRef = useRef<HTMLVideoElement>(null);

  // 弹窗打开时自动播放视频，关闭时停止
  useEffect(() => {
    if (attachmentPreviewVisible && attachmentPreviewType === 'video' && attachmentPreviewVideoRef.current) {
      const v = attachmentPreviewVideoRef.current;
      v.currentTime = 0;
      v.muted = false;
      const playPromise = v.play();
      if (playPromise && typeof playPromise.catch === 'function') {
        playPromise.catch(() => {
          // 自动播放被阻止时静音重试
          v.muted = true;
          v.play().catch(() => {});
        });
      }
    } else if (!attachmentPreviewVisible && attachmentPreviewVideoRef.current) {
      const v = attachmentPreviewVideoRef.current;
      v.pause();
      v.muted = true;
      v.currentTime = 0;
    }
  }, [attachmentPreviewVisible, attachmentPreviewType, attachmentPreviewUrl]);
  const [playingAudioUrl, setPlayingAudioUrl] = useState<string | null>(null);
  const [audioProgress, setAudioProgress] = useState(0);

  // 附件详情悬浮窗状态
  const [attachmentPopupVisible, setAttachmentPopupVisible] = useState<boolean>(false);
  const [attachmentPopupMessageId, setAttachmentPopupMessageId] = useState<string | null>(null);
  const [attachmentPopupPosition, setAttachmentPopupPosition] = useState({ x: 0, y: 0 });

  const [showImageSettingsModal, setShowImageSettingsModal] = useState(false);
  const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
  const [ratioOptions, setRatioOptions] = useState([]);
  const [resolutionOptions, setResolutionOptions] = useState([]);
  const [currentEngineSupportedSizes, setCurrentEngineSupportedSizes] = useState<Record<string, Record<string, string>>>({});

  const [showEngineModal, setShowEngineModal] = useState(false);
  const [showMediaTypeModal, setShowMediaTypeModal] = useState(false);

  const [creditRatios, setCreditRatios] = useState<any[]>([]);
  const [cimage, setCimage] = useState<any[]>([]);
  const [creditCalculationData, setCreditCalculationData] = useState<any[]>([]);

  // 获取预估积分 - 根据引擎ID、类型和分辨率计算
  const getEstimatedCredits = (): number => {
    // 根据当前选择的引擎ID、类型和分辨率查找对应的积分配置
    let config: any = {};
    config = creditCalculationData.find((item: any) =>
      item.modelConfigId === countType &&
      item.genType === mediaType &&
      item.resolution === (mediaType === 'video' ? videoResolution : selectedResolution)
    );

    if (!config) {
      if (mediaType === 'video') {
        // 如果没有找到对应的配置，则使用默认配置
        config = {
          perSecondCredits: 2,
          baseCredits: 60,
          ratio: 1.3,
          inputVideoRatio: 1.3,
          inputVideoBaseCredits: 0,
          inputVideoPerSecondCredits: 15,
          inputImageRatio: 1,
          inputImageBaseCredits: 0,
          inputImagePerImageCredits: 0.0,
        };
        if (videoResolution === '1080p') {
          config.ratio = 1.3;
        } else if (videoResolution === '720p') {
          config.ratio = 1.3;
        } else if (videoResolution === '480p') {
          config.ratio = 1.3;
        }
      }
      else {
        // 如果没有找到对应的配置，则使用默认配置
        config = {
          perSecondCredits: 0.1,
          baseCredits: 2,
          ratio: 3,
          inputImageRatio: 1,
          inputImageBaseCredits: 0,
          inputImagePerImageCredits: 0.0,
        };
        if (selectedResolution === '2K') {
          config.ratio = 3;
        } else if (selectedResolution === '4K') {
          config.ratio = 3;
        } else if (selectedResolution === '1K') {
          config.ratio = 3;
        }
      }
    }

    // 根据配置计算积分（保留两位小数，不做取整）
    if (mediaType === 'video') {
      // 视频：(秒数 × perSecondCredits + baseCredits) × ratio
      let total = (videoDuration * config.perSecondCredits + config.baseCredits) * config.ratio;
      // 传入视频积分
      const inputVideoDuration = currentMedia
        .filter((m) => m.type === 'video')
        .reduce((sum, m) => sum + (m.duration || 0), 0);
      if (inputVideoDuration > 0) {
        const inputVideoCost = ((config.inputVideoBaseCredits || 0) + (config.inputVideoPerSecondCredits || 0) * inputVideoDuration) * (config.inputVideoRatio || 1);
        total += inputVideoCost;
      }
      // 传入图片积分
      const inputImageCount = currentMedia
        .filter((m) => m.type === 'image')
        .length;
      if (inputImageCount > 0) {
        const inputImageCost = ((config.inputImageBaseCredits || 0) + (config.inputImagePerImageCredits || 0) * inputImageCount) * (config.inputImageRatio || 1);
        total += inputImageCost;
      }
      return Number(total.toFixed(2));
    } else {
      // 图片：baseCredits × ratio
      let total = config.baseCredits * config.ratio;
      // 传入图片积分
      const inputImageCount = currentMedia
        .filter((m) => m.type === 'image')
        .length;
      if (inputImageCount > 0) {
        const inputImageCost = ((config.inputImageBaseCredits || 0) + (config.inputImagePerImageCredits || 0) * inputImageCount) * (config.inputImageRatio || 1);
        total += inputImageCost;
      }
      return Number(total.toFixed(2));
    }
  };

  const messagesEndRef = useRef<HTMLDivElement>(null);
  const scrollContainerRef = useRef<HTMLDivElement>(null);
  const pollingRef = useRef<number | null>(null);
  const isFirstLoadRef = useRef<boolean>(true);
  const isInitialLoadDone = useRef(false);
  const lastAutoScrollTime = useRef(0);

  const currentConversation = conversations.find((c) => c.id === currentConversationId);


  const [gen_list, setGen_list] = useState<any>([]);

  const [Pagebreak, setPagebreak] = useState<any>({
    page: 1,
    pageSize: 20,
  });
  const [Totalnumber, setTotalnumber] = useState<any>(0);
  const [isLoadingMore, setIsLoadingMore] = useState(false);
  // ==================== 副作用 ====================

  useEffect(() => {
    const state = location.state as any;
    
    if (state) {
      if (state.generationPrompt) {
        setInputValue(state.generationPrompt);
      }
      if (state.mediaReferences && Array.isArray(state.mediaReferences) && state.mediaReferences.length > 0) {
        const mediaItems: MediaReference[] = state.mediaReferences.map((ref: any) => {
          const url = ref.url || ref.resourceUrl || ref.previewUrl || '';
          const fullUrl = url.startsWith('http') ? url : `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${url}`;
          return {
            ...ref,
            name: ref.name || `参考${ref.type}`,
            type: ref.type === 'video' ? 'video' : ref.type === 'audio' ? 'audio' : 'image',
            url: fullUrl,
            duration: ref.duration || 0,
            label: ref.label || '',
          };
        });
        setCurrentMedia(mediaItems);
      }
      if (state.aspectRatio) {
        setVideoAspectRatio(state.aspectRatio);
      }
      window.history.replaceState({}, '', window.location.pathname);
    }
  }, [location.state]);

  // 滚动到底部的辅助函数
  useEffect(() => {
    return () => {
      if (mediaStackCloseTimerRef.current) {
        window.clearTimeout(mediaStackCloseTimerRef.current);
      }
    };
  }, []);

  const scrollToBottom = useCallback((behavior: ScrollBehavior = 'instant') => {
    const scrollContainer = scrollContainerRef.current;
    if (!scrollContainer) return;

    lastAutoScrollTime.current = Date.now();

    const doScroll = () => {
      scrollContainer.scrollTo({ top: scrollContainer.scrollHeight, behavior });
    };

    requestAnimationFrame(doScroll);
  }, []);

  // 初次打开或页面刷新时自动滚动到底部（只在初始加载时执行一次）
  useEffect(() => {
    if (gen_list.length > 0 && !isInitialLoadDone.current) {
      const timer = setTimeout(() => {
        scrollToBottom('smooth');
        isInitialLoadDone.current = true;
      }, 300);
      return () => clearTimeout(timer);
    }
  }, [gen_list.length, scrollToBottom]);

  useEffect(() => {
    const newOptions = mediaType === 'image' ? enginesele.image : enginesele.video;
    if (newOptions && newOptions.length > 0) {
      // 如果当前 countType 不在新选项中，重置为第一个选项
      const isValidOption = newOptions.some((item: any) => item.id === countType);
      if (!isValidOption) {
        setCountType(newOptions[0].id);
      }

    }
  }, [mediaType, enginesele]);

  // 点击外部关闭弹窗
  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      // 关闭媒体类型选择弹窗
      if (showMediaTypeModal && !target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
        setShowMediaTypeModal(false);
      }
      // 关闭引擎选择弹窗
      if (showEngineModal && !target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
        setShowEngineModal(false);
      }
      // 关闭图片设置弹窗
      if (showImageSettingsModal && !target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
        setShowImageSettingsModal(false);
      }
      // 关闭视频设置弹窗
      if (showVideoSettingsModal && !target.closest('.image-settings-popover') && !target.closest('.image-settings-trigger')) {
        setShowVideoSettingsModal(false);
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [showMediaTypeModal, showEngineModal, showImageSettingsModal, showVideoSettingsModal]);

  useEffect(() => {
    if (mediaType !== 'video') return;
    const engine = enginesele?.video?.find((e: any) => e.id === countType);
    if (!engine) return;

    const supportsFLF = engine.supportsFirstLastFrame ?? false;
    const supportsUR = engine.supportsUniversalReference ?? true;

    setReferenceMode((prevMode) => {
      if (supportsUR) return 'universal';
      if (prevMode === 'universal' && !supportsUR) {
        if (supportsFLF) return 'first_last_frame';
      }
      return prevMode;
    });
  }, [countType, mediaType, enginesele]);

  // 初始化获取参数 - 只在组件挂载时执行一次
  useEffect(() => {
    getEngine()
      .then((data: any) => {
        // console.log('引擎', data);

        setEnginesele(data.engine);

        // 如果是视频模式，初始化视频参数选项
        if (data.engine.video && data.engine.video.length > 0) {
          const defaultEngine = data.engine.video[0];

          // 查找用户之前选择的引擎（如果存在）
          const savedEngine = data.engine.video.find((e: any) => e.id === countType);
          const targetEngine = savedEngine || defaultEngine;

          // 更新引擎选项为当前引擎支持的参数
          setEngineOptions({
            ratios: targetEngine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
            resolutions: targetEngine.supportedResolutions || ['480p', '720p', '1080p'],
            durations: targetEngine.supportedDurations || [5, 8, 10, 12, 15],
          });

          // 确保视频参数在引擎支持的范围内
          if (!targetEngine.supportedRatios?.includes(videoAspectRatio)) {
            setVideoAspectRatio(targetEngine.supportedRatios?.[0] || '16:9');
          }
          if (!targetEngine.supportedResolutions?.includes(videoResolution)) {
            setVideoResolution(targetEngine.supportedResolutions?.[0] || '720p');
          }
          if (!targetEngine.supportedDurations?.includes(videoDuration)) {
            setVideoDuration(targetEngine.supportedDurations?.[0] || 5);
          }

          // 如果之前没有选择过引擎（还是默认值），才设置默认引擎
          if (countType === '请选择') {
            setCountType(targetEngine.id);
          }
        }

        if (data.engine.image && data.engine.image.length > 0) {
          const savedImageEngine = data.engine.image.find((e: any) => e.id === countType);
          const targetImageEngine = savedImageEngine || data.engine.image[0];

          const supportedSizes = targetImageEngine.supportedSizes || {};
          const resolutionLevels = Object.keys(supportedSizes).sort((a, b) => {
            const levelOrder = { '1K': 0, '2K': 1, '4K': 2 };
            return (levelOrder[a] || 0) - (levelOrder[b] || 0);
          });

          const primaryResolution = resolutionLevels[0] || '2K';
          const supportedResolutions = Object.keys(supportedSizes[primaryResolution] || {});

          const newRatioOptions = supportedResolutions.map((res: any) => ({
            value: res,
            label: res,
          }));
          setRatioOptions(newRatioOptions);
          setCurrentEngineSupportedSizes(supportedSizes);
          setResolutionOptions(resolutionLevels.map((level) => {
            const match = level.match(/(\d+)K/);
            const num = match ? parseInt(match[1]) : 1;
            const labels: Record<number, string> = { 1: '标清', 2: '高清', 4: '超清' };
            return {
              value: level,
              label: `${labels[num] || '高清'} ${level}`,
            };
          }));

          if (supportedSizes[primaryResolution] && supportedSizes[primaryResolution][supportedResolutions[0]]) {
            const defaultSize = supportedSizes[primaryResolution][supportedResolutions[0]];
            const [w, h] = defaultSize.split(/[×x]/);
            setWidth(Number(w));
            setHeight(Number(h));
            setSelectedRatio(supportedResolutions[0]);
            setSelectedResolution(primaryResolution);
          }

          if (countType === '请选择') {
            setCountType(targetImageEngine.id);
          }
        }
      })
      .catch(() => {
      });
    calculateCredits().then((data: any) => {
      // console.log('积分计算', data);
      // 保存积分计算数据
      setCreditCalculationData(data);
    })
    getgen_list(Pagebreak).then((data: any) => {
      let mess_list = data.items
      let total = data.total
      setGen_list(mess_list)
      setTotalnumber(total)
    })
    // getParameters()
    //   .then((data) => {
    //     let supportedSizes = (data as any).items?.[0]?.supportedSizes || {};
    //     let supportedResolutions = [];
    //     let twokwidth = [];
    //     let fourkwidth = [];

    //     for (let key in supportedSizes["2K"]) {
    //       supportedResolutions.push(key);
    //       twokwidth.push(supportedSizes["2K"][key]);
    //     }

    //     const newRatioOptions = supportedResolutions.map((res: any, index: number) => ({
    //       value: res,
    //       label: String(index),
    //     }));
    //     setRatioOptions(newRatioOptions);

    //     for (let key in supportedSizes["4K"]) {
    //       fourkwidth.push(supportedSizes["4K"][key]);
    //     }

    //     const newWidthandHeight = [twokwidth, fourkwidth];
    //     setWidthandHeight(newWidthandHeight);
    //     setResolutionOptions([
    //       { value: '2K', label: '高清 2K' },
    //       { value: '4K', label: '超清 4K' },
    //     ]);
    //   })
    //   .catch(() => { });
  }, []);


  // 轮询逻辑 - 当有任务在生成时，每5秒查询一次状态
  useEffect(() => {
    // 先清理之前的定时器
    if (pollingRef.current) {
      clearInterval(pollingRef.current);
      pollingRef.current = null;
    }

    // 判断是否有正在生成的任务
    const hasGeneratingTask = gen_list.some((item: any) => item.status === 'generating');

    if (!hasGeneratingTask) return;

    // 设置5秒轮询
    pollingRef.current = window.setInterval(() => {
      getgen_list(Pagebreak).then((data: any) => {
        // 只更新正在生成的任务，不影响其他已加载的数据
        setGen_list((prevList: any[]) => {
          return prevList.map((prevItem: any) => {
            // 只更新正在生成的任务
            if (prevItem.status === 'generating') {
              const newItem = data.items.find((item: any) => item.id === prevItem.id);
              // 如果找到了对应的新数据，使用新数据；否则保持旧数据
              return newItem || prevItem;
            }
            // 非生成中的任务保持不变
            return prevItem;
          });
        });
        setTotalnumber(data.total);
      }).catch((error) => {
      });
    }, 10000);

    // 清理定时器
    return () => {
      if (pollingRef.current) {
        clearInterval(pollingRef.current);
        pollingRef.current = null;
      }
    };
  }, [gen_list, Pagebreak]);

  // 点击空白处关闭图片设置浮层
  useEffect(() => {
    if (!showImageSettingsModal) return;
    const handleClickOutside = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (
        !target.closest(".image-settings-popover") &&
        !target.closest(".image-settings-trigger")
      ) {
        setShowImageSettingsModal(false);
      }
    };
    document.addEventListener("click", handleClickOutside);
    return () => document.removeEventListener("click", handleClickOutside);
  }, [showImageSettingsModal]);

  useEffect(() => {
    if (!showVideoSettingsModal) return;
    const handleClickOutside = (e: MouseEvent) => {
      const target = e.target as HTMLElement;
      if (
        !target.closest(".image-settings-popover") &&
        !target.closest(".image-settings-trigger")
      ) {
        setShowVideoSettingsModal(false);
      }
    };
    document.addEventListener("click", handleClickOutside);
    return () => document.removeEventListener("click", handleClickOutside);
  }, [showVideoSettingsModal]);

  // 根据比例和分辨率计算尺寸
  const calculateSizeFromRatione = (ratio: string) => {
    const resolutionLevels = Object.keys(currentEngineSupportedSizes).sort((a, b) => {
      const levelOrder: Record<string, number> = { '1K': 0, '2K': 1, '4K': 2 };
      return (levelOrder[a] || 0) - (levelOrder[b] || 0);
    });

    const targetResolution = currentEngineSupportedSizes[selectedResolution] && currentEngineSupportedSizes[selectedResolution][ratio]
      ? selectedResolution
      : resolutionLevels.find(level => currentEngineSupportedSizes[level] && currentEngineSupportedSizes[level][ratio]) || resolutionLevels[0];

    if (targetResolution && currentEngineSupportedSizes[targetResolution] && currentEngineSupportedSizes[targetResolution][ratio]) {
      const size = currentEngineSupportedSizes[targetResolution][ratio];
      const [w, h] = size.split(/[×x]/);
      setWidth(Number(w));
      setHeight(Number(h));
      setSelectedRatio(ratio);
      setSelectedResolution(targetResolution);
    }
  };

  const calculateSizeFromRatiotwo = (resolution: string) => {
    if (!currentEngineSupportedSizes[resolution]) {
      const resolutionLevels = Object.keys(currentEngineSupportedSizes).sort((a, b) => {
        const levelOrder: Record<string, number> = { '1K': 0, '2K': 1, '4K': 2 };
        return (levelOrder[a] || 0) - (levelOrder[b] || 0);
      });
      resolution = resolutionLevels[0] || resolution;
    }

    const supportedRatios = currentEngineSupportedSizes[resolution] ? Object.keys(currentEngineSupportedSizes[resolution]) : [];
    
    const newRatioOptions = supportedRatios.map((res: any) => ({
      value: res,
      label: res,
    }));
    setRatioOptions(newRatioOptions);

    const targetRatio = supportedRatios.includes(selectedRatio)
      ? selectedRatio
      : supportedRatios[0] || '';

    if (targetRatio && currentEngineSupportedSizes[resolution] && currentEngineSupportedSizes[resolution][targetRatio]) {
      const size = currentEngineSupportedSizes[resolution][targetRatio];
      const [w, h] = size.split(/[×x]/);
      setWidth(Number(w));
      setHeight(Number(h));
      setSelectedRatio(targetRatio);
      setSelectedResolution(resolution);
    }
  };

  // 交换宽高
  const handleSwap = () => {
    setWidth(height);
    setHeight(width);
  };

  const currentVideoEngine = enginesele?.video?.find((e: any) => e.id === countType);
  const supportsFirstLastFrame = currentVideoEngine?.supportsFirstLastFrame ?? false;
  const supportsUniversalReference = currentVideoEngine?.supportsUniversalReference ?? true;

  const handleReferenceModeChange = (mode: 'universal' | 'first_last_frame') => {
    if (mode === 'first_last_frame' && !supportsFirstLastFrame) return;
    if (mode === 'universal' && !supportsUniversalReference) return;
    setReferenceMode(mode);
    setReferenceModeDropdownVisible(false);
    setCurrentMedia([]);
    setInputValue('');
  };

  const handleSwapFrames = () => {
    const temp = firstFrame;
    setFirstFrame(lastFrame);
    setLastFrame(temp);
  };

  const handleRemoveFirstFrame = () => {
    setFirstFrame(null);
    setLastFrame(null);
  };

  const handleRemoveLastFrame = () => {
    setLastFrame(null);
  };

  // ==================== 事处理函数 ====================

  const handleNewChat = () => {
    // 生成唯一ID（使用时间戳）
    const newId = Date.now().toString();
    const newConversation: Conversation = {
      id: newId,
      title: '新对话',
      lastMessage: '',
      timestamp: new Date().toLocaleString('zh-CN'),
      messages: [],
    };

    // 将新对话插入到列表顶部
    setConversations((prev) => [newConversation, ...prev]);
    // 切换到新对话
    setCurrentConversationId(newId);
    // 清空输入框和已上传媒体
    setInputValue('');
    setCurrentMedia([]);
    setFirstFrame(null);
    setLastFrame(null);
    // 显示提示消息
    antdMessage.info('已开启新对话');

  };


  const handleDeleteChat = (conversationId: string) => {
    // 过滤掉要删除的对话
    setConversations((prev) => prev.filter((c) => c.id !== conversationId));
    // 如果删除的是当前选中的对话，切换到其他对话
    if (currentConversationId === conversationId) {
      setCurrentConversationId(
        conversations[0]?.id === conversationId
          ? conversations[1]?.id || null
          : conversations[0]?.id || null
      );
    }
    // 显示成功提示
    antdMessage.success('对话已删除');
  };


  const handleSelectChat = (conversationId: string) => {
    setCurrentConversationId(conversationId);
    setCurrentMedia([]);
    setFirstFrame(null);
    setLastFrame(null);
  };


  const handleSend = async () => {
    const isFirstLastFrameMode = mediaType === 'video' && referenceMode === 'first_last_frame';

    if (isFirstLastFrameMode) {
      if (!inputValue.trim()) {
        antdMessage.warning('请输入内容');
        return;
      }
    } else {
      if (!inputValue.trim() && currentMedia.length === 0) {
        antdMessage.warning('请输入内容或上传图片/视频');
        return;
      }
    }

    let mediaReferences: MediaReference[] | undefined;
    if (isFirstLastFrameMode) {
      mediaReferences = [];
      if (firstFrame) {
        mediaReferences.push({ ...firstFrame, role: 'first_frame' });
      }
      if (lastFrame) {
        mediaReferences.push({ ...lastFrame, role: 'last_frame' });
      }
      if (mediaReferences.length === 0) {
        mediaReferences = undefined;
      }
    } else {
      if (currentMedia.length > 0) {
        mediaReferences = currentMedia.map((m) => {
          if (m.type === 'image') {
            const { duration, ...rest } = m;
            return rest;
          }
          return m;
        });
      } else {
        mediaReferences = undefined;
      }
    }


    // console.log(mediaReferences);

    // 创建用户消息对象
    const newMessage: Message = {
      id: '',
      gen_type: mediaType,
      original_prompt: inputValue.trim(),
      engine_id: countType,

      idempotency_key: new Date().toLocaleString('zh-CN'),
      media_references: mediaReferences,
      // 图片参数（仅图片模式时添加）
      ...(mediaType === 'image' && {
        image_size: selectedResolution,
        image_proportion: selectedRatio,
        image_px: width + "x" + height,
      }),
      // 视频参数（仅视频模式时添加）
      ...(mediaType === 'video' && {
        duration: videoDuration,
        aspect_ratio: videoAspectRatio,
        resolution: videoResolution,
      }),
    };






    // 设置加载状态
    setLoading(true);

    createGenerationTask(newMessage).then(() => {
      // 创建任务成功后，清空输入框和已上传媒体
      setInputValue('');
      setCurrentMedia([]);
      setFirstFrame(null);
      setLastFrame(null);

      // 创建任务成功后，重置页数为1，获取最新列表
      const newPagebreak = { ...Pagebreak, page: 1 };
      setPagebreak(newPagebreak);

      getgen_list(newPagebreak).then((data: any) => {
        // 将data.items的最后一个元素添加到gen_list末尾
        setGen_list((prev: any[]) => [...prev, data.items[data.items.length - 1]]);
        setTotalnumber(data.total);
        // 发送消息后滚动到底部
        setTimeout(() => {
          messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
        }, 100);
      }).catch((error) => {
      });
    }).catch((error: any) => {

      // 失败时不清空输入框和媒体

      // 尝试从错误对象中提取detail字段
      let errorMessage = "创建任务失败";
      if (error?.response?.data?.detail) {
        errorMessage = error.response.data.detail;
      } else if (error?.data?.detail) {
        errorMessage = error.data.detail;
      } else if (error?.detail) {
        errorMessage = error.detail;
      } else if (error?.message) {
        errorMessage = error.message;
      }

      antdMessage.error({
        content: errorMessage,
        duration: 3,
      });
    }).finally(() => {
      setLoading(false);
    });

    setTimeout(() => {
      setLoading(false);
    }, 3000);


  };

  // 加载更多
  const handleLoadMore = async () => {
    // 检查是否还有更多数据
    if (gen_list.length >= Totalnumber) {
      return;
    }

    // 保存当前滚动位置（相对于顶部的偏移）
    const scrollContainer = scrollContainerRef.current;
    if (!scrollContainer) {
      return;
    }

    const scrollTopBefore = scrollContainer.scrollTop;
    const scrollHeightBefore = scrollContainer.scrollHeight;

    setIsLoadingMore(true);

    try {
      const nextPage = Pagebreak.page + 1;
      const result = await getgen_list({
        ...Pagebreak,
        page: nextPage,
      });

      // 处理返回数据，兼容数组或对象格式
      const data = Array.isArray(result) ? { items: result, total: result.length } : result;


      // 更新总数
      if (data.total) {
        setTotalnumber(data.total);
      }

      // 更新页码
      setPagebreak((prev: any) => ({ ...prev, page: nextPage }));

      // 去重后合并数据（根据 id 去重，新数据添加到前面）
      setGen_list((prev: any[]) => {
        const existingIds = new Set(prev.map((item: any) => item.id));
        // 只添加不存在的新数据，保持新数据的原有顺序
        const newItems = data.items.filter((item: any) => {
          if (!item.id) return false;
          if (existingIds.has(item.id)) return false;
          existingIds.add(item.id);
          return true;
        });
        // 新数据在前，旧数据在后
        return [...newItems, ...prev];
      });

      // 恢复滚动位置（等待DOM更新完成后执行，增加超时时间确保DOM完全更新）
      setTimeout(() => {
        const scrollHeightAfter = scrollContainer.scrollHeight;
        const addedHeight = scrollHeightAfter - scrollHeightBefore;
        // 新数据添加到前面，保持当前查看内容的位置不变
        scrollContainer.scrollTop = scrollTopBefore + addedHeight;
      }, 200);
    } catch (error) {
    } finally {
      setIsLoadingMore(false);
    }
  };

  const getVideoDuration = (file: File): Promise<number> => {
    return new Promise((resolve, reject) => {
      const video = document.createElement('video');
      video.preload = 'metadata';
      video.onloadedmetadata = () => {
        window.URL.revokeObjectURL(video.src);
        resolve(video.duration);
      };
      video.onerror = () => {
        window.URL.revokeObjectURL(video.src);
        reject(new Error('无法获取视频时长'));
      };
      video.src = URL.createObjectURL(file);
    });
  };

  const getAudioDuration = (file: File): Promise<number> => {
    return new Promise((resolve, reject) => {
      const audio = document.createElement('audio');
      audio.preload = 'metadata';
      audio.onloadedmetadata = () => {
        URL.revokeObjectURL(audio.src);
        resolve(audio.duration);
      };
      audio.onerror = () => {
        URL.revokeObjectURL(audio.src);
        reject(new Error('无法获取音频时长'));
      };
      audio.src = URL.createObjectURL(file);
    });
  };

  const handleAudioPlay = (url: string) => {
    const audioUrl = url.startsWith('http') ? url : `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${url}`;
    if (playingAudioUrl === audioUrl) {
      const audio = document.getElementById('audio-player') as HTMLAudioElement;
      if (audio) {
        audio.pause();
      }
      setPlayingAudioUrl(null);
    } else {
      setPlayingAudioUrl(audioUrl);
    }
  };

  const getImageDimensions = (file: File): Promise<{ width: number; height: number }> => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => {
        window.URL.revokeObjectURL(img.src);
        resolve({ width: img.naturalWidth, height: img.naturalHeight });
      };
      img.onerror = () => {
        window.URL.revokeObjectURL(img.src);
        reject(new Error('无法读取图片尺寸'));
      };
      img.src = URL.createObjectURL(file);
    });
  };

  const getVideoDimensions = (file: File): Promise<{ width: number; height: number; duration: number }> => {
    return new Promise((resolve, reject) => {
      const video = document.createElement('video');
      video.preload = 'metadata';
      video.onloadedmetadata = () => {
        window.URL.revokeObjectURL(video.src);
        resolve({ width: video.videoWidth, height: video.videoHeight, duration: video.duration });
      };
      video.onerror = () => {
        window.URL.revokeObjectURL(video.src);
        reject(new Error('无法读取视频尺寸'));
      };
      video.src = URL.createObjectURL(file);
    });
  };

  // 图片尺寸校验：宽高比 (0.4, 2.5)，宽高长度 (300, 6000)
  const validateImageDimensions = (width: number, height: number): string | null => {
    if (width < 300 || width > 6000) return `图片宽度需在 300~6000px 之间，当前为 ${width}px`;
    if (height < 300 || height > 6000) return `图片高度需在 300~6000px 之间，当前为 ${height}px`;
    const ratio = width / height;
    if (ratio < 0.4 || ratio > 2.5) return `图片宽高比需在 0.4~2.5 之间，当前为 ${ratio.toFixed(2)}`;
    return null;
  };

  // 视频尺寸校验：宽高比 [0.4, 2.5]，宽高 [300, 6000]，总像素 [409600, 8295044]
  const validateVideoDimensions = (width: number, height: number): string | null => {
    if (width < 300 || width > 6000) return `视频宽度需在 300~6000px 之间，当前为 ${width}px`;
    if (height < 300 || height > 6000) return `视频高度需在 300~6000px 之间，当前为 ${height}px`;
    const ratio = width / height;
    if (ratio < 0.4 || ratio > 2.5) return `视频宽高比需在 0.4~2.5 之间，当前为 ${ratio.toFixed(2)}`;
    const totalPixels = width * height;
    if (totalPixels < 409600) return `视频总像素数过小（${width}×${height}=${totalPixels}），需 ≥ 640×640=409600`;
    if (totalPixels > 8295044) return `视频总像素数过大（${width}×${height}=${totalPixels}），需 ≤ 3326×2494=8295044`;
    return null;
  };

  const handleUpload = async (file: File, frameTarget?: 'first' | 'last' | File[]) => {
    const isImage = file.type.startsWith('image/');
    const isVideo = file.type.startsWith('video/');

    if (mediaType === 'video' && referenceMode === 'first_last_frame') {
      if (!isImage) {
        antdMessage.error('首尾帧模式仅支持上传图片');
        return false;
      }
      if (file.size / 1024 / 1024 > 10) {
        antdMessage.error('图片大小不能超过10MB');
        return false;
      }

      try {
        const { width, height } = await getImageDimensions(file);
        const error = validateImageDimensions(width, height);
        if (error) {
          antdMessage.error(error);
          return false;
        }
      } catch {
        antdMessage.error('无法读取图片尺寸，请检查文件是否损坏');
        return false;
      }

      const effectiveUploadTarget = frameTarget || uploadTarget;
      if (!effectiveUploadTarget) {
        antdMessage.error('请选择首帧或尾帧上传位置');
        return false;
      }

      setUploading(true);
      try {
        const res = await uploadImage(file);
        const mediaRef: MediaReference = {
          name: file.name,
          type: 'image',
          url: res.url,
          role: effectiveUploadTarget === 'first' ? 'first_frame' : 'last_frame',
        };
        if (effectiveUploadTarget === 'first') {
          setFirstFrame(mediaRef);
        } else {
          setLastFrame(mediaRef);
        }
        antdMessage.success('图片上传成功');
      } catch (error) {
        antdMessage.error('上传失败');
      } finally {
        setUploading(false);
        setUploadTarget(null);
      }
      return false;
    }

    const isAudio = file.type.startsWith('audio/');

    if (!isImage && !isVideo && !isAudio) {
      antdMessage.error('仅支持图片、视频或音频文件');
      return false;
    }

    if (isAudio) {
      const audioExt = file.name.split('.').pop()?.toLowerCase();
      if (!['wav', 'mp3'].includes(audioExt || '')) {
        antdMessage.error('音频仅支持wav和mp3格式');
        return false;
      }
    }

    if (mediaType === 'image' && (isVideo || isAudio)) {
      antdMessage.error('图片模式仅支持上传图片');
      return false;
    }

    if (isAudio && mediaType !== 'video') {
      antdMessage.error('仅视频模式支持上传音频');
      return false;
    }

    const maxMB = isVideo ? 100 : (isAudio ? 50 : 10);
    const fileTypeText = isVideo ? '视频' : (isAudio ? '音频' : '图片');
    if (file.size / 1024 / 1024 > maxMB) {
      antdMessage.error(`${fileTypeText}大小不能超过${maxMB}MB`);
      return false;
    }

    // 图片尺寸校验（所有图片都需要校验）
    if (isImage) {
      try {
        const { width, height } = await getImageDimensions(file);
        const error = validateImageDimensions(width, height);
        if (error) {
          antdMessage.error(error);
          return false;
        }
      } catch {
        antdMessage.error('无法读取图片尺寸，请检查文件是否损坏');
        return false;
      }
    }

    const imageCount = currentMedia.filter((m) => m.type === 'image').length;
    if (isImage && imageCount >= maxImage) {
      antdMessage.error(`该引擎最多上传${maxImage}张图片`);
      return false;
    }

    const videoCount = currentMedia.filter((m) => m.type === 'video').length;
    if (isVideo && videoCount >= maxVideo) {
      antdMessage.error(`该引擎最多上传${maxVideo}个视频`);
      return false;
    }

    const audioCount = currentMedia.filter((m) => m.type === 'audio').length;
    if (isAudio && audioCount >= maxAudio) {
      antdMessage.error(`该引擎最多上传${maxAudio}个音频`);
      return false;
    }

    let videoDuration = 0;
    let audioDuration = 0;
    if (isVideo) {
      try {
        videoDuration = await getVideoDuration(file);
        if (videoDuration < 2) {
          antdMessage.error('视频素材最短不能少于 2 秒');
          return false;
        }
        const existingVideoDuration = currentMedia
          .filter((m) => m.type === 'video')
          .reduce((sum, m) => sum + (m.duration || 0), 0);
        if (existingVideoDuration + videoDuration > 15) {
          antdMessage.error(`所有视频素材总时长不能超过 15 秒，当前 ${(existingVideoDuration + videoDuration).toFixed(1)} 秒`);
          return false;
        }
        // 视频尺寸校验
        const { width, height } = await getVideoDimensions(file);
        const error = validateVideoDimensions(width, height);
        if (error) {
          antdMessage.error(error);
          return false;
        }
      } catch {
        antdMessage.error('无法获取视频信息，请检查文件是否损坏');
        return false;
      }
    }


   

    if (isAudio) {
      try {
        audioDuration = await getAudioDuration(file);
        if (audioDuration < 2) {
          antdMessage.error('音频素材最短不能少于 2 秒');
          return false;
        }
        const existingAudioDuration = currentMedia
          .filter((m) => m.type === 'audio')
          .reduce((sum, m) => sum + (m.duration || 0), 0);
        if (existingAudioDuration + audioDuration > 15) {
          antdMessage.error(`所有音频素材总时长不能超过 15 秒，当前 ${(existingAudioDuration + audioDuration).toFixed(1)} 秒`);
          return false;
        }
      } catch {
        antdMessage.error('无法获取音频信息，请检查文件是否损坏');
        return false;
      }
    }

    setUploading(true);

    try {
      let res;
      if (isImage) {
        res = await uploadImage(file);
      } else if (isAudio) {
        res = await uploadAudio(file, audioDuration);
      } else {
        res = await uploadVideo(file, videoDuration);
      }
      const mediaType: 'image' | 'video' | 'audio' = isImage ? 'image' : (isAudio ? 'audio' : 'video');
      const newList = [...currentMedia, {
        name: file.name,
        type: mediaType,
        url: res.url,
        label: '',
        ...(isVideo && { duration: videoDuration }),
        ...(isAudio && { duration: audioDuration }),
      }];
      const labels = generateMediaLabels(newList);
      setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));
    } catch (error) {
      antdMessage.error('上传失败');
    } finally {
      setUploading(false);
    }

    return false;
  };

  const doUpload = async (file: File): Promise<false | { name: string; type: 'image' | 'video' | 'audio'; url: string; label: string; duration?: number }> => {
    const isImage = file.type.startsWith('image/');
    const isVideo = file.type.startsWith('video/');
    const isAudio = file.type.startsWith('audio/');

    if (!isImage && !isVideo && !isAudio) {
      antdMessage.error('仅支持图片、视频或音频文件');
      return false;
    }

    const maxMB = isVideo ? 100 : (isAudio ? 50 : 10);
    if (file.size / 1024 / 1024 > maxMB) {
      antdMessage.error(`${isVideo ? '视频' : (isAudio ? '音频' : '图片')}大小不能超过${maxMB}MB`);
      return false;
    }

    if (isAudio) {
      const audioExt = file.name.split('.').pop()?.toLowerCase();
      if (!['wav', 'mp3'].includes(audioExt || '')) {
        antdMessage.error('音频仅支持wav和mp3格式');
        return false;
      }
    }

    // 图片尺寸校验
    if (isImage) {
      try {
        const { width, height } = await getImageDimensions(file);
        const error = validateImageDimensions(width, height);
        if (error) {
          antdMessage.error(error);
          return false;
        }
      } catch {
        antdMessage.error('无法读取图片尺寸，请检查文件是否损坏');
        return false;
      }
    }

    let videoDuration = 0;
    let audioDuration = 0;
    if (isVideo) {
      try {
        videoDuration = await getVideoDuration(file);
        if (videoDuration < 2) {
          antdMessage.error('视频素材最短不能少于 2 秒');
          return false;
        }
        const latestMedia = useAppStore.getState().currentMedia;
        const existingVideoDuration = latestMedia
          .filter((m) => m.type === 'video')
          .reduce((sum, m) => sum + (m.duration || 0), 0);
        if (existingVideoDuration + videoDuration > 15) {
          antdMessage.error(`所有视频素材总时长不能超过 15 秒，当前 ${(existingVideoDuration + videoDuration).toFixed(1)} 秒`);
          return false;
        }
      } catch {
        antdMessage.error('无法获取视频信息，请检查文件是否损坏');
        return false;
      }
    }

    if (isAudio) {
      try {
        audioDuration = await getAudioDuration(file);
        if (audioDuration < 2) {
          antdMessage.error('音频素材最短不能少于 2 秒');
          return false;
        }
        const latestMedia = useAppStore.getState().currentMedia;
        const existingAudioDuration = latestMedia
          .filter((m) => m.type === 'audio')
          .reduce((sum, m) => sum + (m.duration || 0), 0);
        if (existingAudioDuration + audioDuration > 15) {
          antdMessage.error(`所有音频素材总时长不能超过 15 秒，当前 ${(existingAudioDuration + audioDuration).toFixed(1)} 秒`);
          return false;
        }
      } catch {
        antdMessage.error('无法获取音频信息，请检查文件是否损坏');
        return false;
      }
    }

    const mediaType: 'image' | 'video' | 'audio' = isImage ? 'image' : (isAudio ? 'audio' : 'video');
    const pendingMedia: MediaReference = {
      name: file.name,
      type: mediaType,
      url: '',
      label: '',
      ...(isVideo && { duration: videoDuration }),
      ...(isAudio && { duration: audioDuration }),
    };
    const latestMedia = useAppStore.getState().currentMedia as MediaReference[];
    if (!validateMediaReferencesBeforeAdd(latestMedia, [pendingMedia])) {
      return false;
    }

    try {
      let res;
      if (isImage) {
        res = await uploadImage(file);
      } else if (isAudio) {
        res = await uploadAudio(file, audioDuration);
      } else {
        res = await uploadVideo(file, videoDuration);
      }
      return {
        name: pendingMedia.name,
        type: pendingMedia.type,
        url: res.url,
        label: pendingMedia.label || '',
        ...(pendingMedia.duration !== undefined && { duration: pendingMedia.duration }),
      };
    } catch (error) {
      antdMessage.error('上传失败');
      return false;
    }
  };

  const handleBatchUpload = async (files: File[]) => {
    let successCount = 0;
    let failCount = 0;
    
    setUploading(true);
    
    for (const file of files) {
      const result = await doUpload(file);
      
      if (result) {
        const latestMedia = useAppStore.getState().currentMedia;
        const newList = [...latestMedia, result];
        const labels = generateMediaLabels(newList);
        setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));
        successCount++;
      } else {
        failCount++;
      }
    }
    
    setUploading(false);
    
    if (successCount > 0) {
      antdMessage.success(`成功上传${successCount}个文件${failCount > 0 ? `，${failCount}个文件上传失败` : ''}`);
    }
  };

  const getMediaDurationTotal = (items: MediaReference[], type: 'video' | 'audio') => {
    return items
      .filter((m) => m.type === type)
      .reduce((sum, m) => sum + (Number(m.duration) || 0), 0);
  };

  const validateMediaReferencesBeforeAdd = (baseMedia: MediaReference[], incoming: MediaReference[]) => {
    if (!incoming.length) return false;

    if (mediaType === 'image' && incoming.some((item) => item.type !== 'image')) {
      antdMessage.error('图片模式仅支持添加图片素材');
      return false;
    }

    if (incoming.some((item) => item.type === 'audio') && mediaType !== 'video') {
      antdMessage.error('仅视频模式支持添加音频素材');
      return false;
    }

    const imageCount = baseMedia.filter((m) => m.type === 'image').length;
    const videoCount = baseMedia.filter((m) => m.type === 'video').length;
    const audioCount = baseMedia.filter((m) => m.type === 'audio').length;
    const incomingImageCount = incoming.filter((m) => m.type === 'image').length;
    const incomingVideoCount = incoming.filter((m) => m.type === 'video').length;
    const incomingAudioCount = incoming.filter((m) => m.type === 'audio').length;

    if (imageCount + incomingImageCount > maxImage) {
      antdMessage.error(`该引擎最多上传${maxImage}张图片，当前还能添加 ${Math.max(0, maxImage - imageCount)} 张`);
      return false;
    }
    if (videoCount + incomingVideoCount > maxVideo) {
      antdMessage.error(`该引擎最多上传${maxVideo}个视频，当前还能添加 ${Math.max(0, maxVideo - videoCount)} 个`);
      return false;
    }
    if (audioCount + incomingAudioCount > maxAudio) {
      antdMessage.error(`该引擎最多上传${maxAudio}个音频，当前还能添加 ${Math.max(0, maxAudio - audioCount)} 个`);
      return false;
    }

    for (const item of incoming) {
      if (item.type !== 'video') continue;
      const duration = Number(item.duration);
      if (!Number.isFinite(duration) || duration <= 0) {
        antdMessage.error(`${item.name || '视频素材'}缺少视频秒数，不能用于 AI 创作`);
        return false;
      }
      if (duration < 2) {
        antdMessage.error(`${item.name || '视频素材'}最短不能少于 2 秒`);
        return false;
      }
      if (duration > 15) {
        antdMessage.error(`${item.name || '视频素材'}最长不能超过 15 秒`);
        return false;
      }
    }

    const totalVideoDuration = getMediaDurationTotal(baseMedia, 'video') + getMediaDurationTotal(incoming, 'video');
    if (totalVideoDuration > 15) {
      antdMessage.error(`所有视频素材总时长不能超过 15 秒，当前 ${totalVideoDuration.toFixed(1)} 秒`);
      return false;
    }

    const totalAudioDuration = getMediaDurationTotal(baseMedia, 'audio') + getMediaDurationTotal(incoming, 'audio');
    if (totalAudioDuration > 15) {
      antdMessage.error(`所有音频素材总时长不能超过 15 秒，当前 ${totalAudioDuration.toFixed(1)} 秒`);
      return false;
    }

    return true;
  };


  const normalizeUploadResourceHistoryItem = (item: UploadResourceHistoryItem): MediaReference | null => {
    const media = item.mediaReference;
    const refType = (media?.type || item.resourceType) as 'image' | 'video' | 'audio';
    const url = media?.url || item.resourceUrl || item.displayUrl || item.previewUrl || '';
    if (!url) {
      antdMessage.error(`${item.fileName || item.id} 缺少素材地址，不能用于 AI 创作`);
      return null;
    }
    if (refType === 'audio' && mediaType !== 'video') {
      antdMessage.error('仅视频模式支持添加音频素材');
      return null;
    }
    const duration = Number(media?.duration ?? item.durationSeconds);
    return {
      name: media?.name || item.fileName || item.id,
      type: refType,
      url,
      source: 'upload_resource',
      upload_resource_id: item.id,
      label: '',
      ...((refType === 'video' || refType === 'audio') && Number.isFinite(duration) && duration > 0 ? { duration } : {}),
    };
  };

  const handleUploadResourceHistorySelected = (items: UploadResourceHistoryItem[]) => {
    const normalized = items
      .map(normalizeUploadResourceHistoryItem)
      .filter(Boolean) as MediaReference[];
    if (!normalized.length) return;

    const latestMedia = useAppStore.getState().currentMedia as MediaReference[];
    if (!validateMediaReferencesBeforeAdd(latestMedia, normalized)) {
      return;
    }

    const newList = [...latestMedia, ...normalized];
    const labels = generateMediaLabels(newList);
    setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));
    antdMessage.success(`已添加 ${normalized.length} 个历史上传素材参考`);
  };

  const normalizePrivatePortraitAsset = (asset: PrivatePortraitSelectableAsset): MediaReference | null => {
    if (asset.assetType === 'Audio') {
      antdMessage.error('音频私域素材暂不支持用于 AI 创作');
      return null;
    }

    const refType: 'image' | 'video' = asset.assetType === 'Video' ? 'video' : 'image';
    const fallbackName = privateAssetPickerLibraryType === 'aigc_virtual' ? '虚拟素材' : '真人素材';
    const previewUrl = refType === 'video'
      ? (asset.videoCoverUrl || asset.previewUrl || asset.displayUrl || asset.providerUrl || '')
      : (asset.previewUrl || asset.displayUrl || asset.videoCoverUrl || asset.providerUrl || '');

    return {
      name: asset.name || fallbackName,
      type: refType,
      url: previewUrl,
      source: 'private_portrait_asset',
      private_asset_id: asset.id,
      label: '',
      ...(refType === 'video' && { duration: Number(asset.videoDuration) || undefined }),
    };
  };

  const openPrivatePortraitPicker = (libraryType: PrivatePortraitLibraryType) => {
    setPrivateAssetPickerLibraryType(libraryType);
    setPrivateAssetPickerOpen(true);
  };

  const handlePrivatePortraitAssetsSelected = (assets: PrivatePortraitSelectableAsset[]) => {
    const normalized = assets
      .map(normalizePrivatePortraitAsset)
      .filter(Boolean) as MediaReference[];
    const latestMedia = useAppStore.getState().currentMedia as MediaReference[];
    if (!validateMediaReferencesBeforeAdd(latestMedia, normalized)) {
      return;
    }

    const newList = [...latestMedia, ...normalized];
    const labels = generateMediaLabels(newList);
    setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));
    antdMessage.success(`已添加 ${normalized.length} 个${privateAssetPickerLibraryType === 'aigc_virtual' ? '虚拟' : '真人'}素材参考`);
  };

  const buildPreviewUrl = (url: string) => {
    if (!url) return '';
    if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('data:') || url.startsWith('blob:')) {
      return url;
    }
    const base = (import.meta.env.VITE_API_BASE || '').replace(/\/$/, '');
    return `${base}${url.startsWith('/') ? '' : '/'}${url}`;
  };


  const handleRemoveMedia = (index: number) => {
    const newList = currentMedia.filter((_, i) => i !== index);
    const labels = generateMediaLabels(newList);
    setCurrentMedia(newList.map((m, i) => ({ ...m, label: labels[i] })));
  };


  // const handleKeyPress = (e: React.KeyboardEvent) => {
  //   if (e.key === 'Enter' && !e.shiftKey) {
  //     e.preventDefault();
  //     handleSend();
  //   }
  // };

  // 检测光标前的 @ 符号
  const checkMention = (textarea: HTMLTextAreaElement, value: string) => {
    const cursorPos = textarea.selectionStart;
    const textBeforeCursor = value.slice(0, cursorPos);
    const atMatch = textBeforeCursor.match(/@([^@\s]*)$/);

    if (atMatch && currentMedia.length > 0) {
      setMentionVisible(true);
      return true;
    }
    setMentionVisible(false);
    return false;
  };

  // 输入框变化处理
  const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    const value = e.target.value;
    setInputValue(value);
    const textarea = e.target;
    checkMention(textarea, value);
  };

  // 键盘事件处理（ESC 关闭提及、Tab/Enter 选择）
  const handleInputKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (mentionVisible) {
      if (e.key === 'Escape') {
        setMentionVisible(false);
      }
    }
  };

  // 插入 @ 提及
  const insertMention = (label: string) => {
    const textarea = mentionInputRef.current?.resizableTextArea?.textArea;
    if (!textarea) return;

    const cursorPos = textarea.selectionStart;
    const textBefore = inputValue.slice(0, cursorPos);
    const textAfter = inputValue.slice(cursorPos);

    const atIndex = textBefore.lastIndexOf('@');
    if (atIndex === -1) {
      setMentionVisible(false);
      return;
    }

    const newValue = textBefore.slice(0, atIndex) + `@${label} ` + textAfter;
    setInputValue(newValue);
    setMentionVisible(false);

    setTimeout(() => {
      const pos = atIndex + label.length + 2;
      textarea.focus();
      textarea.setSelectionRange(pos, pos);
    }, 0);
  };



  const handleClosePreview = () => {
    setPreviewVisible(false);
    setPreviewUrl('');
    if (videoRef.current) {
      videoRef.current.pause();
    }
  };

  const handleDownload = (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (!previewUrl) return;
    const link = document.createElement('a');
    link.href = `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewUrl}&download=1`;
    link.download = previewType === 'image' ? 'image.png' : 'video.mp4';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };

  const getAttachmentMediaType = (ref: any): 'image' | 'video' | 'audio' => {
    const rawType = String(ref?.type || '').toLowerCase();
    const rawUrl = String(ref?.url || ref?.name || '').toLowerCase();
    if (rawType.includes('video') || /\.(mp4|mov|avi|webm|m4v)(\?|$)/.test(rawUrl)) return 'video';
    if (rawType.includes('audio') || /\.(mp3|wav|ogg|aac|m4a)(\?|$)/.test(rawUrl)) return 'audio';
    return 'image';
  };

  const buildAttachmentAssetUrl = (url: string): string => {
    if (!url) return '';
    if (/^https?:\/\//i.test(url)) return url;
    return `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${url}`;
  };

  const buildAttachmentDownloadUrl = (url: string): string => {
    const assetUrl = buildAttachmentAssetUrl(url);
    if (!assetUrl) return '';
    return `${assetUrl}${assetUrl.includes('?') ? '&' : '?'}download=1`;
  };

  const openAttachmentPreview = (ref: any) => {
    if (!ref?.url) return;
    setAttachmentPreviewUrl(ref.url);
    setAttachmentPreviewType(getAttachmentMediaType(ref));
    setAttachmentPreviewName(ref.name || '附件');
    setAttachmentPreviewVisible(true);
  };

  const downloadAttachmentRef = (ref: any, e?: React.MouseEvent) => {
    e?.preventDefault();
    e?.stopPropagation();
    if (!ref?.url) return;
    const link = document.createElement('a');
    link.href = buildAttachmentDownloadUrl(ref.url);
    const refType = getAttachmentMediaType(ref);
    link.download = ref.name || (refType === 'image' ? 'image.png' : refType === 'video' ? 'video.mp4' : 'audio.mp3');
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  };

  // ==================== 渲染 ====================

  const isFirstLastFrameComposer = mediaType === 'video' && referenceMode === 'first_last_frame';
  const composerCanSend = !uploading && (isFirstLastFrameComposer
    ? Boolean(inputValue.trim() || firstFrame)
    : Boolean(inputValue.trim() || currentMedia.length > 0));
  const composerModeLabel = mediaType === 'image'
    ? '图片生成'
    : isFirstLastFrameComposer
      ? '首尾帧视频'
      : '视频生成';
  const composerPlaceholder = mediaType === 'image'
    ? '输入画面描述，或上传图片参考风格、构图、主体与光影。例：@图片1 参考色调，生成一张简洁高级的产品海报。'
    : isFirstLastFrameComposer
      ? '首帧尾帧可以不传，如需传入建议描述首帧到尾帧的主体动作、镜头运动、节奏与转场。例：从首帧自然推进到尾帧，产品居中突出，动作平滑连贯。'
      : '上传最多12个参考素材，输入文字或 @ 引用参考内容，自由组合图、文、视频。例：@图片1 模仿 @视频1 的动作。';
  const composerHelperText = mediaType === 'image'
    ? '图片参考 · 适合海报、产品图、场景图与风格图生成'
    : isFirstLastFrameComposer
      ? '首帧必传 · 尾帧可选 · 适合首尾画面连贯过渡'
      : '多素材参考 · 支持图片 / 视频 / 音频，输入 @ 可快速引用素材';

  const maxImage = maxImageCount;
  const maxVideo = maxVideoCount;
  const maxAudio = currentEngine?.maxAudioCount ?? 1;

  return (
    <Layout className="ai-create-page" style={{
      margin: '-24px -32px -32px',
      borderRadius: 22,
      height: 'calc(100vh - 34px)',
      background: '#fff',

      overflow: 'hidden',
    }}>
      {/* 隐藏的音频播放器 */}
      <audio
        id="audio-player"
        src={playingAudioUrl || null}
        autoPlay
        onEnded={() => setPlayingAudioUrl(null)}
        style={{ display: 'none' }}
      />
      {/* 左侧边栏 - 对话列表（已隐藏，保留代码） */}
      {false && (
        <Sider
          trigger={null}
          collapsible
          collapsed={collapsed}
          width={220}
          style={{
            background: 'rgba(255,255,255,0.7)',
            backdropFilter: 'blur(16px)',
            borderRight: '1px solid rgba(139, 92, 246, 0.08)',
          }}
        >
          <div style={{ padding: 12 }}>
            <Button
              type="text"
              icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
              onClick={() => setCollapsed(!collapsed)}
              style={{ marginBottom: 12, width: '100%' }}
            />

            {!collapsed && (
              <Button
                block 
                type="primary"
                icon={<PlusOutlined />}
                onClick={handleNewChat}
                style={{ marginBottom: 16, borderRadius: 8 }}
              >
                新对话
              </Button>
            )}
           

            {!collapsed && conversations.length > 0 && (
              <div style={{ maxHeight: 'calc(100vh - 120px)', overflowY: 'auto' }}>
                {conversations.map((conversation) => (
                  <div
                    key={conversation.id}
                    onClick={() => handleSelectChat(conversation.id)}
                    style={{
                      display: 'flex',
                      alignItems: 'center',
                      padding: '10px 12px',
                      marginBottom: 4,
                      borderRadius: 10,
                      cursor: 'pointer',
                      background: currentConversationId === conversation.id ? '#FAFBFC' : 'transparent',
                      border: currentConversationId === conversation.id ? '1px solid #ede9fe' : 'none',
                      transition: 'all 0.2s',
                    }}
                    onMouseEnter={(e) => {
                      e.currentTarget.style.background = currentConversationId === conversation.id ? '#FAFBFC' : '#FFFFFF';
                    }}
                    onMouseLeave={(e) => {
                      e.currentTarget.style.background = currentConversationId === conversation.id ? '#FAFBFC' : 'transparent';
                    }}
                  >
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <p style={{ margin: 0, fontSize: 13, fontWeight: 500, color: '#2f3440', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                        {conversation.title}
                      </p>
                      <p style={{ margin: 2, fontSize: 11, color: '#98a2b3', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                        {conversation.lastMessage || '暂无消息'}
                      </p>
                    </div>
                    <Popconfirm
                      title="确定删除此对话？"
                      onConfirm={() => handleDeleteChat(conversation.id)}
                      okText="确定"
                      cancelText="取消"
                    >
                      <Button
                        type="text"
                        icon={<DeleteOutlined />}
                        style={{ color: '#98a2b3', padding: 4 }}
                        onClick={(e) => e.stopPropagation()}
                      />
                    </Popconfirm>
                  </div>
                ))}
              </div>
            )}
          </div>
        </Sider>
      )}

      {/* 主内容区 */}
      <Layout style={{ display: 'flex', flex: 1, background: '#fff' }}>
        {/* 头部 - 显示对话标题和模型信息 */}
        <div className="animate-fadeInUp" style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          padding: '16px 24px', borderRadius: 22,
          background: 'rgb(255, 255, 255)',
          backdropFilter: 'blur(22px)',
          border: '1px solid rgba(231, 234, 240, 0.82)',
          // boxShadow: '0 16px 44px rgba(31, 41, 55, 0.06)',
          position: 'relative', overflow: 'hidden', flexWrap: 'wrap', gap: 12,
        }}>
          <div style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 16 }}>
            <div style={{ width: '15%', height: 1, background: 'linear-gradient(90deg, transparent, rgba(117,106,136,0.18), rgba(232,227,236,0.48), transparent)', borderRadius: 1 }} />
            <div style={{ flex: 1, minWidth: 0, textAlign: 'center' }}>
              <h2 style={{
                margin: 0,
                fontSize: 18,
                fontWeight: 700,
                color: '#8b5cf6',
                letterSpacing: 0.4,
              }}>
                AI创作
              </h2>
              <p style={{ fontSize: 13, color: '#667085', margin: '4px 0 0 0' }}>
                输入想法、剧本或上传参考，智能生成视频/图片
              </p>
            </div>
            <div style={{ width: '15%', height: 1, background: 'linear-gradient(90deg, transparent, rgba(232,227,236,0.48), rgba(117,106,136,0.18), transparent)', borderRadius: 1 }} />
          </div>
        </div>

        {/* 消息区域 */}
        <Content
          style={{
            flex: 1,
            margin: 0,
            padding: '20px 24px 22px',
            boxSizing: 'border-box',
            display: 'flex',
            flexDirection: 'column',
            overflow: 'hidden',
            minHeight: 0,

          }}
        >
          {/* 空状态 - 没有对话或当前对话没有消息时显示 */}
          {gen_list.length === 0 && (
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center' }}>
              <div
                style={{
                  width: 80,
                  height: 80,
                  borderRadius: 50,
                  background: 'linear-gradient(135deg, #8b5cf6 0%, #ddd6fe 100%)',
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  marginBottom: 16,
                }}
              >
                <RobotOutlined style={{ fontSize: 40, color: '#fff' }} />
              </div>
              <h2 style={{ margin: 0, fontSize: 18, fontWeight: 500, color: '#2f3440' }}>
                你好，想创作什么？
              </h2>
              <p style={{ margin: 8, fontSize: 13, color: '#98a2b3' }}>
                输入想法、剧本或上传参考，开始你的创作之旅
              </p>
            </div>
          )}

          {/* 消息列表 - gen_list 有数据时显示 */}
          {gen_list.length > 0 && (
            <div
              ref={scrollContainerRef}
              className="ai-create-scroll"
              style={{
                flex: 1,
                overflowY: 'auto',
                paddingRight: 10,
                paddingBottom: 18,
                // background: 'linear-gradient(180deg, rgba(255,255,255,0.72), rgba(255,255,255,0))',
                background: '#fff',
                // borderRadius: 22,
              }}
              onScroll={(e) => {
                const target = e.currentTarget;
                const now = Date.now();
                const isAutoScroll = now - lastAutoScrollTime.current < 500;
                if (!isAutoScroll && isInitialLoadDone.current && target.scrollTop <= 50 && !isLoadingMore && gen_list.length < Totalnumber) {
                  handleLoadMore();
                }
              }}
            >
              {/* 加载更多提示 */}
              {isLoadingMore && (
                <div style={{ padding: '8px 0', textAlign: 'center', marginBottom: 16 }}>
                  <span style={{ fontSize: 12, color: '#8b5cf6' }}>加载中...</span>
                </div>
              )}
              {/* 遍历消息列表 */}
              {(() => {
                const msgApi = message;
                return gen_list.map((msg) => (
                  <div
                    key={msg.id}
                    style={{
                      width: '100%',
                      display: 'flex',
                      justifyContent: 'flex-start',  // 所有消息左对齐
                      marginBottom: 16,
                    }}
                  >
                    <div style={{ width: '100%', display: 'flex', gap: 10 }}>
                      {/* 头像 */}
                      <div
                        style={{
                          width: 36,
                          height: 36,
                          borderRadius: 12,
                          background: 'linear-gradient(135deg, #8b5cf6 0%, #ddd6fe 100%)',
                          display: 'flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          flexShrink: 0,
                          // boxShadow: '0 8px 18px rgba(47, 52, 64, 0.15)' ,
                        }}
                      >
                        <RobotOutlined style={{ color: '#fff', fontSize: 16 }} />
                      </div>

                      {/* 消息内容 */}
                      <div style={{ flex: 1 }}>
                        {/* 时间戳和参数信息 */}


                        {/* 消息气泡 */}
                        <div
                          style={{
                            background: 'rgba(255, 255, 255, 0.92)',
                            backdropFilter: 'blur(18px)',
                            borderRadius: '22px',
                            padding: '14px 16px',
                            width: '70%',
                            minWidth: 500,
                            boxSizing: 'border-box',
                            boxShadow: '0 18px 50px rgba(47, 52, 64, 0.075)',
                            position: 'relative',
                            border: '1px solid rgba(231, 234, 240, 0.9)',

                          }}
                        >
                          <div style={{ margin: 4, fontSize: 11, color: '#98a2b3', textAlign: 'left', display: 'flex', flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
                            <span>{msg.createdAt?.replace('T', ' ').split('.')[0]}</span>
                            <span style={{
                              background: msg.genType === 'image' ? 'rgba(139, 92, 246, 0.10)' : 'rgba(139, 92, 246, 0.10)',
                              color: msg.genType === 'image' ? '#8b5cf6' : '#8b5cf6',
                              padding: '2px 8px',
                              borderRadius: 12,
                              fontWeight: 500,
                              fontSize: 11,
                              marginLeft: 8
                            }}>
                              {msg.genType === 'image' ? '图片生成' : '视频生成'}
                            </span>
                          </div>
                          {/* 附件详情 - 右上角 */}
                          {msg.mediaReferences && msg.mediaReferences.length > 0 && (
                            <div style={{ position: 'absolute', top: 8, right: 8, zIndex: 100 }}>
                              <span style={{ padding: '4px 12px', borderRadius: 16, color: '#8b5cf6', cursor: 'pointer', fontWeight: 500, border: '1px solid rgba(139, 92, 246, 0.2)', background: 'rgba(139, 92, 246, 0.04)' }} onClick={(e) => { e.stopPropagation(); const target = e.currentTarget as HTMLElement; const rect = target.getBoundingClientRect(); setAttachmentPopupPosition({ x: rect.left, y: rect.top - 10 }); setAttachmentPopupMessageId(msg.id); setAttachmentPopupVisible(true); }}>附件详情</span>
                            </div>
                          )}
                          {/* 操作按钮 - 右下角 */}
                          <div style={{ position: 'absolute', bottom: 8, right: 8, zIndex: 100, display: 'flex', gap: 6 }}>
                            <button
                              onClick={(e) => {
                                e.stopPropagation();
                                setInputValue(msg.originalPrompt || '');
                                if (msg.genType) {
                                  setMediaType(msg.genType);
                                }
                                if (msg.mediaReferences && msg.mediaReferences.length > 0) {
                                  const hasFirstLastFrame = msg.mediaReferences.some((ref: any) => ref.role === 'first_frame' || ref.role === 'last_frame');
                                  if (hasFirstLastFrame && msg.genType === 'video') {
                                    const first = msg.mediaReferences.find((ref: any) => ref.role === 'first_frame');
                                    const last = msg.mediaReferences.find((ref: any) => ref.role === 'last_frame');
                                    setFirstFrame(first ? { ...first, label: first.label || '', duration: first.duration } : null);
                                    setLastFrame(last ? { ...last, label: last.label || '', duration: last.duration } : null);
                                    setCurrentMedia([]);
                                    setReferenceMode('first_last_frame');
                                  } else {
                                    setCurrentMedia(msg.mediaReferences.map((ref: any) => ({
                                      name: ref.name,
                                      type: ref.type,
                                      url: ref.url,
                                      label: ref.label || '',
                                      role: ref.role,
                                      duration: ref.duration,
                                    })));
                                    setFirstFrame(null);
                                    setLastFrame(null);
                                    setReferenceMode('universal');
                                  }
                                } else {
                                  setCurrentMedia([]);
                                  setFirstFrame(null);
                                  setLastFrame(null);
                                }
                                msgApi.success('已加载到编辑区');
                              }}
                              style={{
                                height: 28,
                                padding: '0 10px',
                                borderRadius: 10,
                                border: 'none',
                                background: 'rgba(139, 92, 246, 0.08)',
                                color: '#8b5cf6',
                                cursor: 'pointer',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                transition: 'all 0.2s ease',
                                gap: 4,
                                fontSize: 12,
                              }}
                              onMouseEnter={(e) => {
                                e.currentTarget.style.background = 'rgba(139, 92, 246, 0.15)';
                              }}
                              onMouseLeave={(e) => {
                                e.currentTarget.style.background = 'rgba(139, 92, 246, 0.08)';
                              }}
                            >
                              <ReloadOutlined style={{ fontSize: 12 }} />
                              重新编辑
                            </button>
                            <Popconfirm
                              title="确定要删除吗？"
                              onConfirm={async () => {
                                try {
                                  await deleteHistory(msg.id);
                                  msgApi.success('删除成功');
                                  // 直接在本地列表中删除对应数据
                                  setGen_list(prev => prev.filter(item => item.id !== msg.id));
                                  setTotalnumber(prev => prev - 1);
                                } catch (error: any) {

                                  const errorMsg = error?.response?.data?.message || error?.message || '删除失败';
                                  msgApi.error(errorMsg);
                                }
                              }}
                              okText="确定"
                              cancelText="取消"
                            >
                              <button
                                onClick={(e) => e.stopPropagation()}
                                style={{
                                  height: 28,
                                  padding: '0 10px',
                                  borderRadius: 10,
                                  border: 'none',
                                  background: 'rgba(139, 92, 246, 0.08)',
                                  color: '#8b5cf6',
                                  cursor: 'pointer',
                                  display: 'flex',
                                  alignItems: 'center',
                                  justifyContent: 'center',
                                  transition: 'all 0.2s ease',
                                  gap: 4,
                                  fontSize: 12,
                                }}
                                onMouseEnter={(e) => {
                                  e.currentTarget.style.background = 'rgba(164, 91, 91, 0.1)';
                                  e.currentTarget.style.color = '#A45B5B';
                                }}
                                onMouseLeave={(e) => {
                                  e.currentTarget.style.background = 'rgba(139, 92, 246, 0.08)';
                                  e.currentTarget.style.color = '#8b5cf6';
                                }}
                              >
                                <DeleteOutlined style={{ fontSize: 12 }} />
                                删除
                              </button>
                            </Popconfirm>
                          </div>

                          {/* 文本内容 */}
                          {/* <div
                            style={{
                              width: '100%',
                              position: 'relative',
                              margin: '8px 0',
                              padding: '12px 16px',
                              backgroundColor: 'rgba(139, 92, 246, 0.04)',
                              borderRadius: 10,
                              border: '1px solid rgba(139, 92, 246, 0.08)',
                              fontSize: 13,
                              color: '#475467',
                              lineHeight: 1.6,
                              cursor: 'pointer',
                              transition: 'all 0.2s ease',
                              boxShadow: '0 1px 3px rgba(47, 52, 64, 0.035)',
                            }}
                            onMouseEnter={() => {
                              setExpandedPrompts(prev => {
                                const newSet = new Set(prev);
                                newSet.add(msg.id);
                                return newSet;
                              });
                            }}
                            onMouseLeave={() => {
                              setExpandedPrompts(prev => {
                                const newSet = new Set(prev);
                                newSet.delete(msg.id);
                                return newSet;
                              });
                            }}
                          >
                            默认显示：一行省略
                            <div style={{
                              width: '100%',
                              overflow: 'hidden',
                              textOverflow: 'ellipsis',
                              whiteSpace: 'nowrap',
                              display: expandedPrompts.has(msg.id) ? 'none' : 'block',
                            }}>
                              {msg.originalPrompt}
                            </div>

                            鼠标移入显示：完整内容
                            <div style={{
                              width: '100%',
                              maxHeight: 200,
                              overflowY: 'auto',
                              display: expandedPrompts.has(msg.id) ? 'block' : 'none',
                              wordBreak: 'break-word',
                            }}>
                              {msg.originalPrompt}
                            </div>
                          </div> */}

                          {/* 根据 status 显示不同内容 */}
                          {(msg.status === 'generating' || msg.status === 'failed' || msg.status === 'completed') && (
                            <div style={{
                              display: 'flex', gap: 16, marginBottom: 16, marginTop: 16, width: '100%', alignItems: 'flex-start',

                            }}>
                              <div style={{ width: '50%', overflow: 'hidden', borderRadius: 12, position: 'relative', height: 220, border: '1px solid #E7EAF0', boxShadow: '0 4px 12px rgba(139, 92, 246, 0.08)', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg, #ffffff 0%, #FAFBFC 100%)' }}>
                                {msg.status === 'generating' ? (
                                  <>
                                    <div style={{ position: 'absolute', top: 12, left: 12, display: 'flex', alignItems: 'center', gap: 8, zIndex: 2 }}>
                                      {/* <div style={{ width: 20, height: 20, border: '2px solid #ddd6fe', borderTopColor: '#8b5cf6', borderRadius: '50%', animation: 'spin 1s linear infinite' }} /> */}
                                    </div>
                                    <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.6) 50%, transparent 100%)', animation: 'shimmer 2s infinite' }} />
                                    <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16 }}>
                                      <div style={{ width: 64, height: 64, borderRadius: '50%', background: 'rgba(139, 92, 246, 0.1)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 0 30px rgba(139, 92, 246, 0.2)' }}>
                                        <div style={{ width: 48, height: 48, border: '3px solid #ddd6fe', borderTopColor: '#8b5cf6', borderRadius: '50%', animation: 'spin 1s linear infinite' }} />
                                      </div>
                                      <span style={{ fontSize: 12, color: '#8b5cf6', fontWeight: 500 }}>生成中...</span>

                                      {/* <div style={{ display: 'flex', gap: 4 }}>
                                        <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#8b5cf6', animation: 'pulse 1.5s ease-in-out infinite' }} />
                                        <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#a8a1b6', animation: 'pulse 1.5s ease-in-out 0.2s infinite' }} />
                                        <div style={{ width: 6, height: 6, borderRadius: '50%', background: '#ddd6fe', animation: 'pulse 1.5s ease-in-out 0.4s infinite' }} />
                                      </div> */}
                                    </div>
                                  </>
                                ) : msg.status === 'failed' ? (
                                  <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
                                    <div style={{ width: 48, height: 48, borderRadius: '50%', background: 'rgba(168, 90, 106, 0.10)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                                      <WarningOutlined style={{ color: '#A45B5B', fontSize: 22 }} />
                                    </div>
                                    <span style={{ fontSize: 14, color: '#A45B5B', fontWeight: 620 }}>生成失败（积分已退）</span>
                                    {msg.errorMessage && (
                                      <span style={{ fontSize: 13, color: '#A45B5B', textAlign: 'center', padding: '0 8px', lineHeight: 1.5 }}>{msg.errorMessage}</span>
                                    )}
                                  </div>
                                ) : (
                                  <>
                                    {msg.genType === 'image' ? (
                                      <img src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}/static${msg.imageUrl}&w=300&p=50`} alt={msg.name} style={{ width: '100%', height: '100%', borderRadius: 12, objectFit: 'contain', cursor: 'pointer', transition: 'transform 0.3s ease' }} onClick={() => { setPreviewUrl(msg.imageUrl); setPreviewType('image'); setPreviewVisible(true); }} onMouseEnter={(e) => { e.currentTarget.style.transform = 'scale(1.05)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }} />
                                    ) : (
                                      <>
                                        <img src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}/static${msg.videoCoverUrl}&w=300&p=50`} alt={msg.name} style={{ width: '100%', height: '100%', borderRadius: 12, objectFit: 'contain', cursor: 'pointer', transition: 'transform 0.3s ease' }} onClick={() => { setPreviewUrl(msg.videoUrl); setPreviewType('video'); setPreviewVisible(true); }} onMouseEnter={(e) => { e.currentTarget.style.transform = 'scale(1.05)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }} />
                                        <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', width: 56, height: 56, background: 'rgba(47, 52, 64, 0.72)', borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none', boxShadow: '0 10px 24px rgba(47, 52, 64, 0.22)' }}>
                                          <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"><path d="M8 5v14l11-7z" /></svg>
                                        </div>
                                      </>
                                    )}
                                  </>
                                )}
                              </div>
                              <div style={{ width: '50%', display: 'flex', flexDirection: 'column', gap: 12 }}>
                                <div style={{ background: '#FFFFFF', borderRadius: 12, padding: 12, border: '1px solid #E7EAF0', flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                                  <p style={{ width: '100%', height: 150, overflow: 'auto', padding: 0, marginTop: 0, marginBottom: 0, lineHeight: 2, color: '#475467', fontSize: 13 }}>{msg.originalPrompt}</p>
                                </div>
                                <div style={{ fontSize: 12, color: '#667085', textAlign: 'left', display: 'flex', flexWrap: 'wrap', gap: 12, alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
                                  <span style={{
                                    // background: 'rgba(139, 92, 246, 0.08)',
                                    borderRadius: 16, color: '#8b5cf6', fontWeight: 500
                                  }}>{msg.engineSnapshot.name}</span>
                                  <span style={{
                                    // background: 'rgba(139, 92, 246, 0.08)',
                                    borderRadius: 16, color: '#667085'
                                  }}>{msg.genType === 'image' ? `${msg.imageProportion || ''} · ${msg.imagePx || ''} · ${msg.imageSize || ''}` : `${msg.duration || ''}秒 · ${msg.aspectRatio || ''} · ${msg.resolution || ''}`}</span>
                                  <span style={{
                                    // background: 'rgba(164, 91, 91, 0.08)',
                                    fontSize: 14,
                                    borderRadius: 16, color: '#8b5cf6'
                                  }}>消耗积分：{msg.creditsCost}</span>

                                </div>

                              </div>
                            </div>

                          )}
                        </div>


                      </div>

                    </div>
                  </div>
                ))
              })()}


              {/* 消息列表底部标记 - 用于自动滚动 */}
              <div ref={messagesEndRef} />
            </div>
          )}

          {/* 附件详情悬浮窗 - 参考素材 hover 块风格 */}
          {attachmentPopupVisible && attachmentPopupMessageId && (() => {
            const currentAttachmentMessage = gen_list.find((msg: any) => msg.id === attachmentPopupMessageId);
            const attachmentRefs = currentAttachmentMessage?.mediaReferences || [];
            return (
              <>
                {/* 遮罩层 - 点击关闭悬浮窗 */}
                <div
                  style={{
                    position: 'fixed',
                    top: 0,
                    left: 0,
                    right: 0,
                    bottom: 0,
                    background: 'transparent',
                    zIndex: 9998,
                  }}
                  onClick={() => {
                    setAttachmentPopupVisible(false);
                    setAttachmentPopupMessageId(null);
                  }}
                />
                <div
                  className="ai-reference-expanded-tray ai-attachment-popover"
                  style={{
                    position: 'fixed',
                    top: `max(84px, ${attachmentPopupPosition.y - 96}px)`,
                    left: `max(24px, min(${attachmentPopupPosition.x - 250}px, calc(100vw - 456px)))`,
                    width: 424,
                    padding: '12px 12px 10px',
                    borderRadius: 18,
                    background: 'rgba(255,255,255,0.98)',
                    border: '1px solid #E7EAF0',
                    boxShadow: '0 24px 60px rgba(31, 41, 55, 0.12)',
                    backdropFilter: 'blur(18px)',
                    zIndex: 9999,
                    pointerEvents: 'auto',
                  }}
                  onClick={(e) => e.stopPropagation()}
                >
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                      <span style={{ fontSize: 13, color: '#344054', fontWeight: 800 }}>参考附件</span>
                      <span style={{ fontSize: 11, color: '#98A2B3', fontWeight: 600 }}>点击素材查看，或直接下载原文件</span>
                    </div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                      {/* <span style={{ fontSize: 11, color: '#98A2B3', fontWeight: 700 }}>{attachmentRefs.length}/12</span> */}
                      <button
                        onClick={() => {
                          setAttachmentPopupVisible(false);
                          setAttachmentPopupMessageId(null);
                        }}
                        style={{
                          width: 26,
                          height: 26,
                          borderRadius: '50%',
                          border: '1px solid transparent',
                          background: '#F6F7FA',
                          cursor: 'pointer',
                          color: '#98a2b3',
                          display: 'flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          transition: 'all 0.2s ease',
                        }}
                        onMouseEnter={(e) => {
                          e.currentTarget.style.background = '#EEF1F6';
                          e.currentTarget.style.color = '#2f3440';
                        }}
                        onMouseLeave={(e) => {
                          e.currentTarget.style.background = '#F6F7FA';
                          e.currentTarget.style.color = '#98a2b3';
                        }}
                      >
                        <CloseOutlined style={{ fontSize: 12 }} />
                      </button>
                    </div>
                  </div>

                  <div className="ai-reference-tray-scroll" style={{ display: 'flex', gap: 10, overflowX: 'auto', padding: '2px 2px 4px' }}>
                    {attachmentRefs.map((ref: any, idx: number) => {
                      const refType = getAttachmentMediaType(ref);
                      const label = ref.label || (ref.role === 'first_frame' ? '首帧' : ref.role === 'last_frame' ? '尾帧' : `${refType === 'image' ? '图片' : refType === 'video' ? '视频' : '音频'}${idx + 1}`);
                      return (
                        <div
                          key={`${ref.url || ref.name || idx}-${idx}`}
                          style={{
                            flex: '0 0 92px',
                            width: 92,
                            borderRadius: 16,
                            background: '#FFFFFF',
                            border: '1px solid #E7EAF0',
                            boxShadow: '0 8px 18px rgba(31, 41, 55, 0.06)',
                            padding: 7,
                            boxSizing: 'border-box',
                          }}
                        >
                          <div
                            onClick={(e) => {
                              if (refType === 'audio') {
                                e.stopPropagation();
                                handleAudioPlay(ref.url);
                              } else {
                                openAttachmentPreview(ref);
                                setAttachmentPopupVisible(false);
                                setAttachmentPopupMessageId(null);
                              }
                            }}
                            style={{
                              position: 'relative',
                              width: '100%',
                              height: 70,
                              borderRadius: 12,
                              overflow: 'hidden',
                              cursor: 'pointer',
                              background: '#F7F8FA',
                              border: '1px solid rgba(231, 234, 240, 0.9)',
                            }}
                          >
                            {refType === 'image' ? (
                              <img
                                src={buildAttachmentAssetUrl(ref.url)}
                                alt={ref.name || label}
                                style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
                              />
                            ) : refType === 'video' ? (
                              <>
                                <video
                                  src={buildAttachmentAssetUrl(ref.url)}
                                  muted
                                  playsInline
                                  style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
                                />
                                <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(31, 41, 55, 0.08)' }}>
                                  <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'rgba(47, 52, 64, 0.72)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 8px 18px rgba(31, 41, 55, 0.22)' }}>
                                    <svg width="14" height="14" viewBox="0 0 24 24" fill="#fff"><path d="M8 5v14l11-7z" /></svg>
                                  </div>
                                </div>
                              </>
                            ) : (
                              <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)' }}>
                                {playingAudioUrl === (ref.url.startsWith('http') ? ref.url : `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${ref.url}`) ? (
                                  <PauseOutlined style={{ fontSize: 24, color: '#fff' }} />
                                ) : (
                                  <AudioOutlined style={{ fontSize: 24, color: '#fff' }} />
                                )}
                              </div>
                            )}
                            {/* <span style={{ position: 'absolute', left: 6, top: 6, padding: '2px 6px', borderRadius: 999, background: 'rgba(255,255,255,0.92)', color: '#8b5cf6', fontSize: 10, fontWeight: 800, boxShadow: '0 4px 10px rgba(31, 41, 55, 0.08)' }}>
                              {label}
                            </span> */}
                          </div>

                          <div title={ref.name || label} style={{ marginTop: 6, color: '#667085', fontSize: 10, fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', textAlign: 'center' }}>
                            {ref.name || label}
                          </div>

                          <div style={{ display: 'flex', gap: 5, marginTop: 7 }}>
                            <button
                              onClick={() => {
                                openAttachmentPreview(ref);
                                setAttachmentPopupVisible(false);
                                setAttachmentPopupMessageId(null);
                              }}
                              style={{
                                flex: 1,
                                height: 24,
                                borderRadius: 9,
                                border: '1px solid #E7EAF0',
                                background: '#F8FAFC',
                                color: '#8b5cf6',
                                fontSize: 11,
                                fontWeight: 700,
                                cursor: 'pointer',
                                transition: 'all 0.2s ease',
                              }}
                              onMouseEnter={(e) => { e.currentTarget.style.background = '#EEF1F6'; }}
                              onMouseLeave={(e) => { e.currentTarget.style.background = '#F8FAFC'; }}
                            >
                              查看
                            </button>
                            {/* <button
                              onClick={(e) => downloadAttachmentRef(ref, e)}
                              title="下载"
                              style={{
                                width: 26,
                                height: 24,
                                borderRadius: 9,
                                border: '1px solid #E7EAF0',
                                background: '#FFFFFF',
                                color: '#667085',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                cursor: 'pointer',
                                transition: 'all 0.2s ease',
                              }}
                              onMouseEnter={(e) => { e.currentTarget.style.background = '#EEF1F6'; e.currentTarget.style.color = '#2f3440'; }}
                              onMouseLeave={(e) => { e.currentTarget.style.background = '#FFFFFF'; e.currentTarget.style.color = '#667085'; }}
                            >
                              <DownloadOutlined style={{ fontSize: 12 }} />
                            </button> */}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              </>
            );
          })()}


          {/* 输入区域 - 始终显示 */}
          <div
            style={{
              position: 'relative',
              background: '#ffffff',
              borderRadius: 24,
              padding: '18px 72px 16px 20px',
              boxShadow: '0 22px 64px rgba(31, 41, 55, 0.08), 0 1px 0 rgba(255,255,255,0.98) inset',
              transition: 'all 0.25s ease',
              border: '1px solid rgba(231, 234, 240, 0.78)',
              backdropFilter: 'blur(24px)',
            }}
          >
            {/* <div>12312</div> */}


            {/* 上方输入布局 */}
            <div style={{ display: 'flex', gap: isFirstLastFrameComposer ? 18 : 18, alignItems: 'flex-end', marginBottom: 14 }}>
              
              {/* 左侧附件区域 */}
              <div style={{ width: isFirstLastFrameComposer ? 220 : 70, minWidth: isFirstLastFrameComposer ? 220 : 70, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start', paddingTop: 2, gap: 8 }}>


                {/* 首尾帧模式 */}
                {mediaType === 'video' && referenceMode === 'first_last_frame' ? (
                  <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'stretch', gap: 12, width: '100%', height: 100 }}>
                    {/* 首帧 */}
                    <div style={{ position: 'relative', flex: 1, minWidth: 0, height: 100, borderRadius: 12, border: '1px solid #E7EAF0', background: '#ffffff', boxShadow: '0 6px 16px rgba(47, 52, 64, 0.04)', overflow: 'hidden' }}>
                      <div style={{ position: 'absolute', top: 8, left: 10, right: 10, display: 'flex', alignItems: 'center', justifyContent: 'space-between', zIndex: 2 }}>
                        <span style={{ fontSize: 11, fontWeight: 600, color: '#8b5cf6', lineHeight: 1 }}>首帧(可选)</span>
                      </div>
                      {firstFrame ? (
                        <div style={{ position: 'absolute', left: 10, right: 10, bottom: 10, height: 64 }}>
                          <img
                            src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${firstFrame.url}`}
                            alt={firstFrame.name}
                            onClick={() => {
                              setAttachmentPreviewUrl(firstFrame.url);
                              setAttachmentPreviewType('image');
                              setAttachmentPreviewName(firstFrame.name);
                              setAttachmentPreviewVisible(true);
                            }}
                            style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 8, cursor: 'pointer', border: '1px solid rgba(139, 92, 246, 0.2)', boxShadow: '0 3px 10px rgba(47, 52, 64, 0.06)' }}
                          />
                          <button
                            onClick={handleRemoveFirstFrame}
                            style={{ position: 'absolute', top: -6, right: -6, width: 18, height: 18, border: 'none', background: '#A45B5B', borderRadius: 50, cursor: 'pointer', color: '#fff', fontSize: 9, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 2px 4px rgba(164, 91, 91, 0.3)', zIndex: 10 }}
                          >
                            <DeleteOutlined style={{ fontSize: 9 }} />
                          </button>
                        </div>
                      ) : (
                        <UploadSelector
                          accept="image/*"
                          multiple={false}
                          onLocalSelect={(files) => {
                            if (files.length > 0) {
                              handleUpload(files[0], 'first');
                            }
                          }}
                          onHistorySelect={(items) => {
                            if (items.length > 0) {
                              const item = items[0];
                              const mediaRef: MediaReference = {
                                name: item.fileName || '',
                                type: 'image',
                                url: item.resourceUrl || item.previewUrl || item.displayUrl || '',
                                role: 'first_frame',
                                label: '',
                              };
                              setFirstFrame(mediaRef);
                              antdMessage.success('成功添加首帧');
                            }
                          }}
                          onPortraitSelect={(assets) => {
                            if (assets.length > 0) {
                              const asset = assets[0];
                              const previewUrl = asset.previewUrl || asset.displayUrl || asset.videoCoverUrl || asset.providerUrl || '';
                              const mediaRef: MediaReference = {
                                name: asset.name || '首帧图片',
                                type: 'image',
                                url: previewUrl,
                                role: 'first_frame',
                                label: '',
                              };
                              setFirstFrame(mediaRef);
                              antdMessage.success('成功添加首帧');
                            }
                          }}
                          uploading={uploading}
                        >
                          <div
                            style={{ position: 'absolute', left: 10, right: 10, bottom: 10, height: 64, borderRadius: 8, border: '1px dashed rgba(139, 92, 246, 0.28)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', transition: 'all 0.25s ease', backgroundColor: 'rgba(139, 92, 246, 0.04)', flexDirection: 'column', gap: 4 }}
                            onMouseEnter={(e) => { e.currentTarget.style.borderColor = '#a78bfa'; e.currentTarget.style.backgroundColor = 'rgba(139, 92, 246, 0.08)'; }}
                            onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'rgba(139, 92, 246, 0.28)'; e.currentTarget.style.backgroundColor = 'rgba(139, 92, 246, 0.04)'; }}
                          >
                            <PlusOutlined style={{ fontSize: 18, color: '#8b5cf6' }} />
                            <span style={{ fontSize: 12, color: '#8b5cf6', fontWeight: 500 }}>上传首帧</span>
                          </div>
                        </UploadSelector>
                      )}
                    </div>

                    {/* 调换按钮 */}
                    <button
                      onClick={handleSwapFrames}
                      disabled={!firstFrame || !lastFrame}
                      title="调换首尾帧"
                      style={{ width: 32, height: 32, alignSelf: 'center', borderRadius: 50, border: '1px solid rgba(231, 234, 240, 0.95)', background: firstFrame && lastFrame ? 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)' : '#F3F5F8', cursor: firstFrame && lastFrame ? 'pointer' : 'not-allowed', color: firstFrame && lastFrame ? '#fff' : '#98A2B3', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: firstFrame && lastFrame ? '0 6px 14px rgba(139, 92, 246, 0.24)' : 'none', transition: 'all 0.2s ease', flexShrink: 0 }}
                      onMouseEnter={(e) => { if (firstFrame && lastFrame) e.currentTarget.style.transform = 'scale(1.06)'; }}
                      onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }}
                    >
                      <SwapOutlined style={{ fontSize: 14 }} />
                    </button>

                    {/* 尾帧 */}
                    <div style={{ position: 'relative', flex: 1, minWidth: 0, height: 100, borderRadius: 12, border: '1px solid #E7EAF0', background: '#ffffff', boxShadow: '0 6px 16px rgba(47, 52, 64, 0.04)', overflow: 'hidden', opacity: !firstFrame ? 0.5 : 1 }}>
                      <div style={{ position: 'absolute', top: 8, left: 10, right: 10, display: 'flex', alignItems: 'center', justifyContent: 'space-between', zIndex: 2 }}>
                        <span style={{ fontSize: 11, fontWeight: 600, color: '#8b5cf6', lineHeight: 1 }}>尾帧</span>
                      </div>
                      {lastFrame ? (
                        <div style={{ position: 'absolute', left: 10, right: 10, bottom: 10, height: 64 }}>
                          <img
                            src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${lastFrame.url}`}
                            alt={lastFrame.name}
                            onClick={() => {
                              setAttachmentPreviewUrl(lastFrame.url);
                              setAttachmentPreviewType('image');
                              setAttachmentPreviewName(lastFrame.name);
                              setAttachmentPreviewVisible(true);
                            }}
                            style={{ width: '100%', height: '100%', objectFit: 'cover', borderRadius: 8, cursor: 'pointer', border: '1px solid rgba(139, 92, 246, 0.2)', boxShadow: '0 3px 10px rgba(47, 52, 64, 0.06)' }}
                          />
                          <button
                            onClick={handleRemoveLastFrame}
                            style={{ position: 'absolute', top: -6, right: -6, width: 18, height: 18, border: 'none', background: '#A45B5B', borderRadius: 50, cursor: 'pointer', color: '#fff', fontSize: 9, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 2px 4px rgba(164, 91, 91, 0.3)', zIndex: 10 }}
                          >
                            <DeleteOutlined style={{ fontSize: 9 }} />
                          </button>
                        </div>
                      ) : (
                        firstFrame ? (
                          <UploadSelector
                            accept="image/*"
                            multiple={false}
                            onLocalSelect={(files) => {
                              if (files.length > 0) {
                                handleUpload(files[0], 'last');
                              }
                            }}
                            onHistorySelect={(items) => {
                              if (items.length > 0) {
                                const item = items[0];
                                const mediaRef: MediaReference = {
                                  name: item.fileName || '',
                                  type: 'image',
                                  url: item.resourceUrl || item.previewUrl || item.displayUrl || '',
                                  role: 'last_frame',
                                  label: '',
                                };
                                setLastFrame(mediaRef);
                                antdMessage.success('成功添加尾帧');
                              }
                            }}
                            onPortraitSelect={(assets) => {
                              if (assets.length > 0) {
                                const asset = assets[0];
                                const previewUrl = asset.previewUrl || asset.displayUrl || asset.videoCoverUrl || asset.providerUrl || '';
                                const mediaRef: MediaReference = {
                                  name: asset.name || '尾帧图片',
                                  type: 'image',
                                  url: previewUrl,
                                  role: 'last_frame',
                                  label: '',
                                };
                                setLastFrame(mediaRef);
                                antdMessage.success('成功添加尾帧');
                              }
                            }}
                            uploading={uploading}
                          >
                            <div
                              style={{ position: 'absolute', left: 10, right: 10, bottom: 10, height: 64, borderRadius: 8, border: '1px dashed rgba(139, 92, 246, 0.24)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', transition: 'all 0.25s ease', backgroundColor: 'rgba(139, 92, 246, 0.04)', flexDirection: 'column', gap: 4 }}
                              onMouseEnter={(e) => { e.currentTarget.style.borderColor = '#a78bfa'; e.currentTarget.style.backgroundColor = 'rgba(139, 92, 246, 0.08)'; }}
                              onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'rgba(139, 92, 246, 0.24)'; e.currentTarget.style.backgroundColor = 'rgba(139, 92, 246, 0.04)'; }}
                            >
                              <PlusOutlined style={{ fontSize: 18, color: '#8b5cf6' }} />
                              <span style={{ fontSize: 12, color: '#8b5cf6', fontWeight: 500 }}>上传尾帧</span>
                            </div>
                          </UploadSelector>
                        ) : (
                          <div
                            style={{ position: 'absolute', left: 10, right: 10, bottom: 10, height: 64, borderRadius: 8, border: '1px dashed rgba(226, 232, 240, 0.4)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'not-allowed', backgroundColor: 'rgba(241, 245, 249, 0.5)', flexDirection: 'column', gap: 4 }}
                          >
                            <PlusOutlined style={{ fontSize: 18, color: '#cbd5e1' }} />
                            <span style={{ fontSize: 12, color: '#94a3b8', fontWeight: 500 }}>请先上传首帧</span>
                          </div>
                        )
                      )}
                    </div>
                  </div>) : (
                  <>

                    {/* 上传区域 - 图片堆叠展示，右下角圆形+按钮 */}
                    {!(mediaType === 'video' && referenceMode === 'first_last_frame') && (
                      <div
                        style={{
                          position: 'relative',
                          width: 64,
                          height: 72,
                          marginTop: '-10',
                        }}
                        onMouseEnter={openMediaStackTray}
                        onMouseLeave={closeMediaStackTray}
                      >
                        {/* 没有上传时的卡片样式 */}
                        {currentMedia.length === 0 && (
                          <UploadSelector
                            accept={mediaType === 'image' ? 'image/*' : 'image/*,video/*,audio/*'}
                            onLocalSelect={handleBatchUpload}
                            onHistorySelect={handleUploadResourceHistorySelected}
                            onPortraitLibrarySelect={(libraryType) => {
                              openPrivatePortraitPicker(libraryType);
                            }}
                            uploading={uploading}
                            tooltipTitle={mediaType === 'image'
                              ? `图片${currentMedia.filter(m => m.type === 'image').length}/${maxImageCount}`
                              : `图片${currentMedia.filter(m => m.type === 'image').length}/${maxImageCount}，
                              视频${currentMedia.filter(m => m.type === 'video').length}/${maxVideoCount}${maxAudio > 0 ? `，
                              音频${currentMedia.filter(m => m.type === 'audio').length}/${maxAudio}` : ''}`
                            }
                            maxImageCount={maxImageCount}
                            maxVideoCount={maxVideoCount}
                            usedImageCount={currentMedia.filter(m => m.type === 'image').length}
                            usedVideoCount={currentMedia.filter(m => m.type === 'video').length}
                            usedVideoDuration={currentMedia.filter(m => m.type === 'video').reduce((sum, m) => sum + (m.duration || 0), 0)}
                            maxVideoDuration={15}
                            maxAudioCount={maxAudio > 0 ? maxAudio : undefined}
                            usedAudioCount={currentMedia.filter(m => m.type === 'audio').length}
                            maxAudioDuration={15}
                            usedAudioDuration={currentMedia.filter(m => m.type === 'audio').reduce((sum, m) => sum + (m.duration || 0), 0)}
                            hideLimitHint={mediaType === 'image'}
                          >
                            <div
                              style={{
                                width: 54,
                                height: 74,
                                borderRadius: 7,
                                border: '1px solid rgba(231, 234, 240, 0.95)',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                cursor: 'pointer',
                                transition: 'all 0.25s ease',
                                background: '#f4f4f4',
                                flexDirection: 'column',
                                gap: 5,
                                transform: 'rotate(-7deg)',
                                // boxShadow: '0 9px 20px rgba(47, 52, 64, 0.10), inset 0 1px 0 rgba(255,255,255,0.95)',
                              }}
                              onMouseEnter={(e) => {
                                e.currentTarget.style.borderColor = '#D7DDE7';
                                e.currentTarget.style.background = '#f4f4f4';
                                e.currentTarget.style.transform = 'rotate(0deg) translateY(-2px)';
                                // e.currentTarget.style.boxShadow = '0 14px 28px rgba(47, 52, 64, 0.15), inset 0 1px 0 rgba(255,255,255,0.98)';
                              }}
                              onMouseLeave={(e) => {
                                e.currentTarget.style.borderColor = 'rgba(231, 234, 240, 0.95)';
                                e.currentTarget.style.background = '#f4f4f4';
                                e.currentTarget.style.transform = 'rotate(-7deg)';
                                // e.currentTarget.style.boxShadow = '0 9px 20px rgba(47, 52, 64, 0.10), inset 0 1px 0 rgba(255,255,255,0.95)';
                              }}
                            >
                              {uploading ? (
                                <LoadingOutlined style={{ fontSize: 17, color: '#667085' }} />
                              ) : (
                                <>
                                  <PlusOutlined style={{ fontSize: 18, color: '#667085', lineHeight: 1 }} />
                                  <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 14px)', columnGap: 2, justifyContent: 'center', color: '#344054', fontSize: 12, fontWeight: 700, lineHeight: 1.05, letterSpacing: 0 }}>
                                    <span style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}><span>参</span><span>考</span></span>
                                    <span style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 1 }}><span>内</span><span>容</span></span>
                                  </div>
                                </>
                              )}
                            </div>
                          </UploadSelector>
                        )}
                        {/* {mediaType === 'video' && currentMedia.length === 0 && (
                          <Button
                            size="small"
                            onClick={() => setPrivateAssetPickerOpen(true)}
                            style={{ marginTop: 8, borderRadius: 8, color: '#8b5cf6', borderColor: '#ddd6fe', background: '#fff' }}
                          >
                            真人素材库
                          </Button>
                        )} */}

                        {/* 层叠附件展示 - 鼠标移入向右排列展开 */}
                        {currentMedia.length > 0 && (
                          <>
                            {currentMedia.map((media, idx) => {
                              const reversedIdx = Math.min(currentMedia.length, 3) - 1 - idx;
                              const offsetX = mediaStackHovered ? idx * 58 : (idx < 3 ? idx * 6 : 18);
                              const isVisible = !mediaStackHovered ? idx < 3 : true;
                              return (
                                <div
                                  key={`stack-${idx}`}
                                  style={{
                                    position: 'absolute',
                                    left: offsetX,
                                    bottom: 0,
                                    zIndex: idx + 1,
                                    transition: 'all 0.28s cubic-bezier(0.4, 0, 0.2, 1)',
                                    transform: mediaStackHovered ? `scale(1) rotate(0deg)` : `scale(${idx < 3 ? (1 - reversedIdx * 0.08) : 0}) rotate(${idx < 3 ? (-3 + idx * 1.5) : 0}deg)`,
                                    opacity: isVisible ? (mediaStackHovered ? 1 : (1 - reversedIdx * 0.15)) : 0,
                                    pointerEvents: isVisible ? 'auto' : 'none',
                                  }}
                                >
                                  <div style={{ position: 'relative', width: 52, height: 60 }}>
                                    {media.type === 'image' ? (
                                      <img
                                        src={buildPreviewUrl(media.url)}
                                        alt={media.name}
                                        onClick={() => {
                                          setAttachmentPreviewUrl(media.url);
                                          setAttachmentPreviewType('image');
                                          setAttachmentPreviewName(media.name);
                                          setAttachmentPreviewVisible(true);
                                        }}
                                        style={{ width: 52, height: 60, objectFit: 'cover', borderRadius: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.98)', boxShadow: '0 4px 12px rgba(31,41,55,0.15)' }}
                                      />
                                    ) : media.type === 'video' ? (
                                      <video
                                        src={buildPreviewUrl(media.url)}
                                        muted
                                        onClick={() => {
                                          setAttachmentPreviewUrl(media.url);
                                          setAttachmentPreviewType('video');
                                          setAttachmentPreviewName(media.name);
                                          setAttachmentPreviewVisible(true);
                                        }}
                                        style={{ width: 52, height: 60, objectFit: 'cover', borderRadius: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.98)', boxShadow: '0 4px 12px rgba(31,41,55,0.15)' }}
                                      />
                                    ) : (
                                      <div
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          handleAudioPlay(media.url);
                                        }}
                                        style={{ width: 52, height: 60, objectFit: 'cover', borderRadius: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.98)', boxShadow: '0 4px 12px rgba(31,41,55,0.15)', background: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
                                      >
                                        {playingAudioUrl === (buildPreviewUrl(media.url)) ? (
                                          <PauseOutlined style={{ fontSize: 20, color: '#fff' }} />
                                        ) : (
                                          <AudioOutlined style={{ fontSize: 20, color: '#fff' }} />
                                        )}
                                      </div>
                                    )}
                                    {/* 右上角删除按钮 */}
                                    <button
                                      onClick={() => handleRemoveMedia(idx)}
                                      style={{
                                        position: 'absolute',
                                        top: -6,
                                        right: -6,
                                        width: 20,
                                        height: 20,
                                        borderRadius: 50,
                                        background: '#1f2937',
                                        border: 'none',
                                        color: '#fff',
                                        cursor: 'pointer',
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'center',
                                        boxShadow: '0 2px 6px rgba(0,0,0,0.2)',
                                        zIndex: 10,
                                        transition: 'all 0.2s ease',
                                      }}
                                      onMouseEnter={(e) => {
                                        e.currentTarget.style.background = '#dc2626';
                                        e.currentTarget.style.transform = 'scale(1.1)';
                                      }}
                                      onMouseLeave={(e) => {
                                        e.currentTarget.style.background = '#1f2937';
                                        e.currentTarget.style.transform = 'scale(1)';
                                      }}
                                    >
                                      <DeleteOutlined style={{ fontSize: 10 }} />
                                    </button>
                                  </div>
                                </div>
                              );
                            })}
                          </>
                        )}

                        {/* 右下角圆形+上传按钮 */}
                        {currentMedia.length > 0 && (
                          <UploadSelector
                            accept={mediaType === 'image' ? 'image/*' : 'image/*,video/*,audio/*'}
                            onLocalSelect={handleBatchUpload}
                            onHistorySelect={handleUploadResourceHistorySelected}
                            onPortraitLibrarySelect={(libraryType) => {
                              openPrivatePortraitPicker(libraryType);
                            }}
                            uploading={uploading}
                            tooltipTitle={mediaType === 'image'
                              ? `图片${currentMedia.filter(m => m.type === 'image').length}/${maxImageCount}`
                              : `图片${currentMedia.filter(m => m.type === 'image').length}/${maxImageCount}，
                              视频${currentMedia.filter(m => m.type === 'video').length}/${maxVideoCount}${maxAudio > 0 ? `，
                              音频${currentMedia.filter(m => m.type === 'audio').length}/${maxAudio}` : ''}`
                            }
                            maxImageCount={maxImageCount}
                            maxVideoCount={maxVideoCount}
                            usedImageCount={currentMedia.filter(m => m.type === 'image').length}
                            usedVideoCount={currentMedia.filter(m => m.type === 'video').length}
                            usedVideoDuration={currentMedia.filter(m => m.type === 'video').reduce((sum, m) => sum + (m.duration || 0), 0)}
                            maxVideoDuration={15}
                            maxAudioCount={maxAudio > 0 ? maxAudio : undefined}
                            usedAudioCount={currentMedia.filter(m => m.type === 'audio').length}
                            maxAudioDuration={15}
                            usedAudioDuration={currentMedia.filter(m => m.type === 'audio').reduce((sum, m) => sum + (m.duration || 0), 0)}
                            hideLimitHint={mediaType === 'image'}
                          >
                            <div
                              style={{
                                position: 'absolute',
                                right: 0,
                                bottom: 0,
                                width: 28,
                                height: 28,
                                borderRadius: 50,
                                background: '#ffffff',
                                border: '1px solid rgba(231, 234, 240, 0.95)',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                cursor: 'pointer',
                                transition: 'all 0.2s ease',
                                boxShadow: '0 2px 8px rgba(47, 52, 64, 0.08)',
                                zIndex: 100,
                              }}
                              onMouseEnter={(e) => {
                                e.currentTarget.style.borderColor = '#8b5cf6';
                                e.currentTarget.style.boxShadow = '0 4px 12px rgba(139, 92, 246, 0.2)';
                              }}
                              onMouseLeave={(e) => {
                                e.currentTarget.style.borderColor = 'rgba(231, 234, 240, 0.95)';
                                e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.08)';
                              }}
                            >
                              <PlusOutlined style={{ fontSize: 14, color: '#8b5cf6', lineHeight: 1 }} />
                            </div>
                          </UploadSelector>
                        )}
                        {/* {mediaType === 'video' && currentMedia.length > 0 && (
                          <Tooltip title="选择真人素材库">
                            <div
                              onClick={(e) => { e.stopPropagation(); setPrivateAssetPickerOpen(true); }}
                              style={{
                                position: 'absolute',
                                right: -32,
                                bottom: 0,
                                width: 28,
                                height: 28,
                                borderRadius: 50,
                                background: '#fff',
                                border: '1px solid #ddd6fe',
                                color: '#8b5cf6',
                                display: 'flex',
                                alignItems: 'center',
                                justifyContent: 'center',
                                cursor: 'pointer',
                                fontSize: 12,
                                fontWeight: 800,
                                boxShadow: '0 2px 8px rgba(47, 52, 64, 0.08)',
                                zIndex: 100,
                              }}
                            >
                              真
                            </div>
                          </Tooltip>
                        )} */}
                      </div>
                    )}
                  </>
                )}
              </div>

              {/* 右侧输入区域 */}
              <div style={{ flex: 1, minWidth: 0 }}>
                {/* 输入框区域 */}
                <div style={{
                  display: 'flex',
                  flexDirection: 'column',
                  gap: 6,
                  padding: '0',
                  backgroundColor: 'transparent',
                  borderRadius: 0,
                  border: 'none',
                  boxShadow: 'none',
                  transition: 'all 0.2s ease',
                  position: 'relative',
                  minHeight: isFirstLastFrameComposer ? 92 : 74,
                }}>
                  {/* {!inputValue.trim() && (
                        <div style={{ display: 'flex', alignItems: 'center', gap: 10, minHeight: 22, paddingTop: 1 }}>
                          <span style={{ fontSize: 13, fontWeight: 800, color: '#475467', letterSpacing: 0.1, whiteSpace: 'nowrap' }}>{composerModeLabel}</span>
                          <span style={{ fontSize: 13, color: '#667085', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontWeight: 500 }}>{composerHelperText}</span>
                        </div>
                    )} */}
                  {/* 文本输入框 */}
                  <TextArea
                    ref={mentionInputRef}
                    value={inputValue}
                    onChange={handleInputChange}
                    onKeyDown={handleInputKeyDown}
                    onPaste={(e) => {
                      const items = e.clipboardData?.items;
                      if (!items) return;
                      const imageFiles: File[] = [];
                      for (let i = 0; i < items.length; i++) {
                        if (items[i].type.startsWith('image/')) {
                          const file = items[i].getAsFile();
                          if (file) imageFiles.push(file);
                        }
                      }
                      if (imageFiles.length > 0) {
                        e.preventDefault();
                        imageFiles.forEach(async (file) => {
                          await handleUpload(file);
                        });
                      }
                    }}
                    placeholder={composerPlaceholder}
                    autoSize={{ minRows: 3, maxRows: 6 }}
                    style={{
                      width: '100%',
                      borderRadius: 0,
                      border: 'none',
                      outline: 'none',
                      boxShadow: 'none',
                      fontSize: 14,
                      lineHeight: 1.72,
                      color: '#2f3440',
                      fontWeight: 500,
                      resize: 'none',
                      backgroundColor: 'transparent',
                      padding: 10,

                    }}
                    disabled={loading}
                  />

                  {/* @ 提及下拉列表 */}
                  {mentionVisible && currentMedia.length > 0 && referenceMode === 'universal' && (
                    <div
                      style={{
                        position: 'absolute',
                        bottom: '100%',
                        left: 10,
                        marginBottom: 8,
                        zIndex: 1000,
                        background: '#fff',
                        borderRadius: 16,
                        boxShadow: '0 18px 42px rgba(47, 52, 64, 0.12)',
                        border: '1px solid #E7EAF0',
                        padding: 8,
                        minWidth: 160,
                        maxHeight: 260,
                        overflowY: 'auto',
                      }}
                    >
                      {currentMedia.map((media, idx) => (
                        <div
                          key={idx}
                          onClick={() => insertMention(media.label)}
                          style={{
                            padding: '8px 12px',
                            borderRadius: 6,
                            cursor: 'pointer',
                            display: 'flex',
                            alignItems: 'center',
                            gap: 8,
                            fontSize: 13,
                            color: '#2f3440',
                            transition: 'all 0.15s',
                          }}
                          onMouseEnter={(e) => {
                            e.currentTarget.style.background = 'rgba(139, 92, 246, 0.08)';
                            e.currentTarget.style.color = '#8b5cf6';
                          }}
                          onMouseLeave={(e) => {
                            e.currentTarget.style.background = 'transparent';
                            e.currentTarget.style.color = '#2f3440';
                          }}
                        >
                          {media.type === 'image' ? (
                            <PictureOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                          ) : (
                            <VideoCameraOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                          )}
                          <span>{media.label}</span>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              </div>
            </div>

            {/* 底部工具栏 */}
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 14, marginTop: 10, paddingTop: 13, borderTop: '1px solid rgba(231, 234, 240, 0.76)' }}>
              <Space size={8} wrap style={{ flex: 1, minWidth: 0 }}>
                {/* <span>
                  创作类型：
                </span> */}
                {/* 文件类型选择器 */}
                <div style={{ position: 'relative', display: 'inline-block' }}>
                  <button
                    onClick={() => {
                      setShowEngineModal(false);
                      setShowImageSettingsModal(false);
                      setShowVideoSettingsModal(false);
                      setReferenceModeDropdownVisible(false);
                      setShowMediaTypeModal(prev => !prev);
                    }}
                    className="image-settings-trigger"
                    style={{
                      minWidth: 118,
                      padding: '5px 12px',
                      height: 32,
                      borderRadius: 10,
                      border: '1px solid #E7EAF0',
                      backgroundColor: '#ffffff',
                      cursor: 'pointer',
                      display: 'inline-flex',
                      alignItems: 'center',
                      gap: 6,
                      transition: 'all 0.2s ease',
                      boxShadow: '0 1px 2px rgba(47, 52, 64, 0.025)',
                    }}
                    onMouseEnter={(e) => {
                      e.currentTarget.style.backgroundColor = '#FFFFFF';
                      e.currentTarget.style.borderColor = '#D7DDE7';
                      e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.06)';
                    }}
                    onMouseLeave={(e) => {
                      e.currentTarget.style.backgroundColor = '#ffffff';
                      e.currentTarget.style.borderColor = '#E7EAF0';
                      e.currentTarget.style.boxShadow = '0 1px 2px rgba(47, 52, 64, 0.03)';
                    }}
                  >
                    {mediaType === 'video' ? (
                      <VideoCameraOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                    ) : (
                      <PictureOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                    )}
                    <Text style={{
                      fontSize: 13,
                      fontWeight: 500,
                      color: '#2f3440',
                    }}>
                      {mediaType === 'video' ? '视频生成' : '图片生成'}
                    </Text>
                    <CaretDownOutlined style={{ fontSize: 10, color: '#8b5cf6', marginLeft: 'auto' }} />
                  </button>

                  {showMediaTypeModal && (
                    <div
                      className="image-settings-popover"
                      style={{
                        position: 'absolute',
                        bottom: 'calc(100% + 8px)',
                        left: 0,
                        width: 300,
                        backgroundColor: '#ffffff',
                        backdropFilter: 'blur(16px)',
                        borderRadius: 16,
                        boxShadow: '0 20px 48px rgba(47, 52, 64, 0.12)',
                        padding: 16,
                        border: '1px solid #E7EAF0',
                        zIndex: 9999,
                      }}
                      onClick={(e) => e.stopPropagation()}
                    >
                      <div style={{ marginBottom: 8 }}>
                        <Text style={{
                          display: 'block',
                          marginBottom: 8,
                          fontSize: 12,
                          fontWeight: 600,
                          color: '#475467',
                        }}>
                          创作类型
                        </Text>
                        <div style={{
                          display: 'flex',
                          flexDirection: 'column',
                          gap: 4,
                        }}>
                          {[
                            { value: 'video', label: '视频生成', icon: VideoCameraOutlined },
                            { value: 'image', label: '图片生成', icon: PictureOutlined },
                          ].map((item) => (
                            <button
                              key={item.value}
                              onClick={() => {
                                setMediaType(item.value);
                                setShowMediaTypeModal(false);
                                setCurrentMedia([]);
                                setInputValue('');
                              }}
                              style={{
                                flex: 1,
                                minHeight: 48,
                                borderRadius: 10,
                                border: mediaType === item.value
                                  ? '1px solid #8b5cf6'
                                  : '1px solid #E7EAF0',
                                backgroundColor: mediaType === item.value
                                  ? '#f5f3ff'
                                  : '#ffffff',
                                cursor: 'pointer',
                                display: 'flex',
                                alignItems: 'center',
                                padding: '8px 12px',
                                transition: 'all 0.2s',
                                textAlign: 'left',
                                gap: 8,
                              }}
                            >
                              <item.icon style={{ fontSize: 14, color: mediaType === item.value ? '#8b5cf6' : '#98a2b3' }} />
                              <span style={{
                                fontSize: 14,
                                fontWeight: mediaType === item.value ? 600 : 500,
                                color: mediaType === item.value ? '#8b5cf6' : '#475467',
                              }}>
                                {item.label}
                              </span>
                            </button>
                          ))}
                        </div>
                      </div>
                    </div>
                  )}
                </div>

                {/* 引擎选择器 */}
                <div style={{ position: 'relative', display: 'inline-block' }}>
                  <button
                    onClick={() => {
                      setShowMediaTypeModal(false);
                      setShowImageSettingsModal(false);
                      setShowVideoSettingsModal(false);
                      setReferenceModeDropdownVisible(false);
                      setShowEngineModal(prev => !prev);
                    }}
                    className="image-settings-trigger"
                    style={{
                      minWidth: 174,
                      padding: '5px 12px',
                      height: 32,
                      borderRadius: 10,
                      border: '1px solid #E7EAF0',
                      backgroundColor: '#ffffff',
                      cursor: 'pointer',
                      display: 'inline-flex',
                      alignItems: 'center',
                      gap: 6,
                      transition: 'all 0.2s ease',
                      boxShadow: '0 1px 2px rgba(47, 52, 64, 0.025)',
                    }}
                    onMouseEnter={(e) => {
                      e.currentTarget.style.backgroundColor = '#FFFFFF';
                      e.currentTarget.style.borderColor = '#D7DDE7';
                      e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.06)';
                    }}
                    onMouseLeave={(e) => {
                      e.currentTarget.style.backgroundColor = '#ffffff';
                      e.currentTarget.style.borderColor = '#E7EAF0';
                      e.currentTarget.style.boxShadow = '0 1px 2px rgba(47, 52, 64, 0.03)';
                    }}
                  >
                    <SettingOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                    <Text style={{
                      fontSize: 13,
                      fontWeight: 500,
                      color: '#2f3440',
                    }}>
                      {mediaType === 'image' ? enginesele.image?.find((e: any) => e.id === countType)?.name : enginesele.video?.find((e: any) => e.id === countType)?.name || '选择引擎'}
                    </Text>
                    <CaretDownOutlined style={{ fontSize: 10, color: '#8b5cf6', marginLeft: 'auto' }} />
                  </button>

                  {showEngineModal && (
                    <div
                      className="image-settings-popover"
                      style={{
                        position: 'absolute',
                        bottom: 'calc(100% + 8px)',
                        left: 0,
                        width: 360,
                        backgroundColor: '#ffffff',
                        backdropFilter: 'blur(16px)',
                        borderRadius: 16,
                        boxShadow: '0 20px 48px rgba(47, 52, 64, 0.12)',
                        padding: 16,
                        border: '1px solid #E7EAF0',
                        zIndex: 9999,
                      }}
                      onClick={(e) => e.stopPropagation()}
                    >
                      {/* 选择引擎 */}
                      <div style={{ marginBottom: 8 }}>
                        <Text style={{
                          display: 'block',
                          marginBottom: 8,
                          fontSize: 12,
                          fontWeight: 600,
                          color: '#475467',
                        }}>
                          选择引擎
                        </Text>
                        <div style={{
                          display: 'flex',
                          flexDirection: 'column',
                          gap: 4,
                        }}>
                          {(mediaType === 'image' ? enginesele.image : enginesele.video)?.map((engine: any) => (
                            <button
                              key={engine.id}
                              onClick={() => {
                                setCountType(engine.id);
                                if (mediaType === 'video') {
                                  setEngineOptions({
                                    ratios: engine.supportedRatios || ['16:9', '4:3', '1:1', '3:4', '9:16', '21:9'],
                                    resolutions: engine.supportedResolutions || ['480p', '720p', '1080p'],
                                    durations: engine.supportedDurations || [5, 8, 10, 12, 15],
                                  });
                                  if (!engine.supportedRatios?.includes(videoAspectRatio)) {
                                    setVideoAspectRatio(engine.supportedRatios?.[0] || '16:9');
                                  }
                                  if (!engine.supportedResolutions?.includes(videoResolution)) {
                                    setVideoResolution(engine.supportedResolutions?.[0] || '720p');
                                  }
                                  if (!engine.supportedDurations?.includes(videoDuration)) {
                                    setVideoDuration(engine.supportedDurations?.[0] || 5);
                                  }
                                }
                                if (mediaType === 'image') {
                                  const supportedSizes = engine.supportedSizes || {};
                                  const resolutionLevels = Object.keys(supportedSizes).sort((a, b) => {
                                    const levelOrder = { '1K': 0, '2K': 1, '4K': 2 };
                                    return (levelOrder[a] || 0) - (levelOrder[b] || 0);
                                  });

                                  const primaryResolution = resolutionLevels[0] || '2K';
                                  const supportedResolutions = Object.keys(supportedSizes[primaryResolution] || {});

                                  const newRatioOptions = supportedResolutions.map((res: any) => ({
                                    value: res,
                                    label: res,
                                  }));
                                  setRatioOptions(newRatioOptions);
                                  setCurrentEngineSupportedSizes(supportedSizes);
                                  setResolutionOptions(resolutionLevels.map((level) => {
                                    const match = level.match(/(\d+)K/);
                                    const num = match ? parseInt(match[1]) : 1;
                                    const labels: Record<number, string> = { 1: '标清', 2: '高清', 4: '超清' };
                                    return {
                                      value: level,
                                      label: `${labels[num] || '高清'} ${level}`,
                                    };
                                  }));

                                  if (supportedSizes[primaryResolution] && supportedSizes[primaryResolution][supportedResolutions[0]]) {
                                    const defaultSize = supportedSizes[primaryResolution][supportedResolutions[0]];
                                    const [w, h] = defaultSize.split(/[×x]/);
                                    setWidth(Number(w));
                                    setHeight(Number(h));
                                    setSelectedRatio(supportedResolutions[0]);
                                    setSelectedResolution(primaryResolution);
                                  }
                                }
                                setShowEngineModal(false);
                              }}
                              style={{
                                flex: 1,
                                minHeight: 48,
                                borderRadius: 10,
                                border: countType === engine.id
                                  ? '1px solid #8b5cf6'
                                  : '1px solid #E7EAF0',
                                backgroundColor: countType === engine.id
                                  ? '#f5f3ff'
                                  : '#ffffff',
                                cursor: 'pointer',
                                display: 'flex',
                                flexDirection: 'column',
                                justifyContent: 'center',
                                alignItems: 'flex-start',
                                padding: '8px 12px',
                                transition: 'all 0.2s',
                                textAlign: 'left',
                              }}
                            >
                              <span style={{
                                fontSize: 14,
                                fontWeight: countType === engine.id ? 600 : 500,
                                color: countType === engine.id ? '#8b5cf6' : '#475467',
                                marginBottom: 2,
                              }}>
                                {engine.name}
                              </span>
                              <span style={{
                                fontSize: 11,
                                color: '#98a2b3',
                              }}>
                              </span>
                            </button>
                          ))}
                        </div>
                      </div>
                    </div>
                  )}
                </div>

                {/* 参考模式切换按钮 - 仅视频模式显示 */}
                {mediaType === 'video' && (supportsFirstLastFrame || supportsUniversalReference) && (
                  <div style={{ position: 'relative', display: 'inline-block' }}>
                    <button
                      onClick={() => {
                        setShowMediaTypeModal(false);
                        setShowEngineModal(false);
                        setShowImageSettingsModal(false);
                        setShowVideoSettingsModal(false);
                        setReferenceModeDropdownVisible(!referenceModeDropdownVisible);
                      }}
                      className="image-settings-trigger"
                      style={{
                        minWidth: 118,
                        padding: '6px 14px',
                        height: 32,
                        borderRadius: 10,
                        border: '1px solid #E7EAF0',
                        backgroundColor: '#ffffff',
                        cursor: 'pointer',
                        display: 'inline-flex',
                        alignItems: 'center',
                        gap: 6,
                        transition: 'all 0.2s ease',
                        boxShadow: '0 1px 2px rgba(47, 52, 64, 0.025)',
                      }}
                      onMouseEnter={(e) => {
                        e.currentTarget.style.backgroundColor = '#FFFFFF';
                        e.currentTarget.style.borderColor = '#D7DDE7';
                        e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.06)';
                      }}
                      onMouseLeave={(e) => {
                        e.currentTarget.style.backgroundColor = '#ffffff';
                        e.currentTarget.style.borderColor = '#E7EAF0';
                        e.currentTarget.style.boxShadow = '0 1px 2px rgba(47, 52, 64, 0.03)';
                      }}
                    >
                      <PictureOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                      <Text style={{
                        fontSize: 13,
                        fontWeight: 500,
                        color: '#2f3440',
                      }}>
                        {referenceMode === 'universal' ? '全能参考' : '首尾帧'}
                      </Text>
                      <CaretDownOutlined style={{ fontSize: 10, color: '#8b5cf6', marginLeft: 'auto' }} />
                    </button>

                    {referenceModeDropdownVisible && (
                      <div
                        className="image-settings-popover"
                        style={{
                          position: 'absolute',
                          bottom: 'calc(100% + 8px)',
                          left: 0,
                          width: 300,
                          backgroundColor: '#ffffff',
                          backdropFilter: 'blur(16px)',
                          borderRadius: 16,
                          boxShadow: '0 20px 48px rgba(47, 52, 64, 0.12)',
                          padding: 16,
                          border: '1px solid #E7EAF0',
                          zIndex: 9999,
                        }}
                        onClick={(e) => e.stopPropagation()}
                      >
                        <div style={{ marginBottom: 8 }}>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 600,
                            color: '#475467',
                          }}>
                            参考模式
                          </Text>
                          <div style={{
                            display: 'flex',
                            flexDirection: 'column',
                            gap: 4,
                          }}>
                            <button
                              onClick={() => {
                                handleReferenceModeChange('universal');
                                setReferenceModeDropdownVisible(false);
                              }}
                              disabled={!supportsUniversalReference}
                              style={{
                                flex: 1,
                                minHeight: 48,
                                borderRadius: 10,
                                border: referenceMode === 'universal'
                                  ? '1px solid #8b5cf6'
                                  : '1px solid #E7EAF0',
                                backgroundColor: referenceMode === 'universal'
                                  ? '#f5f3ff'
                                  : '#ffffff',
                                cursor: supportsUniversalReference ? 'pointer' : 'not-allowed',
                                display: 'flex',
                                alignItems: 'center',
                                padding: '8px 12px',
                                transition: 'all 0.2s',
                                textAlign: 'left',
                                gap: 8,
                                opacity: supportsUniversalReference ? 1 : 0.4,
                              }}
                            >
                              <PictureOutlined style={{ fontSize: 14, color: referenceMode === 'universal' ? '#8b5cf6' : '#98a2b3' }} />
                              <span style={{
                                fontSize: 14,
                                fontWeight: referenceMode === 'universal' ? 600 : 500,
                                color: referenceMode === 'universal' ? '#8b5cf6' : '#475467',
                              }}>
                                全能参考
                              </span>
                              {!supportsUniversalReference && (
                                <span style={{ fontSize: 10, color: '#98a2b3', marginLeft: 'auto' }}>不支持</span>
                              )}
                            </button>
                            <button
                              onClick={() => {
                                handleReferenceModeChange('first_last_frame');
                                setReferenceModeDropdownVisible(false);
                              }}
                              disabled={!supportsFirstLastFrame}
                              style={{
                                flex: 1,
                                minHeight: 48,
                                borderRadius: 10,
                                border: referenceMode === 'first_last_frame'
                                  ? '1px solid #8b5cf6'
                                  : '1px solid #E7EAF0',
                                backgroundColor: referenceMode === 'first_last_frame'
                                  ? '#f5f3ff'
                                  : '#ffffff',
                                cursor: supportsFirstLastFrame ? 'pointer' : 'not-allowed',
                                display: 'flex',
                                alignItems: 'center',
                                padding: '8px 12px',
                                transition: 'all 0.2s',
                                textAlign: 'left',
                                gap: 8,
                                opacity: supportsFirstLastFrame ? 1 : 0.4,
                              }}
                            >
                              <SwapOutlined style={{ fontSize: 14, color: referenceMode === 'first_last_frame' ? '#8b5cf6' : '#98a2b3' }} />
                              <span style={{
                                fontSize: 14,
                                fontWeight: referenceMode === 'first_last_frame' ? 600 : 500,
                                color: referenceMode === 'first_last_frame' ? '#8b5cf6' : '#475467',
                              }}>
                                首尾帧
                              </span>
                              {!supportsFirstLastFrame && (
                                <span style={{ fontSize: 10, color: '#98a2b3', marginLeft: 'auto' }}>不支持</span>
                              )}
                            </button>
                          </div>
                        </div>
                      </div>
                    )}
                  </div>
                )}

                {/* 图片设置按钮 */}
                {mediaType === 'image' && (
                  <div style={{ position: 'relative', display: 'inline-block' }}>
                    <button
                      onClick={() => {
                        setShowMediaTypeModal(false);
                        setShowEngineModal(false);
                        setShowVideoSettingsModal(false);
                        setReferenceModeDropdownVisible(false);
                        setShowImageSettingsModal(!showImageSettingsModal);
                      }}
                      className="image-settings-trigger"
                      style={{
                        minWidth: 156,
                        padding: '6px 14px',
                        height: 32,
                        borderRadius: 10,
                        border: '1px solid #E7EAF0',
                        backgroundColor: '#ffffff',
                        cursor: 'pointer',
                        display: 'inline-flex',
                        alignItems: 'center',
                        gap: 6,
                        transition: 'all 0.2s ease',
                        boxShadow: '0 1px 2px rgba(47, 52, 64, 0.025)',
                      }}
                      onMouseEnter={(e) => {
                        e.currentTarget.style.backgroundColor = '#FFFFFF';
                        e.currentTarget.style.borderColor = '#D7DDE7';
                        e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.06)';
                      }}
                      onMouseLeave={(e) => {
                        e.currentTarget.style.backgroundColor = '#ffffff';
                        e.currentTarget.style.borderColor = '#E7EAF0';
                        e.currentTarget.style.boxShadow = '0 1px 2px rgba(47, 52, 64, 0.03)';
                      }}
                    >
                      <LayoutOutlined style={{ fontSize: 14, color: '#8b5cf6' }} />
                      <Text style={{
                        fontSize: 13,
                        fontWeight: 500,
                        color: '#2f3440',
                      }}>
                        {selectedRatio === 'auto' ? '智能' : selectedRatio} · {selectedResolution == '2K' ? '2K高清' : '4K超清'} · {width}×{height}
                      </Text>
                      <CaretDownOutlined style={{ fontSize: 10, color: '#8b5cf6', marginLeft: 'auto' }} />
                    </button>

                    {showImageSettingsModal && (
                      <div
                        className="image-settings-popover"
                        style={{
                          position: 'absolute',
                          bottom: 'calc(100% + 8px)',
                          left: 0,
                          width: 480,
                          backgroundColor: '#ffffff',
                          backdropFilter: 'blur(16px)',
                          borderRadius: 14,
                          boxShadow: '0 18px 44px rgba(47, 52, 64, 0.12)',
                          padding: 16,
                          border: '1px solid #E7EAF0',
                          zIndex: 9999,
                        }}
                        onClick={(e) => e.stopPropagation()}
                      >
                        {/* 选择比例 */}
                        <div style={{ marginBottom: 16 }}>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            选择比例
                          </Text>
                          <div style={{
                            display: 'flex',
                            flexWrap: 'wrap',
                            gap: 4,
                          }}>
                            {ratioOptions.map((item: any) => (
                              <button
                                key={item.value}
                                onClick={() => {
                                  setSelectedRatio(item.value);
                                  calculateSizeFromRatione(item.label);
                                }}
                                style={{
                                  flex: '0 0 calc(11.11% - 4px)',
                                  minWidth: 44,
                                  height: 52,
                                  borderRadius: 6,
                                  border: selectedRatio === item.value
                                    ? '2px solid #8b5cf6'
                                    : '1px solid #E7EAF0',
                                  backgroundColor: selectedRatio === item.value
                                    ? '#f5f3ff'
                                    : '#FFFFFF',
                                  cursor: 'pointer',
                                  display: 'flex',
                                  flexDirection: 'column',
                                  justifyContent: 'center',
                                  alignItems: 'center',
                                  transition: 'all 0.2s',
                                }}
                              >
                                <div style={{
                                  width: (() => {
                                    const [w, h] = item.value === 'auto' ? [1, 1] : item.value.split(':').map(Number);
                                    const maxSize = 18;
                                    if (w >= h) return maxSize;
                                    return Math.round(maxSize * (w / h));
                                  })(),
                                  height: (() => {
                                    const [w, h] = item.value === 'auto' ? [1, 1] : item.value.split(':').map(Number);
                                    const maxSize = 18;
                                    if (h >= w) return maxSize;
                                    return Math.round(maxSize * (h / w));
                                  })(),
                                  border: `2px solid ${selectedRatio === item.value ? '#8b5cf6' : '#98a2b3'}`,
                                  borderRadius: 2,
                                  marginBottom: 2,
                                  display: 'flex',
                                  alignItems: 'center',
                                  justifyContent: 'center',
                                }}>
                                  {item.value === 'auto' && (
                                    <span style={{
                                      fontSize: 7,
                                      color: selectedRatio === item.value
                                        ? '#8b5cf6'
                                        : '#98a2b3',
                                    }}>
                                      智
                                    </span>
                                  )}
                                </div>
                                <span style={{
                                  fontSize: 9,
                                  color: selectedRatio === item.value
                                    ? '#8b5cf6'
                                    : '#667085',
                                  fontWeight: selectedRatio === item.value ? 600 : 400,
                                }}>
                                  {item.value}
                                </span>
                              </button>
                            ))}
                          </div>
                        </div>

                        {/* 选择分辨率 */}
                        <div style={{ marginBottom: 16 }}>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            选择分辨率
                          </Text>
                          <div style={{ display: 'flex', gap: 6 }}>
                            {resolutionOptions.map((item: any) => (
                              <button
                                key={item.value}
                                onClick={() => {
                                  setSelectedResolution(item.value);
                                  calculateSizeFromRatiotwo(item.value);
                                }}
                                style={{
                                  flex: 1,
                                  height: 42,
                                  borderRadius: 6,
                                  border: selectedResolution === item.value
                                    ? '2px solid #8b5cf6'
                                    : '1px solid #E7EAF0',
                                  backgroundColor: selectedResolution === item.value
                                    ? '#8b5cf6'
                                    : '#FFFFFF',
                                  cursor: 'pointer',
                                  display: 'flex',
                                  justifyContent: 'center',
                                  alignItems: 'center',
                                  transition: 'all 0.2s',
                                }}
                              >
                                <span style={{
                                  fontSize: 12,
                                  fontWeight: 600,
                                  color: selectedResolution === item.value
                                    ? '#fff'
                                    : '#475467',
                                }}>
                                  {item.value}
                                  {item.value === '4K' && (
                                    <span style={{ marginLeft: 2 }}>✨</span>
                                  )}
                                </span>
                              </button>
                            ))}
                          </div>
                        </div>

                        {/* 尺寸 */}
                        <div>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            尺寸
                          </Text>
                          <div style={{
                            display: 'flex',
                            alignItems: 'center',
                            gap: 6,
                          }}>
                            <div style={{
                              display: 'flex',
                              alignItems: 'center',
                              flex: 1,
                              maxWidth: 120,
                            }}>
                              <span style={{
                                color: '#98a2b3',
                                fontSize: 11,
                                marginRight: 4,
                              }}>
                                W
                              </span>
                              <Input
                                value={width}
                                onChange={(e) => setWidth(Number(e.target.value) || 0)}
                                style={{
                                  flex: 1,
                                  textAlign: 'center',
                                  borderRadius: 4,
                                  height: 34,
                                  border: '1px solid #E7EAF0',
                                  backgroundColor: '#FFFFFF',
                                  fontSize: 12,
                                  fontWeight: 600,
                                  color: '#2f3440',
                                }}
                              />
                            </div>

                            <button
                              onClick={handleSwap}
                              style={{
                                width: 24,
                                height: 24,
                                borderRadius: 4,
                                border: '1px solid #E7EAF0',
                                backgroundColor: '#fff',
                                cursor: 'pointer',
                                display: 'flex',
                                justifyContent: 'center',
                                alignItems: 'center',
                                color: '#8b5cf6',
                              }}
                            >
                              <SwapOutlined style={{ fontSize: 10 }} />
                            </button>

                            <div style={{
                              display: 'flex',
                              alignItems: 'center',
                              flex: 1,
                              maxWidth: 120,
                            }}>
                              <span style={{
                                color: '#98a2b3',
                                fontSize: 11,
                                marginRight: 4,
                              }}>
                                H
                              </span>
                              <Input
                                value={height}
                                onChange={(e) => setHeight(Number(e.target.value) || 0)}
                                style={{
                                  flex: 1,
                                  textAlign: 'center',
                                  borderRadius: 4,
                                  height: 34,
                                  border: '1px solid #E7EAF0',
                                  backgroundColor: '#FFFFFF',
                                  fontSize: 12,
                                  fontWeight: 600,
                                  color: '#2f3440',
                                }}
                              />
                            </div>

                            <span style={{ color: '#98a2b3', fontSize: 11 }}>
                              PX
                            </span>
                          </div>
                        </div>
                      </div>
                    )}
                  </div>
                )}

                {/* 视频参数设置 */}
                {mediaType === 'video' && (
                  <div style={{ position: 'relative', display: 'inline-block' }}>
                    <button
                      onClick={() => {
                        setShowMediaTypeModal(false);
                        setShowEngineModal(false);
                        setShowImageSettingsModal(false);
                        setReferenceModeDropdownVisible(false);
                        setShowVideoSettingsModal(!showVideoSettingsModal);
                      }}
                      className="image-settings-trigger"
                      style={{
                        minWidth: 156,
                        padding: '6px 14px',
                        height: 32,
                        borderRadius: 10,
                        border: '1px solid #E7EAF0',
                        backgroundColor: '#ffffff',
                        cursor: 'pointer',
                        display: 'inline-flex',
                        alignItems: 'center',
                        gap: 6,
                        transition: 'all 0.2s ease',
                        boxShadow: '0 1px 2px rgba(47, 52, 64, 0.025)',
                      }}
                      onMouseEnter={(e) => {
                        e.currentTarget.style.backgroundColor = '#FFFFFF';
                        e.currentTarget.style.borderColor = '#D7DDE7';
                        e.currentTarget.style.boxShadow = '0 2px 8px rgba(47, 52, 64, 0.06)';
                      }}
                      onMouseLeave={(e) => {
                        e.currentTarget.style.backgroundColor = '#ffffff';
                        e.currentTarget.style.borderColor = '#E7EAF0';
                        e.currentTarget.style.boxShadow = '0 1px 2px rgba(47, 52, 64, 0.03)';
                      }}
                    >
                      <LayoutOutlined style={{ fontSize: 14, color: '#2f3440' }} />
                      <span style={{ fontSize: 13, fontWeight: 600, color: '#2f3440' }}>{videoAspectRatio}</span>
                      <span style={{ width: 1, height: 14, background: '#E7EAF0' }} />
                      <span style={{ fontSize: 13, fontWeight: 600, color: '#2f3440' }}>{videoResolution?.toUpperCase?.() || videoResolution}</span>
                      <span style={{ width: 1, height: 14, background: '#E7EAF0' }} />
                      <span style={{ fontSize: 13, fontWeight: 600, color: '#2f3440' }}>{videoDuration}秒</span>
                      <CaretDownOutlined style={{ fontSize: 10, color: '#667085', marginLeft: 'auto' }} />
                    </button>

                    {showVideoSettingsModal && (
                      <div
                        className="image-settings-popover"
                        style={{
                          position: 'absolute',
                          bottom: 'calc(100% + 8px)',
                          left: 0,
                          width: 400,
                          backgroundColor: '#ffffff',
                          backdropFilter: 'blur(16px)',
                          borderRadius: 14,
                          boxShadow: '0 18px 44px rgba(47, 52, 64, 0.12)',
                          padding: 16,
                          border: '1px solid #E7EAF0',
                          zIndex: 9999,
                        }}
                        onClick={(e) => e.stopPropagation()}
                      >
                        {/* 选择比例 */}
                        <div style={{ marginBottom: 16 }}>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            选择比例
                          </Text>
                          <div style={{
                            display: 'flex',
                            flexWrap: 'wrap',
                            gap: 4,
                          }}>
                            {engineOptions.ratios.map((ratio) => (
                              <button
                                key={ratio}
                                onClick={() => setVideoAspectRatio(ratio)}
                                style={{
                                  flex: '0 0 calc(14.28% - 4px)',
                                  minWidth: 44,
                                  height: 52,
                                  borderRadius: 6,
                                  border: videoAspectRatio === ratio
                                    ? '2px solid #8b5cf6'
                                    : '1px solid #E7EAF0',
                                  backgroundColor: videoAspectRatio === ratio
                                    ? '#f5f3ff'
                                    : '#FFFFFF',
                                  cursor: 'pointer',
                                  display: 'flex',
                                  flexDirection: 'column',
                                  justifyContent: 'center',
                                  alignItems: 'center',
                                  transition: 'all 0.2s',
                                }}
                              >
                                <div style={{
                                  width: (() => {
                                    const [w, h] = ratio.split(':').map(Number);
                                    const maxSize = 18;
                                    if (w >= h) return maxSize;
                                    return Math.round(maxSize * (w / h));
                                  })(),
                                  height: (() => {
                                    const [w, h] = ratio.split(':').map(Number);
                                    const maxSize = 18;
                                    if (h >= w) return maxSize;
                                    return Math.round(maxSize * (h / w));
                                  })(),
                                  border: `2px solid ${videoAspectRatio === ratio ? '#8b5cf6' : '#98a2b3'}`,
                                  borderRadius: 2,
                                  marginBottom: 2,
                                }} />
                                <span style={{
                                  fontSize: 9,
                                  color: videoAspectRatio === ratio
                                    ? '#8b5cf6'
                                    : '#667085',
                                  fontWeight: videoAspectRatio === ratio ? 600 : 400,
                                }}>
                                  {ratio}
                                </span>
                              </button>
                            ))}
                          </div>
                        </div>

                        {/* 选择时长 */}
                        <div style={{ marginBottom: 16 }}>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            选择时长
                          </Text>
                          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                            <div style={{ flex: 1, position: 'relative', height: 24, display: 'flex', alignItems: 'center' }}>
                              {/* 背景轨道 */}
                              <div style={{
                                position: 'absolute',
                                top: '50%',
                                left: 0,
                                right: 0,
                                height: 6,
                                borderRadius: 3,
                                background: '#E7EAF0',
                                transform: 'translateY(-50%)',
                              }} />
                              {/* 已滑动部分 */}
                              <div style={{
                                position: 'absolute',
                                top: '50%',
                                left: 0,
                                height: 6,
                                borderRadius: 3,
                                background: '#8b5cf6',
                                width: `${((videoDuration - Math.min(...engineOptions.durations)) / (Math.max(...engineOptions.durations) - Math.min(...engineOptions.durations))) * 100}%`,
                                transform: 'translateY(-50%)',
                              }} />
                              {/* 滑块 */}
                              <input
                                type="range"
                                min={Math.min(...engineOptions.durations)}
                                max={Math.max(...engineOptions.durations)}
                                value={videoDuration}
                                onChange={(e) => setVideoDuration(Number(e.target.value))}
                                style={{
                                  position: 'relative',
                                  width: '100%',
                                  height: 24,
                                  borderRadius: 3,
                                  background: 'transparent',
                                  outline: 'none',
                                  appearance: 'none',
                                  cursor: 'pointer',
                                  zIndex: 1,
                                }}
                              />
                            </div>
                            <div style={{
                              display: 'flex',
                              alignItems: 'center',
                              gap: 4,
                              padding: '4px 12px',
                              backgroundColor: '#F6F7FA',
                              borderRadius: 6,
                            }}>
                              <span style={{ fontSize: 14, fontWeight: 600, color: '#667085' }}>
                                {videoDuration}
                              </span>
                              <span style={{ fontSize: 12, color: '#98a2b3' }}>秒</span>
                            </div>
                          </div>

                        </div>

                        {/* 选择分辨率 */}
                        <div>
                          <Text style={{
                            display: 'block',
                            marginBottom: 8,
                            fontSize: 12,
                            fontWeight: 500,
                            color: '#667085',
                          }}>
                            选择分辨率
                          </Text>
                          <div style={{ display: 'flex', gap: 6 }}>
                            {engineOptions.resolutions.map((resolution) => (
                              <button
                                key={resolution}
                                onClick={() => setVideoResolution(resolution)}
                                style={{
                                  flex: 1,
                                  height: 42,
                                  borderRadius: 6,
                                  border: videoResolution === resolution
                                    ? '2px solid #8b5cf6'
                                    : '1px solid #E7EAF0',
                                  backgroundColor: videoResolution === resolution
                                    ? '#8b5cf6'
                                    : '#FFFFFF',
                                  cursor: 'pointer',
                                  display: 'flex',
                                  justifyContent: 'center',
                                  alignItems: 'center',
                                  transition: 'all 0.2s',
                                }}
                              >
                                <span style={{
                                  fontSize: 12,
                                  fontWeight: 600,
                                  color: videoResolution === resolution
                                    ? '#fff'
                                    : '#475467',
                                }}>
                                  {resolution}
                                </span>
                              </button>
                            ))}
                          </div>
                        </div>
                      </div>
                    )}
                  </div>
                )}
              </Space>

              <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexShrink: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6, color: '#667085', whiteSpace: 'nowrap', height: 34, padding: '0 12px', borderRadius: 11, background: 'rgba(255, 255, 255, 0.92)', border: '1px solid rgba(231, 234, 240, 0.92)', boxShadow: '0 4px 12px rgba(47, 52, 64, 0.04)' }}>
                  <Text style={{ fontSize: 13, color: '#667085', fontWeight: 600 }}>预估积分：</Text>
                  <Text style={{ fontSize: 13, color: '#2f3440', fontWeight: 800 }}>{getEstimatedCredits()}</Text>
                </div>
                <Button
                  type="primary"
                  shape="circle"
                  icon={<ArrowUpOutlined />}
                  onClick={handleSend}
                  disabled={!composerCanSend}
                  loading={loading}
                  style={{
                    flexShrink: 0,
                    width: 36,
                    height: 36,
                    borderRadius: '50%',
                    background: composerCanSend
                      ? 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)'
                      : '#E7EAF0',
                    color: '#ffffff',
                    opacity: composerCanSend ? 1 : 0.86,
                    boxShadow: composerCanSend ? '0 10px 24px rgba(139, 92, 246, 0.28)' : 'inset 0 0 0 1px rgba(139, 92, 246, 0.18)',
                    cursor: composerCanSend ? 'pointer' : 'not-allowed',
                    transition: 'all 0.2s ease',
                    border: 'none',
                  }}
                />
              </div>
            </div>
          </div>
        </Content>
      </Layout>

      {/* 自定义CSS动画 - 加载中闪烁效果 */}
      <style>{`

        .ai-create-page {
          --ai-accent: #8b5cf6;
          --ai-accent-soft: #f5f3ff;
          --ai-accent-mid: #a78bfa;
        }
        @keyframes blink {
          0%, 50% { opacity: 1; }
          51%, 100% { opacity: 0.3; }
        }
        textarea::placeholder {
          color: #98a2b3 !important;
          line-height: 1.72 !important;
          font-weight: 500 !important;
          white-space: normal !important;
        }
        .ai-create-scroll::-webkit-scrollbar {
          width: 8px;
        }
        .ai-create-scroll::-webkit-scrollbar-thumb {
          background: rgba(139, 92, 246, 0.32);
          border-radius: 999px;
        }
        .ai-create-scroll::-webkit-scrollbar-track {
          background: transparent;
        }
        .ai-composer-select .ant-select-selector {
          height: 32px !important;
          border-radius: 11px !important;
          border-color: #E7EAF0 !important;
          box-shadow: 0 1px 3px rgba(47, 52, 64, 0.035) !important;
          background: rgba(255,255,255,0.86) !important;
        }
        .ai-composer-select .ant-select-selection-item {
          display: flex !important;
          align-items: center !important;
          font-weight: 700 !important;
          color: #2f3440 !important;
        }
        .ant-select-dropdown {
          border-radius: 16px !important;
          box-shadow: 0 20px 48px rgba(47, 52, 64, 0.12) !important;
          border: 1px solid #E7EAF0 !important;
          padding: 8px !important;
        }
        .ant-select-dropdown .ant-select-item {
          border-radius: 10px !important;
          min-height: 36px !important;
          color: #2f3440 !important;
          font-weight: 600 !important;
        }
        .ant-select-dropdown .ant-select-item-option-active,
        .ant-select-dropdown .ant-select-item-option-selected {
          background: #f5f3ff !important;
          color: #8b5cf6 !important;
        }
        .image-settings-popover {
          animation: composerPopoverIn 0.16s ease-out;
        }
        @keyframes composerPopoverIn {
          from { opacity: 0; transform: translateY(6px) scale(0.98); }
          to { opacity: 1; transform: translateY(0) scale(1); }
        }
      `}</style>

      {/* 图片/视频预览弹窗 */}
      <Modal
        open={previewVisible}
        title={
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{ width: 4, height: 20, background: 'linear-gradient(180deg, #8b5cf6 0%, #ddd6fe 100%)', borderRadius: 2 }} />
            <span style={{ fontSize: 16, fontWeight: 700, color: '#8b5cf6', letterSpacing: 0.4 }}>
              预览
            </span>
          </div>
        }
        onCancel={handleClosePreview}
        width={800}
        footer={
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12, padding: '16px 24px', background: 'rgba(255,255,255,0.6)', borderTop: '1px solid rgba(139, 92, 246, 0.08)' }}>
            <Button
              type="primary"
              icon={<DownloadOutlined />}
              onClick={handleDownload}
              style={{ borderRadius: 10, background: 'linear-gradient(135deg, #8b5cf6 0%, #ddd6fe 100%)', border: 'none', boxShadow: '0 8px 18px rgba(47, 52, 64, 0.15)' }}
              disabled={isMediaExpired(previewUrl)}
            >
              {isMediaExpired(previewUrl) ? '资源已过期' : '下载'}
            </Button>
          </div>
        }
        centered
        style={{ borderRadius: 16 }}
        styles={{
          body: {
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            minHeight: '400px',
          },
          header: { background: 'rgba(255,255,255,0.6)', backdropFilter: 'blur(10px)', borderBottom: '1px solid rgba(139, 92, 246, 0.08)', padding: '16px 24px' },
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }}>
          {isMediaExpired(previewUrl) ? (
            <div style={{ textAlign: 'center', padding: '40px' }}>
              <p style={{ fontSize: 16, color: '#A45B5B', marginBottom: 16 }}>图片/视频资源已过期，请刷新重新加载～</p>
            </div>
          ) : previewType === 'image' ? (
            <img
              src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}/static${previewUrl}&w=300&q=50`}
              alt="预览"
              style={{ width: '100%', maxHeight: '400px', objectFit: 'contain' }}
            />
          ) : (
            <video
              ref={videoRef}
              src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewUrl}`}
              controls
              style={{ maxWidth: '100%', maxHeight: '400px' }}
            />
          )}
        </div>
      </Modal>

      {/* 附件预览弹窗（独立弹窗） */}
      <Modal
        open={attachmentPreviewVisible}
        title={
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{ width: 4, height: 20, background: 'linear-gradient(180deg, #8b5cf6 0%, #ddd6fe 100%)', borderRadius: 2 }} />
            <span style={{ fontSize: 16, fontWeight: 700, color: '#8b5cf6', letterSpacing: 0.4 }}>
              附件预览
            </span>
          </div>
        }
        onCancel={() => {
          // 关闭前停止视频播放
          if (attachmentPreviewVideoRef.current) {
            const v = attachmentPreviewVideoRef.current;
            v.pause();
            v.muted = true;
            v.currentTime = 0;
          }
          setAttachmentPreviewVisible(false);
        }}
        afterClose={() => {
          // Modal 完全关闭后再次确保视频被停止
          if (attachmentPreviewVideoRef.current) {
            const v = attachmentPreviewVideoRef.current;
            v.pause();
            v.muted = true;
          }
        }}
        width={800}
        footer={
          <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12, padding: '16px 24px', background: 'rgba(255,255,255,0.6)', borderTop: '1px solid rgba(139, 92, 246, 0.08)' }}>
            <Button
              type="primary"
              icon={<DownloadOutlined />}
              onClick={() => {
                if (!attachmentPreviewUrl) return;
                const link = document.createElement('a');
                link.href = `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${attachmentPreviewUrl}&download=1`;
                link.download = attachmentPreviewName || (attachmentPreviewType === 'image' ? 'image.png' : 'video.mp4');
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
              }}
              style={{ borderRadius: 10, background: 'linear-gradient(135deg, #8b5cf6 0%, #ddd6fe 100%)', border: 'none', boxShadow: '0 8px 18px rgba(47, 52, 64, 0.15)' }}
            >
              下载
            </Button>
          </div>
        }
        centered
        style={{ borderRadius: 16 }}
        styles={{
          body: {
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            minHeight: '400px',
          },
          header: { background: 'rgba(255,255,255,0.6)', backdropFilter: 'blur(10px)', borderBottom: '1px solid rgba(139, 92, 246, 0.08)', padding: '16px 24px' },
        }}
      >
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }}>
          {attachmentPreviewType === 'image' ? (
            <img
              src={buildPreviewUrl(attachmentPreviewUrl)}
              alt="预览"
              style={{ width: '100%', maxHeight: '400px', objectFit: 'contain' }}
            />
          ) : (
            <video
              ref={attachmentPreviewVideoRef}
              src={buildPreviewUrl(attachmentPreviewUrl)}
              controls
              playsInline
              style={{ maxWidth: '100%', maxHeight: '400px' }}
            />
          )}
        </div>
      </Modal>
      <PrivatePortraitAssetPicker
        open={privateAssetPickerOpen}
        libraryType={privateAssetPickerLibraryType}
        onClose={() => setPrivateAssetPickerOpen(false)}
        onSelect={handlePrivatePortraitAssetsSelected}
        selectedIds={currentMedia.map((m) => m.private_asset_id).filter(Boolean) as string[]}
        maxCount={Math.max(1, maxImage + maxVideo)}
        maxImageCount={maxImageCount}
        maxVideoCount={maxVideoCount}
        usedImageCount={currentMedia.filter(m => m.type === 'image').length}
        usedVideoCount={currentMedia.filter(m => m.type === 'video').length}
        usedVideoDuration={currentMedia.filter(m => m.type === 'video').reduce((sum, m) => sum + (m.duration || 0), 0)}
        maxVideoDuration={15}
        accept={mediaType === 'image' ? 'image/*' : 'image/*,video/*'}
      />

    </Layout>
  );
};

export default AIChatPage;
