
import React, { useState, useEffect, useRef } from 'react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { Image as ImageIcon, Loader2 } from 'lucide-react';
import {Input} from '@/components/ui/input';
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/components/ui/select';
import {
  History as HistoryIcon,
  Search,
  Filter,
  Clock,
  Eye,
  Download,
  RefreshCw,
  MoreHorizontal,
  ImageOff,
  AlertCircle,
  Trash2,
  Plus,
  ChevronDown
} from 'lucide-react';
import {motion, AnimatePresence} from 'framer-motion';
import {useAuth} from '@/contexts/AuthContext';
import {useNavigate} from 'react-router-dom';
import { toast } from 'sonner';

// 导入AI生图API
import {aiSwapAPI} from '@/api/ai_swap';
import {aiSwapBgAPI} from '@/api/ai_swap_bg';
import {aiSwapClothAPI} from '@/api/ai_swap_cloth';
import {aiSwapFaceAPI} from '@/api/ai_swap_face';
import { aiGenVideoAPI } from '@/api/ai_gen_video';
import { textTemplateAPI } from '@/api/textTemplates';
import { materialLibraryAPI } from '@/api/materials';

// 获取图片URL的辅助函数
const getImageUrl = (item) => {
  if (!item || !item.stored_path) {
    console.log('无效的图片数据：', item);
    return '';
  }

  try {
    const filename = item.stored_path.split(/[\\/]/).pop();
    if (!filename) {
      console.warn('无法从路径提取文件名：', item.stored_path);
      return '';
    }

    let baseUrl = import.meta.env.VITE_API_BASE_URL || '';
    if (!baseUrl) {
      console.warn('API基础URL未配置');
      return '';
    }

    // 根据图片类型和路径判断使用哪个静态文件服务
    let url = '';
    if (item.image_type === 'result' || item.stored_path.includes('output')) {
      // 结果图片使用 /output 路径
      url = `${baseUrl}/output/${filename}`;
    } else {
      // 素材图片使用 /materials 路径
      url = `${baseUrl}/materials/${filename}`;
    }

    console.log('生成的图片URL:', url);
    return url;
  } catch (error) {
    console.error('生成图片URL时出错', error);
    return '';
  }
}; 

// 判断文件是否为视频格式
const isVideoFile = (url) => {
  if (!url) return false;
  const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv', '.m4v'];
  const lowerUrl = url.toLowerCase();
  return videoExtensions.some(ext => lowerUrl.includes(ext));
};

// 媒体组件（支持图片和视频）
const MediaWithFallback = ({ src, alt, className, onLoad, onClick, isSelectable = false, isSelected = false, ...mediaProps }) => {
  const [error, setError] = useState(false);
  const [loading, setLoading] = useState(true);
  const [isVideo, setIsVideo] = useState(false);

  useEffect(() => {
    if (src) {
      setIsVideo(isVideoFile(src));
    }
  }, [src]);

  const handleError = (e) => {
    try {
      console.error(`媒体加载失败 - ${alt}:`, e);
    } catch (_) {
      console.error('媒体加载失败');
    }
    setError(true);
    setLoading(false);
  };

  const handleLoad = () => {
    setLoading(false);
    if (onLoad) onLoad();
  };

  // 如果没有src，显示无媒体状态
  if (!src) {
    return (
      <div className={`flex items-center justify-center ${className} bg-slate-50`}>
        <ImageOff className="w-6 h-6 text-slate-400" />
        <span className="text-xs text-slate-500 ml-2">无媒体</span>
      </div>
    );
  }

  // 如果加载出错，显示错误状态
  if (error) {
    return (
      <div className={`flex items-center justify-center ${className} bg-slate-50`}>
        <AlertCircle className="w-6 h-6 text-red-400" />
        <span className="text-xs text-red-500 ml-2">加载失败</span>
      </div>
    );
  }

  return (
    <div className={`relative w-full h-full ${isSelectable ? 'cursor-pointer' : ''} ${isSelected ? 'ring-2 ring-blue-500' : ''}`} onClick={onClick}>
      {loading && (
        <div className="absolute inset-0 flex items-center justify-center bg-slate-50">
          <Loader2 className="w-6 h-6 text-slate-400 animate-spin" />
        </div>
      )}
      {isSelected && (
        <div className="absolute top-2 right-2 w-6 h-6 bg-blue-500 rounded-full flex items-center justify-center z-10">
          <div className="w-3 h-3 bg-white rounded-full"></div>
        </div>
      )}
      {isVideo ? (
        <video
          src={src}
          className={`${className} ${loading ? 'invisible' : 'visible'}`}
          onError={handleError}
          onLoadedData={handleLoad}
          controls
          muted
          playsInline
          preload="metadata"
          {...mediaProps}
        >
          您的浏览器不支持视频播放。
        </video>
      ) : (
        <img
          src={src}
          alt={alt}
          className={`${className} ${loading ? 'invisible' : 'visible'}`}
          onError={handleError}
          onLoad={handleLoad}
          {...mediaProps}
        />
      )}
    </div>
  );
};

// 为了向后兼容，保留 ImageWithFallback 作为 MediaWithFallback 的别名
const ImageWithFallback = MediaWithFallback;

// 将图片URL转换为临时素材ID的辅助函数
const uploadImageFromUrl = async (imageUrl, userId) => {
  try {
    // 获取图片数据
    const response = await fetch(imageUrl);
    if (!response.ok) {
      throw new Error(`无法获取图片: ${response.status}`);
    }
    const blob = await response.blob();
    
    // 生成临时文件名
    const timestamp = Date.now();
    const filename = `temp_video_source_${timestamp}.jpg`;
    
    // 上传到素材库
    const uploadResult = await materialLibraryAPI.uploadMaterial(
      userId,
      blob,  // File 对象
      'result', // image_type
      filename  // original_filename
    );
    if (uploadResult.success) {
      return uploadResult.material_id;
    } else {
      throw new Error(uploadResult.error || '上传失败');
    }
  } catch (error) {
    console.error('上传图片失败:', error);
    throw error;
  }
};


// 添加提取标题的辅助函数
const extractTitle = (text) => {
  if (!text) return '';

  // 查找标题部分（以 "- 标题：" 开头的内容）
  const titleMatch = text.match(/[-\s]*标题：\s*([^\n-]+)/);
  if (titleMatch && titleMatch[1]) {
    return titleMatch[1].trim();
  }

  return '';
};

// 添加提取文案的辅助函数
const extractContent = (text) => {
  if (!text) return '';
  
  
  // 查找文案部分（以 "- 文案：" 开头的内容）
  const contentMatch = text.match(/[-\s]*文案：\s*([^\n-]+)/);
  if (contentMatch && contentMatch[1]) {
    return contentMatch[1].trim();
  }

  return '';
};

// 添加提取话题标签的辅助函数
const extractLabel = (text) => {
  if (!text) return '';
  
  // 查找话题标签部分（以 "- 话题标签：" 开头的内容）
  const labelMatch = text.match(/[-\s]*话题标签：\s*([^\n-]+)/);
  if (labelMatch && labelMatch[1]) {
    return labelMatch[1].trim();
  }

  return '';
};

// 下载辅助
const sanitizeFilename = (name) => {
  return String(name || 'download')
    .replace(/[\\/:*?"<>|\n\r]+/g, '_')
    .slice(0, 120);
};

const getFilenameFromUrl = (url, fallback) => {
  try {
    const u = new URL(url);
    const name = u.pathname.split('/').pop();
    return name || fallback;
  } catch {
    try {
      const parts = (url || '').split('?')[0].split('/');
      return parts[parts.length - 1] || fallback;
    } catch {
      return fallback;
    }
  }
};

const downloadBlob = (blob, filename) => {
  const href = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = href;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(href);
};

const downloadUrl = async (url, filename) => {
  const res = await fetch(url, { mode: 'cors' });
  if (!res.ok) throw new Error(`下载失败 ${res.status}`);
  const blob = await res.blob();
  downloadBlob(blob, filename);
};

// 状态显示
const getStatusName = (status) => {
  const names = {
    approved: '已审核',
    pending: '待审核',
    processing: '处理中',
    failed: '处理失败',
  };
  return names[status] || status || '未知';
};

const getStatusPillClass = (status) => {
  const classes = {
    approved: 'bg-green-50 text-green-700',
    pending: 'bg-yellow-50 text-yellow-700',
    processing: 'bg-orange-50 text-orange-700',
    failed: 'bg-red-50 text-red-700',
  };
  return classes[status] || 'bg-gray-50 text-gray-700';
};

// 任务类型显示
const getTaskTypeName = (taskType) => {
  const map = {
    swap_face: '换脸',
    swap_cloth: '换衣',
    swap_bg: '换景',
    swap_all: '替换',
    img2video: '图生视频',
  };
  return map[taskType] || taskType || '未知类型';
};

// 分组偏好：用于固定某个 face+cloth 组合的“基准记录”
const getGroupKey = (faceId, clothId) => `${faceId}-${clothId}`;
const getPreferredRecordId = (groupKey) => {
  try { return localStorage.getItem(`contentPreferred:${groupKey}`); } catch { return null; }
};
const setPreferredRecordId = (groupKey, recordId) => {
  try { localStorage.setItem(`contentPreferred:${groupKey}`, String(recordId)); } catch {}
};

export default function ContentBrowser() {
  const { user, isAuthenticated } = useAuth();
  const navigate = useNavigate();
  const [selectedContent, setSelectedContent] = useState(null);
  const [generatedContents, setGeneratedContents] = useState([]);
  const [allContents, setAllContents] = useState([]);
  const [loading, setLoading] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isApproving, setIsApproving] = useState(false);
  const [isGenerating, setIsGenerating] = useState(false); // 新增生成状态
  const [tempResultSlots, setTempResultSlots] = useState([]); // 本地占位槽位 {id,status:'running'|'done',url}
  const [generatedItemPx, setGeneratedItemPx] = useState(null); // 生成图片项高度（与参考图等高）
  const faceBoxRef = useRef(null);
  const [searchTerm, setSearchTerm] = useState('');
  const [filterStatus, setFilterStatus] = useState('all');
  const [regenerating, setRegenerating] = useState({}); // process_id -> true
  // 视频生成相关状态
  const [freePrompt, setFreePrompt] = useState('');
  const [sceneTemplates, setSceneTemplates] = useState([]);
  const [selectedSceneTemplateIds, setSelectedSceneTemplateIds] = useState([]);
  // 选择视频来源：原图/服装/某一张生成图
  const [selectedVideoSource, setSelectedVideoSource] = useState(null); // { type: 'original'|'cloth'|'generated', url?: string }

  // 同步生成图片项高度与参考图片等高
  useEffect(() => {
    const syncSize = () => {
      try {
        const el = faceBoxRef.current;
        if (el) {
          const w = el.clientWidth;
          if (w && w !== generatedItemPx) setGeneratedItemPx(w);
        }
      } catch {}
    };
    syncSize();
    window.addEventListener('resize', syncSize);
    return () => window.removeEventListener('resize', syncSize);
  }, [generatedItemPx, selectedContent]);

  useEffect(() => {
    if (!isAuthenticated) {
      navigate('/login');
      return;
    }
    loadData();
    // 加载场景模板
    (async () => {
      try {
        if (!user?.id) return;
        const resp = await textTemplateAPI.getTextTemplates(user.id, 'prompt', 1, 100);
        const list = (resp && resp.success && Array.isArray(resp.templates))
          ? resp.templates.map(t => ({ id: t.id, name: t.text_name, content: t.text_content, tag: t.text_label }))
          : [];
        setSceneTemplates(list);
      } catch (e) {
        console.error('加载场景模板失败:', e);
      }
    })();
  }, [isAuthenticated, user]);

  const loadData = async (preferGroupKey) => {
    if (!isAuthenticated || !user?.id) return;
    setLoading(true);
    // 清空临时结果槽位，因为数据重新加载时应该显示实际的记录数据
    setTempResultSlots([]);
    try {
      // 拉取用户历史，取前100条
      const pageSize = 100;
      const firstResp = await aiSwapAPI.getUserProcessHistory(user.id, 1, pageSize);
      const records = Array.isArray(firstResp?.records) ? firstResp.records : [];
      // 并发获取每条记录详情
      const details = await Promise.all(
        records.map(r => aiSwapAPI.getProcessDetail(r.id, user.id).catch(() => null))
      );

      // 先平铺：带上 face/cloth id 与时间戳及原始图片对象
      const flattened = records.map((r, idx) => {
        const d = details[idx];
        const generatedText = d?.process_record?.generated_text || r.generated_text || '';
        const normalizedStatus = (r.status === '已审核' || r.status === 'approved') ? 'approved' : 'pending';
        return {
          id: r.id,
          face_image_id: r.face_image_id,
          cloth_image_id: r.cloth_image_id,
          task_type: d?.process_record?.task_type || r.task_type || '',
          prompt: d?.process_record?.prompt || r.prompt || '',
          title: extractTitle(generatedText) || `AI换脸换装处理 - 记录 #${r.id}`,
          content: extractContent(generatedText) || '无文案内容',
          label: extractLabel(generatedText) || '无话题标签',
          status: normalizedStatus,
          created_date: new Date(r.completed_at || r.created_at).toLocaleString(),
          completed_at_ts: new Date(r.completed_at || r.created_at).getTime(),
          raw_status: r.status,
          face_image: d?.face_image || null,
          cloth_image: d?.cloth_image || null,
          result_image: d?.result_image || null,
          additional_images: Array.isArray(d?.additional_images) ? d.additional_images : [],
        };
      });

      // 分组合并：以 face_image_id + cloth_image_id 为 key
      const idToFlat = new Map(flattened.map(it => [it.id, it]));
      const groupedMap = new Map();
      for (const item of flattened) {
        const groupKey = getGroupKey(item.face_image_id, item.cloth_image_id);
        const existing = groupedMap.get(groupKey);
        const currentResults = [
          ...(item.result_image ? [item.result_image] : []),
          ...(item.additional_images || [])
        ];

        if (!existing) {
          groupedMap.set(groupKey, {
            ...item,
            groupKey,
            result_images: currentResults.slice(),
            record_ids: [item.id],
            members: [{
              id: item.id,
              task_type: item.task_type,
              title: item.title,
              content: item.content,
              label: item.label,
              status: item.status,
              created_date: item.created_date,
              completed_at_ts: item.completed_at_ts,
            }],
          });
        } else {
          // 结果图片聚合（简单追加，稍后去重）
          if (currentResults.length > 0) {
            existing.result_images = existing.result_images.concat(currentResults);
          }
          // 使用最新记录更新标题文案等
          if (item.completed_at_ts > existing.completed_at_ts) {
            existing.id = item.id;
            existing.task_type = item.task_type;
            existing.title = item.title;
            existing.content = item.content;
            existing.label = item.label;
            existing.status = item.status;
            existing.created_date = item.created_date;
            existing.completed_at_ts = item.completed_at_ts;
            // face/cloth 图片不变（相同素材）
          }
          existing.record_ids.push(item.id);
          existing.members.push({
            id: item.id,
            task_type: item.task_type,
            title: item.title,
            content: item.content,
            label: item.label,
            status: item.status,
            created_date: item.created_date,
            completed_at_ts: item.completed_at_ts,
          });
        }
      }

      // 去重图片（以 stored_path）并生成最终分组数组
      const uniqueByPath = (images) => {
        const seen = new Set();
        const result = [];
        for (const img of images || []) {
          const key = img?.stored_path || JSON.stringify(img || {});
          if (!seen.has(key)) { seen.add(key); result.push(img); }
        }
        return result;
      };

      const grouped = Array.from(groupedMap.values()).map(group => {
        const preferredId = getPreferredRecordId(group.groupKey);
        const canonicalMember = (preferredId && group.members?.find(m => String(m.id) === String(preferredId)))
          || (group.members || []).reduce((acc, cur) => (cur.completed_at_ts > acc.completed_at_ts ? cur : acc), (group.members || [group])[0]);

        const faceUrl = group.face_image ? getImageUrl(group.face_image) : '';
        const clothUrl = group.cloth_image ? getImageUrl(group.cloth_image) : '';
        const allResults = uniqueByPath(group.result_images).map(img => getImageUrl(img)).filter(Boolean);
        // 每个成员自己的主结果图 meta，用于删除
        const metas = (group.members || []).map(m => {
          const rec = idToFlat.get(m.id);
          if (rec && rec.result_image) {
            return { url: getImageUrl(rec.result_image), process_id: m.id };
          }
          return null;
        }).filter(Boolean);
        const metaUrls = metas.map(m => m.url);
        const additionalUrls = allResults.filter(u => !metaUrls.includes(u));

        return {
          id: canonicalMember?.id ?? group.id,
          task_type: canonicalMember?.task_type ?? group.task_type,
          title: canonicalMember?.title ?? group.title,
          content: canonicalMember?.content ?? group.content,
          label: canonicalMember?.label ?? group.label,
          status: canonicalMember?.status ?? group.status,
          created_date: canonicalMember?.created_date ?? group.created_date,
          face_image_id: group.face_image_id,
          cloth_image_id: group.cloth_image_id,
          original_image_url: faceUrl,
          cloth_image_url: clothUrl,
          generated_image_urls: allResults,
          result_images_meta: metas,
          additional_result_urls: additionalUrls,
          record_ids: Array.from(new Set(group.record_ids)),
          groupKey: group.groupKey,
        };
      });

      // 选中最近的分组（按 canonical 的时间），或优先使用指定的组合 key
      let selectedByPref = null;
      if (preferGroupKey) {
        selectedByPref = grouped.find(g => g.groupKey === preferGroupKey) || null;
      }
      const latestGroup = grouped
        .map((g, i) => ({ g, i, ts: new Date(g.created_date).getTime() }))
        .sort((a, b) => b.ts - a.ts)[0];
      const selected = selectedByPref || (latestGroup ? grouped[latestGroup.i] : (grouped[0] || null));

      setAllContents(grouped);
      setSelectedContent(selected);
    } catch (error) {
      console.error('加载数据失败:', error);
      setAllContents([]);
      setSelectedContent(null);
    } finally {
      setLoading(false);
    }
  };

  // 选中一条记录并滚动到页面顶部
  const handleSelectContent = (item) => {
    setSelectedContent(item);
    // 清空临时结果槽位，因为这些槽位是针对之前选中记录的
    setTempResultSlots([]);
    // 重置视频选择与输入
    setSelectedVideoSource(null);
    setFreePrompt('');
    setSelectedSceneTemplateIds([]);
    try {
      if (typeof window !== 'undefined' && window.scrollTo) {
        window.scrollTo({ top: 0, behavior: 'smooth' });
      }
    } catch (_) {
      try { window.scrollTo(0, 0); } catch {}
    }
  };

  // 重新生成：删除该结果图，然后基于当前记录触发一次生成，并在完成后替换该位置的图片
  const handleRegenerateImage = async (meta, index) => {
    if (!isAuthenticated || !user?.id || !selectedContent) return;
    const processId = meta?.process_id;
    if (!processId) return;

    try {
      // 1) UI 置灰 + 转圈
      setRegenerating(prev => ({ ...prev, [processId]: true }));

      // 2) 先删除当前结果图（后端要求）
      await aiSwapAPI.deleteResultImage(processId, user.id);

      // 3) 按当前记录参数启动生成
      const processDetail = await aiSwapAPI.getProcessDetail(selectedContent.id, user.id);
      const record = processDetail?.process_record;
      if (!record) throw new Error('未能获取到原始记录详情');

      const taskType = record.task_type || selectedContent.task_type || 'swap_face';
      const faceImageId = record.face_image_id || selectedContent.face_image_id;
      const clothImageId = record.cloth_image_id || selectedContent.cloth_image_id;
      const prompt = record.prompt || '';

      const payload = { user_id: user.id, prompt };
      let apiCall;
      if (taskType === 'swap_face') {
        if (!faceImageId) throw new Error('缺少人脸图片ID');
        apiCall = aiSwapFaceAPI.processSwapFace({ ...payload, raw_image_id: clothImageId || faceImageId, face_image_id: faceImageId });
      } else if (taskType === 'swap_cloth') {
        if (!faceImageId || !clothImageId) throw new Error('缺少人脸或服装图片ID');
        apiCall = aiSwapClothAPI.processSwapCloth({ ...payload, raw_image_id: faceImageId, cloth_image_id: clothImageId });
      } else if (taskType === 'swap_bg') {
        if (!faceImageId) throw new Error('缺少原始图片ID');
        apiCall = aiSwapBgAPI.processSwapBg({ ...payload, image_id: faceImageId });
      } else if (taskType === 'swap_all') {
        if (!faceImageId || !clothImageId) throw new Error('缺少人脸或服装图片ID');
        apiCall = aiSwapAPI.processSwap({ ...payload, face_image_id: faceImageId, cloth_image_id: clothImageId });
      } else {
        throw new Error('未知任务类型，无法生成图片');
      }

      const submitRes = await apiCall;
      if (!submitRes || submitRes.success === false) {
        throw new Error(submitRes?.error || submitRes?.message || '生成提交失败');
      }

      // 4) 轮询直到出现新图片URL
      const prevUrls = Array.isArray(selectedContent.generated_image_urls)
        ? selectedContent.generated_image_urls.slice()
        : [];
      const prevSet = new Set(prevUrls);

      const fetchGroupUrls = async () => {
        try {
          const pageSize = 100;
          const history = await aiSwapAPI.getUserProcessHistory(user.id, 1, pageSize);
          const records = Array.isArray(history?.records) ? history.records : [];
          const sameGroup = records.filter(r => String(r.face_image_id) === String(faceImageId) && String(r.cloth_image_id) === String(clothImageId));
          const details = await Promise.all(sameGroup.map(r => aiSwapAPI.getProcessDetail(r.id, user.id).catch(() => null)));
          const urls = [];
          for (const d of details) {
            if (d?.result_image) urls.push(getImageUrl(d.result_image));
            if (Array.isArray(d?.additional_images)) {
              for (const img of d.additional_images) urls.push(getImageUrl(img));
            }
          }
          return Array.from(new Set(urls.filter(Boolean)));
        } catch {
          return [];
        }
      };

      let obtainedUrl = null;
      for (let attempt = 0; attempt < 30; attempt++) {
        await new Promise(r => setTimeout(r, 2000));
        const urls = await fetchGroupUrls();
        const news = urls.filter(u => !prevSet.has(u));
        if (news.length > 0) { obtainedUrl = news[0]; break; }
      }

      // 5) 用新的URL替换该位置
      if (obtainedUrl) {
        const newUrl = obtainedUrl;
        setSelectedContent(prev => {
          if (!prev) return prev;
          const metas = Array.isArray(prev.result_images_meta) ? prev.result_images_meta.slice() : [];
          if (metas[index]) metas[index] = { ...metas[index], url: newUrl };
          const genUrls = Array.isArray(prev.generated_image_urls) ? prev.generated_image_urls.slice() : [];
          // 替换旧URL（若存在）
          const oldUrl = meta?.url;
          const replaced = genUrls.map(u => (u === oldUrl ? newUrl : u));
          const hasOld = genUrls.includes(oldUrl);
          const hasNew = replaced.includes(newUrl);
          const finalUrls = hasOld ? replaced : (hasNew ? replaced : replaced.concat(newUrl));
          return { ...prev, result_images_meta: metas, generated_image_urls: finalUrls };
        });
        setAllContents(list => list.map(item => {
          if (item.groupKey !== selectedContent.groupKey) return item;
          const metas = Array.isArray(item.result_images_meta) ? item.result_images_meta.slice() : [];
          if (metas[index]) metas[index] = { ...metas[index], url: newUrl };
          const genUrls = Array.isArray(item.generated_image_urls) ? item.generated_image_urls.slice() : [];
          const oldUrl = meta?.url;
          const replaced = genUrls.map(u => (u === oldUrl ? newUrl : u));
          const hasOld = genUrls.includes(oldUrl);
          const hasNew = replaced.includes(newUrl);
          const finalUrls = hasOld ? replaced : (hasNew ? replaced : replaced.concat(newUrl));
          return { ...item, result_images_meta: metas, generated_image_urls: finalUrls };
        }));
        toast.success('已重新生成', { richColors: true });
      } else {
        // 回退整体刷新
        await loadData(selectedContent.groupKey);
        toast.success('已提交重新生成，已刷新列表', { richColors: true });
      }
    } catch (e) {
      console.error('重新生成失败:', e);
      toast.error('重新生成失败：' + (e.message || '未知错误'), { richColors: true });
    } finally {
      setRegenerating(prev => ({ ...prev, [meta?.process_id]: false }));
    }
  };

  // 处理审核通过
  const handleApprove = async () => {
    if (!isAuthenticated || !user?.id) {
      console.log('用户未登录或ID无效，无法审核');
      return;
    }

    try {
      setIsApproving(true);
      console.log('准备审核记录:', {
        processId: selectedContent.process_record?.id || selectedContent.id,
        userId: user.id
      });

      // 组内所有记录ID（若没有则退化为当前ID）
      const recordIds = (selectedContent && Array.isArray(selectedContent.record_ids) && selectedContent.record_ids.length > 0)
        ? selectedContent.record_ids
        : [selectedContent.process_record?.id || selectedContent.id];

      console.log('准备批量审核记录 IDs:', recordIds);

      // 逐条调用审核接口
      for (const pid of recordIds) {
        try {
          const res = await aiSwapAPI.approveProcessRecord(pid, user.id);
          if (!res || !res.success) {
            throw new Error(res?.message || '未知错误');
          }
        } catch (e) {
          console.error(`记录 ${pid} 审核失败:`, e);
          throw new Error(`记录 ${pid} 审核失败: ${e.message}`);
        }
      }

      // 更新本地选中记录的显示状态
      // 更新选中记录与列表中对应分组的状态
      if (selectedContent.process_record) {
        selectedContent.process_record.status = '已审核';
      }
      selectedContent.status = '已审核';
      setSelectedContent({ ...selectedContent });

      // 同步当前页面卡片状态（按 record_ids 找到对应项）
      setGeneratedContents(prev => prev.map(item => {
        const ids = item.record_ids || [item.id];
        const anyMatched = ids.some(id => (selectedContent.record_ids || []).includes(id));
        return anyMatched ? { ...item, status: '已审核' } : item;
      }));

      alert('审核通过成功！');
      await loadData();
    } catch (error) {
      console.error('审核失败:', error);
      alert('审核失败：' + (error.message || '未知错误'));
    } finally {
      setIsApproving(false);
    }
  };  

  // 删除当前组合中某张结果图（基于其来源 process_id）
  const handleDeleteResultImage = async (processId) => {
    if (!isAuthenticated || !user?.id) return;
    try {
      if (!window.confirm('确定要删除该结果图片吗？删除后不可恢复。')) return;
      await aiSwapAPI.deleteResultImage(processId, user.id);
      // 本地同步选中项（移除对应 meta 与 URL）
      setSelectedContent(prev => {
        if (!prev) return prev;
        const metas = Array.isArray(prev.result_images_meta) ? prev.result_images_meta.slice() : [];
        const filteredMetas = metas.filter(m => String(m.process_id) !== String(processId));
        const removedMetaUrls = metas.filter(m => String(m.process_id) === String(processId)).map(m => m.url);
        const addUrls = Array.isArray(prev.additional_result_urls) ? prev.additional_result_urls.slice() : [];
        const filteredAdds = addUrls.filter(u => !removedMetaUrls.includes(u));
        const genUrls = Array.isArray(prev.generated_image_urls) ? prev.generated_image_urls.slice() : [];
        const filteredGen = genUrls.filter(u => !removedMetaUrls.includes(u));
        return { ...prev, result_images_meta: filteredMetas, additional_result_urls: filteredAdds, generated_image_urls: filteredGen };
      });
      // 同步底部列表中该组合的缩略集合
      setAllContents(list => list.map(item => {
        if (!item.result_images_meta) return item;
        const metas = item.result_images_meta.filter(m => String(m.process_id) !== String(processId));
        const removedUrls = item.result_images_meta.filter(m => String(m.process_id) === String(processId)).map(m => m.url);
        const addUrls = (item.additional_result_urls || []).filter(u => !removedUrls.includes(u));
        const genUrls = (item.generated_image_urls || []).filter(u => !removedUrls.includes(u));
        return item.id === (selectedContent?.id || item.id)
          ? { ...item, result_images_meta: metas, additional_result_urls: addUrls, generated_image_urls: genUrls }
          : item;
      }));
      alert('删除成功');
    } catch (e) {
      alert('删除失败：' + (e.message || '未知错误'));
    }
  };

  // 下载结果图
  const handleDownloadImage = async (url, index = 0) => {
    try {
      const title = selectedContent?.title || `记录#${selectedContent?.id || ''}`;
      const fallback = `${sanitizeFilename(title)}_${index + 1}.png`;
      const filename = sanitizeFilename(getFilenameFromUrl(url, fallback));
      // 优先走带CORS的后端直链（与 History.jsx 一致）
      let urlToUse = url;
      try {
        const base = import.meta.env.VITE_API_BASE_URL || '';
        const name = getFilenameFromUrl(url, filename);
        if (url.includes('/output/')) {
          urlToUse = `${base}/api/v1/output/${name}`;
        } else if (url.includes('/materials/')) {
          urlToUse = `${base}/api/v1/materials/${name}`;
        }
      } catch {}

      try {
        await downloadUrl(urlToUse, filename);
      } catch (e) {
        // 回退到原始URL尝试（有时后端路径不同）
        await downloadUrl(url, filename);
      }
    } catch (e) {
      console.error('下载失败:', e);
      try { toast?.error && toast.error('下载失败：' + (e.message || '未知错误'), { richColors: true }); } catch {}
      alert && alert('下载失败：' + (e.message || '未知错误'));
    }
  };

  // 已废弃：任务类型直接来自 selectedContent.task_type（在 loadData 时填充）

  // 新增生成图占位符点击
  const handleAddNewResultPlaceholder = async () => {
    if (!selectedContent || !isAuthenticated || !user?.id) {
      toast.error('请先选择一个内容进行操作', { richColors: true });
      return;
    }

    let errorToastMessage = '生成失败：'; // 提升到外层，确保catch可访问
    let slotId = null; // 用于在失败时移除占位

    try {
      setIsGenerating(true);
      const processDetail = await aiSwapAPI.getProcessDetail(selectedContent.id, user.id);
      const record = processDetail?.process_record;

      if (!record) {
        throw new Error('未能获取到原始记录详情');
      }

      const taskType = record.task_type || 'swap_face'; // 默认人脸
      const faceImageId = record.face_image_id;
      const clothImageId = record.cloth_image_id;
      const prompt = record.prompt || '';

      let apiCall;
      let successToastMessage;
      // errorToastMessage 在外层已初始化

      const payload = { user_id: user.id, prompt: prompt };

      // 记录点击时的已知URL集合，用于后续对比
      const prevUrls = Array.isArray(selectedContent?.generated_image_urls)
        ? selectedContent.generated_image_urls.slice()
        : [];
      const prevSet = new Set(prevUrls);

      // 添加一个本地占位槽位，显示加载动画
      slotId = Date.now() + Math.random();
      setTempResultSlots((slots) => [...slots, { id: slotId, status: 'running', url: null }]);

      if (taskType === 'swap_face') {
        if (!faceImageId) throw new Error('缺少人脸图片ID');
        // aiSwapFaceAPI 的 processSwapFace 需要 raw_image_id 和 face_image_id
        apiCall = aiSwapFaceAPI.processSwapFace({ ...payload, raw_image_id: clothImageId, face_image_id: faceImageId });
        successToastMessage = '人脸生成任务已提交！';
        errorToastMessage = '人脸生成任务提交失败：';
      } else if (taskType === 'swap_cloth') {
        if (!faceImageId || !clothImageId) throw new Error('缺少人脸或服装图片ID');
        // aiSwapClothAPI 的 processSwapCloth 需要 raw_image_id 和 cloth_image_id
        apiCall = aiSwapClothAPI.processSwapCloth({ ...payload, raw_image_id: faceImageId, cloth_image_id: clothImageId });
        successToastMessage = '服装生成任务已提交！';
        errorToastMessage = '服装生成任务提交失败：';
      } else if (taskType === 'swap_bg') {
        if (!faceImageId) throw new Error('缺少原始图片ID');
        // aiSwapBgAPI 的 processSwapBg 需要 image_id 和 prompt
        apiCall = aiSwapBgAPI.processSwapBg({ ...payload, image_id: faceImageId });
        successToastMessage = '背景生成任务已提交！';
        errorToastMessage = '背景生成任务提交失败：';
      } else if (taskType === 'swap_all') {
        if (!faceImageId || !clothImageId) throw new Error('缺少人脸或服装图片ID')
        // aiSwapAPI 的 processSwap 需要 face_image_id 和 cloth_image_id
        apiCall = aiSwapAPI.processSwap({ ...payload, face_image_id: faceImageId, cloth_image_id: clothImageId});
        successToastMessage = '换脸换装任务已提交！';
        errorToastMessage = '换脸换装任务提交失败：';
      } else {
        console.error('未知任务类型：', taskType); // 打印未知任务类型
        errorToastMessage = '未知任务类型，无法生成图片'; // 设置错误消息
        throw new Error('未知任务类型，无法生成图片');
      }

      const res = await apiCall;

      // 成功条件：存在 success=true 或者返回了 task_id/queue 接收
      if (!res || res.success === false) {
        throw new Error(res?.error || res?.message || '生成失败');
      }

      // 轮询查询直到出现新图片，填充到当前占位槽位
      const fetchGroupUrls = async () => {
        try {
          const pageSize = 100;
          const history = await aiSwapAPI.getUserProcessHistory(user.id, 1, pageSize);
          const records = Array.isArray(history?.records) ? history.records : [];
          const sameGroup = records.filter(r => String(r.face_image_id) === String(faceImageId) && String(r.cloth_image_id) === String(clothImageId));
          const details = await Promise.all(sameGroup.map(r => aiSwapAPI.getProcessDetail(r.id, user.id).catch(() => null)));
          const urls = [];
          for (const d of details) {
            if (d?.result_image) urls.push(getImageUrl(d.result_image));
            if (Array.isArray(d?.additional_images)) {
              for (const img of d.additional_images) urls.push(getImageUrl(img));
            }
          }
          return Array.from(new Set(urls.filter(Boolean)));
        } catch {
          return [];
        }
      };

      let obtainedUrl = null;
      for (let attempt = 0; attempt < 30; attempt++) { // 最长约60秒
        await new Promise(r => setTimeout(r, 2000));
        const urls = await fetchGroupUrls();
        const news = urls.filter(u => !prevSet.has(u));
        if (news.length > 0) {
          obtainedUrl = news[0];
          break;
        }
      }

      if (obtainedUrl) {
        // 用生成结果替换占位槽位
        const urlToAdd = obtainedUrl;
        setTempResultSlots(slots => slots.map(s => s.id === slotId ? { ...s, status: 'done', url: urlToAdd } : s));
        // 同步到当前选中项与底部列表
        setSelectedContent(prev => prev ? { ...prev, generated_image_urls: [...(prev.generated_image_urls || []), urlToAdd] } : prev);
        setAllContents(list => list.map(item => item.groupKey === selectedContent.groupKey ? { ...item, generated_image_urls: [...(item.generated_image_urls || []), urlToAdd] } : item));
        toast.success(successToastMessage, { richColors: true });
      } else {
        // 未在超时时间内拿到图，退化为整体刷新
        await loadData(selectedContent.groupKey);
        toast.success(successToastMessage, { richColors: true });
      }

    } catch (e) {
      console.error('新增生成图功能失败:', e);
      // 失败则移除占位槽位
      if (slotId) {
        setTempResultSlots(slots => slots.filter(s => s.id !== slotId));
      }
      toast.error((errorToastMessage || '生成失败：') + (e.message || '未知错误'), { richColors: true });
    } finally {
      setIsGenerating(false);
    }
  };

  const handleSave = async () => {
    if (!selectedContent || !isAuthenticated || !user?.id) return;
    try {
      setIsSaving(true);
      const payload = {
        title: (selectedContent.title || '').trim(),
        content: (selectedContent.content || '').trim(),
        label: (selectedContent.label || '').trim(),
      };
      const res = await aiSwapAPI.updateProcessText(selectedContent.id, user.id, payload);
      if (!res || !res.process_record) throw new Error('服务器响应格式错误');
      // 固定该组合的“基准记录”为当前保存的记录
      if (selectedContent.groupKey) {
        setPreferredRecordId(selectedContent.groupKey, selectedContent.id);
      }
      // 本地即时同步选中项与列表（标题/文案/标签）
      setSelectedContent(prev => prev ? { ...prev, title: payload.title, content: payload.content, label: payload.label } : prev);
      setAllContents(list => list.map(item => item.id === selectedContent.id ? { ...item, title: payload.title, content: payload.content, label: payload.label } : item));
      // 以服务端为准刷新（优先回到当前组合）
      // await loadData(selectedContent.groupKey);
      // alert('保存成功！');
      toast.success('保存成功', {'richColors': true});
    } catch (e) {
      console.error('保存失败:', e);
      toast.error('保存失败：' + (e.message || '未知错误'), {'richColors': true});
    } finally {
      setIsSaving(false);
    }
  };

  if (loading) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <Loader2 className="w-8 h-8 animate-spin text-blue-600" />
      </div>
    );
  }

  return (
    <div className="p-6">
      <div className="max-w-7xl mx-auto space-y-6">
        {/* 页面标题 */}
        <div className="mb-8">
          <div className="flex items-center justify-between">
            <div>
              <h1 className="text-3xl font-bold text-slate-900 mb-2 flex items-center gap-3">
                结果预览与审核
              </h1>
              <p className="text-slate-600">浏览、修改并审核AI生成的内容</p>
            </div>
            <div className="flex gap-2">
              {selectedContent && (
                <span className={`px-3 py-2 rounded-full text-sm ${getStatusPillClass(selectedContent.status)}`}>
                  {getStatusName(selectedContent.status)}
                </span>
              )}
              <Button className="bg-blue-600 hover:bg-blue-700" onClick={handleSave} disabled={isSaving || loading}>
                保存修改
              </Button>
              <Button className="bg-green-600 hover:bg-green-700" onClick={handleApprove} disabled={isApproving || loading}>
                审核通过
              </Button>
            </div>
          </div>
        </div>

        {/* 主要内容区域 */}
        <div className="grid grid-cols-12 gap-6">
          {/* 左侧图片区域 */}
          <div className="col-span-7">
            <Card>
                <CardHeader>
                  <CardTitle className="text-lg">图片素材  · {getTaskTypeName(selectedContent?.task_type)}</CardTitle>
                </CardHeader>
              <CardContent>
                <div className="grid grid-cols-2 gap-4">
                  {/* 人脸和服装图片 */}
                  <div className="space-y-4">
                      <div>
                      <Label className="text-sm font-medium text-slate-600 mb-2 block">参考图片</Label>
                        <div ref={faceBoxRef} className="aspect-square bg-slate-100 rounded-lg overflow-hidden">
                        {selectedContent?.original_image_url ? (
                          <MediaWithFallback 
                            src={selectedContent.original_image_url} 
                            alt="参考图片" 
                            className={`w-full h-full object-contain ${selectedVideoSource?.type === 'original' ? 'ring-2 ring-blue-500' : ''}`}
                            isSelectable
                            isSelected={selectedVideoSource?.type === 'original'}
                            onClick={() => setSelectedVideoSource({ type: 'original' })}
                          />
                        ) : (
                          <div className="w-full h-full flex items-center justify-center">
                            <ImageIcon className="w-12 h-12 text-slate-400" />
                          </div>
                        )}
                      </div>
                    </div>
                    <div>
                      <div className="aspect-square bg-slate-100 rounded-lg overflow-hidden">
                        {selectedContent?.cloth_image_url ? (
                          <MediaWithFallback 
                            src={selectedContent.cloth_image_url} 
                            alt="服装图片" 
                            className={`w-full h-full object-contain ${selectedVideoSource?.type === 'cloth' ? 'ring-2 ring-blue-500' : ''}`}
                            isSelectable
                            isSelected={selectedVideoSource?.type === 'cloth'}
                            onClick={() => setSelectedVideoSource({ type: 'cloth' })}
                          />
                        ) : (
                          <div className="w-full h-full flex items-center justify-center">
                            <ImageIcon className="w-12 h-12 text-slate-400" />
                          </div>
                        )}
                      </div>
                    </div>
                  </div>
                  
                  {/* 生成结果图片 */}
                  <div>
                    <Label className="text-sm font-medium text-slate-600 mb-2 block">生成图片</Label>
                    {selectedContent?.result_images_meta?.length > 0 || selectedContent?.generated_image_urls?.length > 0 ? (
                      <div className="max-h-[700px] overflow-y-auto pr-2">
                        <div className="grid grid-cols-1 gap-4">
                        {selectedContent?.result_images_meta?.map((m, idx) => (
                          <div key={`meta-${idx}`} className="relative bg-slate-100 rounded-lg overflow-hidden group" style={{height: generatedItemPx ? `${generatedItemPx}px` : undefined}}>
                            <MediaWithFallback src={m.url} alt={`生成结果${idx + 1}`} className={`w-full h-full object-contain ${regenerating[m.process_id] ? 'opacity-50 grayscale' : ''} ${selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === m.url ? 'ring-2 ring-blue-500' : ''}`} isSelectable isSelected={selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === m.url} onClick={() => setSelectedVideoSource({ type: 'generated', url: m.url })} />
                            {regenerating[m.process_id] && (
                              <div className="absolute inset-0 flex items-center justify-center">
                                <Loader2 className="w-10 h-10 animate-spin text-blue-500" />
                              </div>
                            )}
                            <div className="absolute bottom-2 right-2 flex gap-2">
                              <button
                                title="下载该结果图"
                                onClick={() => handleDownloadImage(m.url, idx)}
                                className="hidden group-hover:flex items-center justify-center w-10 h-10 rounded-full bg-white text-slate-700 shadow-md hover:bg-slate-100"
                              >
                                <Download className="w-5 h-5 text-blue-500" />
                              </button>
                              <button
                                title="删除该结果图"
                                onClick={() => handleDeleteResultImage(m.process_id)}
                                className="hidden group-hover:flex items-center justify-center w-10 h-10 rounded-full bg-white text-slate-700 shadow-md hover:bg-slate-100"
                              >
                                <Trash2 className="w-5 h-5 text-red-500" />
                              </button>
                              <button
                                title="重新生成"
                                onClick={() => handleRegenerateImage(m, idx)}
                                className="hidden group-hover:flex items-center justify-center w-10 h-10 rounded-full bg-white text-slate-700 shadow-md hover:bg-slate-100"
                              >
                                <RefreshCw className="w-5 h-5 text-green-500" />
                              </button>
                            </div>
                          </div>
                        ))}
                        {selectedContent?.additional_result_urls?.map((url, idx) => (
                          <div key={`add-${idx}`} className="bg-slate-100 rounded-lg overflow-hidden" style={{height: generatedItemPx ? `${generatedItemPx}px` : undefined}}>
                            <MediaWithFallback src={url} alt={`生成结果补充${idx + 1}`} className={`w-full h-full object-contain ${selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === url ? 'ring-2 ring-blue-500' : ''}`} isSelectable isSelected={selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === url} onClick={() => setSelectedVideoSource({ type: 'generated', url })} />
                          </div>
                        ))}
                        {(!selectedContent?.result_images_meta || selectedContent.result_images_meta.length === 0) && selectedContent?.generated_image_urls?.map((url, idx) => (
                          <div key={`flat-${idx}`} className="bg-slate-100 rounded-lg overflow-hidden" style={{height: generatedItemPx ? `${generatedItemPx}px` : undefined}}>
                            <MediaWithFallback src={url} alt={`生成结果${idx + 1}`} className={`w-full h-full object-contain ${selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === url ? 'ring-2 ring-blue-500' : ''}`} isSelectable isSelected={selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === url} onClick={() => setSelectedVideoSource({ type: 'generated', url })} />
                          </div>
                        ))}
                        {/* 本地占位槽位：运行中/完成 */}
                        {tempResultSlots.map((slot) => (
                          <div key={`temp-${slot.id}`} className="relative bg-slate-100 rounded-lg overflow-hidden flex items-center justify-center" style={{height: generatedItemPx ? `${generatedItemPx}px` : undefined}}>
                            {slot.status === 'running' ? (
                              <Loader2 className="w-10 h-10 animate-spin text-blue-500" />
                            ) : (
                              slot.url ? <MediaWithFallback src={slot.url} alt="新生成结果" className={`w-full h-full object-contain ${selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === slot.url ? 'ring-2 ring-blue-500' : ''}`} isSelectable isSelected={selectedVideoSource?.type === 'generated' && selectedVideoSource?.url === slot.url} onClick={() => setSelectedVideoSource({ type: 'generated', url: slot.url })} /> : null
                            )}
                          </div>
                        ))}
                        {/* 新增生成图占位符：生成中时隐藏，仅保留转圈槽位 */}
                        {!isGenerating && (
                          <div className="rounded-lg border-2 border-dashed border-slate-300 hover:border-blue-400 hover:bg-blue-50 transition-colors flex items-center justify-center text-blue-500 bg-white" style={{height: generatedItemPx ? `${generatedItemPx}px` : undefined}}>
                            <button
                              type="button"
                              onClick={handleAddNewResultPlaceholder}
                              className="w-full h-full flex items-center justify-center"
                            >
                              <Plus className="w-10 h-10" />
                            </button>
                          </div>
                        )}
                        </div>
                      </div>
                    ) : (
                      <div className="aspect-square bg-slate-100 rounded-lg overflow-hidden">
                        <div className="w-full h-full flex items-center justify-center">
                          <ImageIcon className="w-12 h-12 text-slate-400" />
                        </div>
                      </div>
                    )}
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>

          {/* 右侧标题文案区域 */}
          <div className="col-span-5">
            <Card>
              <CardHeader>
                <CardTitle className="text-lg">标题文案</CardTitle>
              </CardHeader>
              <CardContent>
                <div className="space-y-4">
                  <div>
                    <Label className="text-sm font-medium text-slate-600 mb-2 block">标题</Label>
                    <Textarea 
                      value={selectedContent?.title || ''} 
                      onChange={(e) => setSelectedContent(prev => ({ ...prev, title: e.target.value }))}
                      placeholder="输入提示词..."
                      className="min-h-[100px]"
                    />
                  </div>
                  <div>
                    <Label className="text-sm font-medium text-slate-600 mb-2 block">文案</Label>
                    <Textarea 
                      value={selectedContent?.content || ''} 
                      onChange={(e) => setSelectedContent(prev => ({ ...prev, content: e.target.value }))}
                      placeholder="输入文案内容..."
                      className="min-h-[200px]"
                    />
                  </div>
                  <div>
                    <Label className="text-sm font-medium text-slate-600 mb-2 block">话题标签</Label>
                    <Textarea 
                      value={selectedContent?.label || ''} 
                      onChange={(e) => setSelectedContent(prev => ({ ...prev, label: e.target.value }))}
                      placeholder="输入话题标签..."
                      className="min-h-[200px]"
                    />
                  </div>
                  {/* 自由提示与场景模板、生成视频 */}
                  <div className="space-y-3 pt-2 border-t">
                    <Label className="text-sm font-medium text-slate-700">自由提示</Label>
                    <Input value={freePrompt} onChange={(e) => setFreePrompt(e.target.value)} placeholder="输入自定义视频生成提示词..." />
                    <div>
                      <div className="flex items-center justify-between mb-2">
                        <Label className="text-sm font-medium text-slate-700">场景模板</Label>
                        <Button variant="outline" size="sm" onClick={() => setSelectedSceneTemplateIds(prev => prev.length === sceneTemplates.length ? [] : sceneTemplates.map(t => t.id))} disabled={sceneTemplates.length === 0}> {selectedSceneTemplateIds.length === sceneTemplates.length && sceneTemplates.length > 0 ? '取消全选' : '全选'} </Button>
                      </div>
                      <div className="max-h-32 overflow-y-auto space-y-2">
                        {sceneTemplates.map(t => (
                          <div key={t.id} className={`p-2 rounded border cursor-pointer ${selectedSceneTemplateIds.includes(t.id) ? 'border-blue-500 bg-blue-50' : 'border-slate-200 hover:border-slate-300'}`} onClick={() => setSelectedSceneTemplateIds(prev => prev.includes(t.id) ? prev.filter(id => id !== t.id) : [...prev, t.id])}>
                            <div className="text-sm font-medium">{t.name}</div>
                            <div className="text-xs text-slate-500 truncate">{t.content}</div>
                          </div>
                        ))}
                        {sceneTemplates.length === 0 && (
                          <div className="text-xs text-slate-400">暂无场景模板</div>
                        )}
                      </div>
                    </div>
                    <div className="flex items-center gap-2">
                      <Button className="bg-purple-600 hover:bg-purple-700" onClick={async () => {
                        try {
                          if (!isAuthenticated || !user?.id) { toast.error('请先登录', { richColors: true }); return; }
                          // 校验提示或模板
                          const hasPrompt = (freePrompt || '').trim().length > 0;
                          const hasScene = selectedSceneTemplateIds.length > 0;
                          if (!hasPrompt && !hasScene) { toast.error('请输入自由提示或选择场景模板', { richColors: true }); return; }
                          // 选择图片：优先使用用户点击选择；未选择则默认参考图片
                          let imageId = null;
                          let selectedImageUrl = null;
                          if (!selectedContent) { toast.error('请先选中一条记录', { richColors: true }); return; }
                          
                          // 根据选择的视频来源确定图片
                          if (selectedVideoSource?.type === 'cloth') {
                            imageId = selectedContent?.cloth_image_id || null;
                            selectedImageUrl = selectedContent?.cloth_image_url || null;
                          } else if (selectedVideoSource?.type === 'generated' && selectedVideoSource?.url) {
                            // 对于生成图片，需要通过URL找到对应的结果图片记录ID
                            selectedImageUrl = selectedVideoSource.url;
                            // 尝试从result_images_meta中找到对应的process_id，然后获取其result_image_id
                            const meta = selectedContent?.result_images_meta?.find(m => m.url === selectedImageUrl);
                            if (meta?.process_id) {
                              try {
                                const processDetail = await aiSwapAPI.getProcessDetail(meta.process_id, user.id);
                                imageId = processDetail?.result_image?.id || null;
                              } catch (e) {
                                console.error('获取生成图片ID失败:', e);
                              }
                            }
                            // 如果还是没找到，尝试通过URL创建临时图片记录
                            if (!imageId) {
                              try {
                                console.log('正在上传生成图片作为临时素材:', selectedImageUrl);
                                imageId = await uploadImageFromUrl(selectedImageUrl, user.id);
                                console.log('临时素材上传成功, ID:', imageId);
                              } catch (uploadError) {
                                console.error('上传临时素材失败:', uploadError);
                                toast.error('无法上传选中的生成图片，请选择原图或服装图片', { richColors: true });
                                return;
                              }
                            }
                          } else {
                            // 默认使用原图（参考图片）
                            imageId = selectedContent?.face_image_id || null;
                            selectedImageUrl = selectedContent?.original_image_url || null;
                          }
                          
                          // 如果仍未拿到，尝试查询该记录详情
                          if (!imageId) {
                            try {
                              const detail = await aiSwapAPI.getProcessDetail(selectedContent.id, user.id);
                              imageId = detail?.process_record?.face_image_id || detail?.process_record?.image_id || null;
                              if (selectedVideoSource?.type === 'cloth') {
                                imageId = detail?.process_record?.cloth_image_id || imageId;
                              }
                            } catch (e) {
                              console.error('获取记录详情失败:', e);
                            }
                          }
                          
                          if (!imageId) { 
                            toast.error('未找到可用的图片ID，请检查选择的图片是否有效', { richColors: true }); 
                            return; 
                          }
                          
                          console.log('选择的图片信息:', {
                            type: selectedVideoSource?.type || 'original',
                            imageId,
                            url: selectedImageUrl
                          });
                          
                          // 组装提示词（多模板则多任务；此处简化为提交首个模板或仅自由提示）
                          const pickedTemplates = sceneTemplates.filter(t => selectedSceneTemplateIds.includes(t.id));
                          const prompts = pickedTemplates.length > 0 ? pickedTemplates.map(t => t.content) : [freePrompt.trim()];
                          let successCount = 0;
                          for (const p of prompts) {
                            const promptText = `图生视频，场景/动作：${p}`;
                            const resp = await aiGenVideoAPI.processGenVideo({ user_id: user.id, image_id: imageId, prompt: promptText, quantity: 1 });
                            if (resp && resp.success) successCount += 1;
                          }
                          toast.success(successCount > 0 ? `已提交${successCount}个视频生成任务` : '未能提交视频任务', { richColors: true });
                        } catch (e) {
                          console.error('生成视频失败:', e);
                          toast.error('生成视频失败：' + (e.message || '未知错误'), { richColors: true });
                        }
                      }}>
                        生成视频
                      </Button>
                      <span className="text-xs text-slate-500">先点击上方图片选择来源（默认使用参考图片，生成图会自动上传为临时素材）</span>
                    </div>
                  </div>
                </div>
              </CardContent>
            </Card>
          </div>
        </div>

        {/* 底部历史记录列表 */}
        <div className="mt-8">
          <div className="bg-white rounded-xl shadow-sm border border-slate-200">
            <div className="p-4 border-b border-slate-200 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
              <h2 className="text-lg font-semibold text-slate-900">所有生成内容 ({allContents.length})</h2>
              <div className="flex flex-col md:flex-row gap-3 w-full md:w-auto">
                <div className="relative md:w-72 w-full">
                  <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400 w-4 h-4" />
                  <Input
                    value={searchTerm}
                    onChange={(e) => setSearchTerm(e.target.value)}
                    placeholder="搜索 标题/文案/标签/创建时间..."
                    className="pl-9"
                  />
                </div>
                <Select value={filterStatus} onValueChange={setFilterStatus}>
                  <SelectTrigger className="md:w-40 w-full"><SelectValue /></SelectTrigger>
                  <SelectContent>
                    <SelectItem value="all">全部状态</SelectItem>
                    <SelectItem value="approved">已审核</SelectItem>
                    <SelectItem value="pending">待审核</SelectItem>
                    <SelectItem value="processing">已发布</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            </div>
            <div className="overflow-x-auto">
              <table className="w-full">
                <thead className="bg-slate-50">
                  <tr>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">任务</th>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">原图</th>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">AI生成图</th>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">标题</th>
                      <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">文案</th>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">状态</th>
                    <th className="px-4 py-3 text-left text-sm font-medium text-slate-600">时间</th>
                  </tr>
                </thead>
                <tbody className="divide-y divide-slate-200">
                  {allContents
                    .filter(item => {
                      const statusOk = filterStatus === 'all' || item.status === filterStatus;
                      if (!statusOk) return false;
                      const q = (searchTerm || '').trim().toLowerCase();
                      if (!q) return true;
                      const createdIso = (() => { try { return new Date(item.completed_at_ts || item.created_date).toISOString().slice(0,10);} catch { return ''; } })();
                      return (
                        (item.title || '').toLowerCase().includes(q) ||
                        (item.content || '').toLowerCase().includes(q) ||
                        (item.label || '').toLowerCase().includes(q) ||
                        (item.created_date || '').toLowerCase().includes(q) ||
                        createdIso.includes(q)
                      );
                    })
                    .map((item) => (
                    <tr
                      key={item.id}
                      className="hover:bg-slate-50 cursor-pointer"
                      onClick={() => handleSelectContent(item)}
                    >
                      <td className="px-4 py-3 text-sm text-slate-600">
                        <div className="flex items-center gap-2">
                          <span>内容审核</span>
                          <Badge variant="outline" className="text-xs">
                            {item.id}
                          </Badge>
                        </div>
                      </td>
                      <td className="px-4 py-3">
                        <div className="w-12 h-12 bg-slate-100 rounded overflow-hidden">
                          {item.original_image_url ? (
                            <MediaWithFallback
                              src={item.original_image_url}
                              alt="原图"
                              className="w-full h-full object-contain"
                            />
                          ) : (
                            <div className="w-full h-full flex items-center justify-center">
                              <ImageIcon className="w-6 h-6 text-slate-400" />
                            </div>
                          )}
                        </div>
                      </td>
                      <td className="px-4 py-3">
                        <div className="flex gap-2">
                          <div className="w-12 h-12 bg-slate-100 rounded overflow-hidden">
                            {item.generated_image_urls?.[0] ? (
                              <MediaWithFallback
                              src={item.generated_image_urls[0]}
                                alt="AI生成图"
                                className="w-full h-full object-contain"
                              />
                            ) : (
                              <div className="w-full h-full flex items-center justify-center">
                                <ImageIcon className="w-6 h-6 text-slate-400" />
                              </div>
                            )}
                          </div>
                          {item.generated_image_urls?.length > 1 && (
                            <div className="w-12 h-12 bg-slate-100 rounded flex items-center justify-center">
                              <span className="text-sm text-slate-600">
                                +{item.generated_image_urls.length - 1}
                              </span>
                            </div>
                          )}
                        </div>
                      </td>
                      <td className="px-4 py-3 text-sm text-slate-600">
                        {item.title || '无标题'}
                      </td>
                      <td className="px-4 py-3 text-sm text-slate-600">
                        <div className="max-w-xs truncate">
                          {item.content || '无文案'}
                        </div>
                      </td>
                      <td className="px-4 py-3">
                        <Badge className={
                          item.status === 'approved' ? 'bg-green-100 text-green-700' :
                          'bg-yellow-100 text-yellow-700'
                        }>
                          {item.status === 'approved' ? '已审核' : '待审核'}
                        </Badge>
                      </td>
                      <td className="px-4 py-3 text-sm text-slate-600">
                        {item.created_date}
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
