
"use client";

import { useState, useEffect, useRef } from "react";
import api from "@/lib/axios";
import {
  getApiBaseUrl,
  resolveMediaUrl,
  resolveAssetUrl,
  resolveBgmUrl,
  getFontFormat,
  buildTextShadow,
  formatDate,
} from "@/lib/media";
import { useTitleSubtitleStyles } from "@/hooks/useTitleSubtitleStyles";
import { useMaterials } from "@/hooks/useMaterials";
import { useRefAudios } from "@/hooks/useRefAudios";
import { useBgm } from "@/hooks/useBgm";
import { useMediaPlayers } from "@/hooks/useMediaPlayers";
import { useGeneratedVideos } from "@/hooks/useGeneratedVideos";
import { useHomePersistence } from "@/hooks/useHomePersistence";
import { useAuth } from "@/contexts/AuthContext";
import { useTask } from "@/contexts/TaskContext";
import VideoPreviewModal from "@/components/VideoPreviewModal";
import ScriptExtractionModal from "@/components/ScriptExtractionModal";
import { HomeHeader } from "@/components/home/HomeHeader";
import { MaterialSelector } from "@/components/home/MaterialSelector";
import { ScriptEditor } from "@/components/home/ScriptEditor";
import { TitleSubtitlePanel } from "@/components/home/TitleSubtitlePanel";
import { VoiceSelector } from "@/components/home/VoiceSelector";
import { RefAudioPanel } from "@/components/home/RefAudioPanel";
import { BgmPanel } from "@/components/home/BgmPanel";
import { GenerateActionBar } from "@/components/home/GenerateActionBar";
import { PreviewPanel } from "@/components/home/PreviewPanel";
import { HistoryList } from "@/components/home/HistoryList";

const API_BASE = getApiBaseUrl();

const VOICES = [
  { id: "zh-CN-YunxiNeural", name: "云溪 (男声-年轻)" },
  { id: "zh-CN-YunjianNeural", name: "云健 (男声-新闻)" },
  { id: "zh-CN-YunyangNeural", name: "云扬 (男声-专业)" },
  { id: "zh-CN-XiaoxiaoNeural", name: "晓晓 (女声-活泼)" },
  { id: "zh-CN-XiaoyiNeural", name: "晓伊 (女声-温柔)" },
];

const FIXED_REF_TEXT = "其实生活中有许多美好的瞬间，比如清晨的阳光，或者一杯温热的清茶。希望这次生成的音色能够自然、流畅，完美还原出我最真实的声音状态。";

const scrollContainerToItem = (container: HTMLDivElement, item: HTMLDivElement) => {
  const containerRect = container.getBoundingClientRect();
  const itemRect = item.getBoundingClientRect();
  const itemTop = itemRect.top - containerRect.top + container.scrollTop;
  const itemBottom = itemTop + itemRect.height;
  const viewTop = container.scrollTop;
  const viewBottom = viewTop + container.clientHeight;

  if (itemTop < viewTop) {
    container.scrollTo({ top: Math.max(itemTop - 8, 0), behavior: 'smooth' });
  } else if (itemBottom > viewBottom) {
    container.scrollTo({ top: itemBottom - container.clientHeight + 8, behavior: 'smooth' });
  }
};

// 类型定义
interface Material {
  id: string;
  name: string;
  scene: string;
  size_mb: number;
  path: string;
}

interface Task {
  task_id: string;
  status: string;
  progress: number;
  message: string;
  download_url?: string;
}

interface GeneratedVideo {
  id: string;
  name: string;
  path: string;
  size_mb: number;
  created_at: number;
}

interface RefAudio {
  id: string;
  name: string;
  path: string;
  ref_text: string;
  duration_sec: number;
  created_at: number;
}





export default function Home() {
  const [selectedMaterial, setSelectedMaterial] = useState<string>("");
  const [previewMaterial, setPreviewMaterial] = useState<string | null>(null);

  const [text, setText] = useState<string>("");
  const [voice, setVoice] = useState<string>("zh-CN-YunxiNeural");

  // 使用全局任务状态
  const { currentTask, isGenerating, startTask } = useTask();

  const [generatedVideo, setGeneratedVideo] = useState<string | null>(null);
  const [selectedVideoId, setSelectedVideoId] = useState<string | null>(null);

  // 字幕和标题相关状态
  const [videoTitle, setVideoTitle] = useState<string>("");
  const [enableSubtitles, setEnableSubtitles] = useState<boolean>(true);
  const [selectedSubtitleStyleId, setSelectedSubtitleStyleId] = useState<string>("");
  const [selectedTitleStyleId, setSelectedTitleStyleId] = useState<string>("");
  const [subtitleFontSize, setSubtitleFontSize] = useState<number>(60);
  const [titleFontSize, setTitleFontSize] = useState<number>(90);
  const [subtitleSizeLocked, setSubtitleSizeLocked] = useState<boolean>(false);
  const [titleSizeLocked, setTitleSizeLocked] = useState<boolean>(false);
  const [showStylePreview, setShowStylePreview] = useState<boolean>(false);
  const [materialDimensions, setMaterialDimensions] = useState<{ width: number; height: number } | null>(null);
  const [previewContainerWidth, setPreviewContainerWidth] = useState<number>(0);

  // 背景音乐相关状态
  const [selectedBgmId, setSelectedBgmId] = useState<string>("");
  const [enableBgm, setEnableBgm] = useState<boolean>(false);
  const [bgmVolume, setBgmVolume] = useState<number>(0.2);

  // 声音克隆相关状态
  const [ttsMode, setTtsMode] = useState<'edgetts' | 'voiceclone'>('edgetts');
  const [selectedRefAudio, setSelectedRefAudio] = useState<RefAudio | null>(null);
  const [refText, setRefText] = useState('其实生活中有许多美好的瞬间，比如清晨的阳光，或者一杯温热的清茶。希望这次生成的音色能够自然、流畅，完美还原出我最真实的声音状态。');

  // 音频预览与重命名状态
  const [editingAudioId, setEditingAudioId] = useState<string | null>(null);
  const [editName, setEditName] = useState("");
  const bgmItemRefs = useRef<Record<string, HTMLDivElement | null>>({});
  const bgmListContainerRef = useRef<HTMLDivElement | null>(null);
  const titlePreviewContainerRef = useRef<HTMLDivElement | null>(null);
  const materialItemRefs = useRef<Record<string, HTMLDivElement | null>>({});
  const videoItemRefs = useRef<Record<string, HTMLDivElement | null>>({});

  // 重命名参考音频
  const startEditing = (audio: RefAudio, e: React.MouseEvent) => {
    e.stopPropagation();
    setEditingAudioId(audio.id);
    // 去掉后缀名进行编辑 (体验更好)
    const nameWithoutExt = audio.name.substring(0, audio.name.lastIndexOf('.'));
    setEditName(nameWithoutExt || audio.name);
  };

  const cancelEditing = (e: React.MouseEvent) => {
    e.stopPropagation();
    setEditingAudioId(null);
    setEditName("");
  };

  const saveEditing = async (audioId: string, e: React.MouseEvent) => {
    e.stopPropagation();
    if (!editName.trim()) return;

    try {
      await api.put(`/api/ref-audios/${encodeURIComponent(audioId)}`, { new_name: editName });
      setEditingAudioId(null);
      fetchRefAudios(); // 刷新列表
    } catch (err: any) {
      alert("重命名失败: " + err);
    }
  };

  // AI 生成标题标签
  const [isGeneratingMeta, setIsGeneratingMeta] = useState(false);

  // 在线录音相关
  const [isRecording, setIsRecording] = useState(false);
  const [recordedBlob, setRecordedBlob] = useState<Blob | null>(null);
  const [recordingTime, setRecordingTime] = useState(0);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const recordingIntervalRef = useRef<NodeJS.Timeout | null>(null);

  // 使用全局认证状态
  const { userId, isLoading: isAuthLoading } = useAuth();

  // 文案提取模态框
  const [extractModalOpen, setExtractModalOpen] = useState(false);



  // 获取存储 key 的前缀（登录用户使用 userId，未登录使用 guest）
  const storageKey = userId || 'guest';

  const {
    materials,
    fetchError,
    isUploading,
    uploadProgress,
    uploadError,
    setUploadError,
    fetchMaterials,
    deleteMaterial,
    handleUpload,
  } = useMaterials({
    selectedMaterial,
    setSelectedMaterial,
  });

  const {
    subtitleStyles,
    titleStyles,
    refreshSubtitleStyles,
    refreshTitleStyles,
  } = useTitleSubtitleStyles({
    isAuthLoading,
    storageKey,
    setSelectedSubtitleStyleId,
    setSelectedTitleStyleId,
  });

  const {
    refAudios,
    isUploadingRef,
    uploadRefError,
    setUploadRefError,
    fetchRefAudios,
    uploadRefAudio,
    deleteRefAudio,
  } = useRefAudios({
    fixedRefText: FIXED_REF_TEXT,
    selectedRefAudio,
    setSelectedRefAudio,
    setRefText,
  });

  const {
    bgmList,
    bgmLoading,
    bgmError,
    fetchBgmList,
  } = useBgm({
    storageKey,
    selectedBgmId,
    setSelectedBgmId,
  });

  const {
    playingAudioId,
    playingBgmId,
    togglePlayPreview,
    toggleBgmPreview,
  } = useMediaPlayers({
    bgmVolume,
    resolveBgmUrl,
    resolveMediaUrl,
    setSelectedBgmId,
    setEnableBgm,
  });

  const {
    generatedVideos,
    fetchGeneratedVideos,
    deleteVideo,
  } = useGeneratedVideos({
    storageKey,
    selectedVideoId,
    setSelectedVideoId,
    setGeneratedVideo,
    resolveMediaUrl,
  });

  const { isRestored } = useHomePersistence({
    isAuthLoading,
    storageKey,
    text,
    setText,
    videoTitle,
    setVideoTitle,
    enableSubtitles,
    setEnableSubtitles,
    ttsMode,
    setTtsMode,
    voice,
    setVoice,
    selectedMaterial,
    setSelectedMaterial,
    selectedSubtitleStyleId,
    setSelectedSubtitleStyleId,
    selectedTitleStyleId,
    setSelectedTitleStyleId,
    subtitleFontSize,
    setSubtitleFontSize,
    titleFontSize,
    setTitleFontSize,
    setSubtitleSizeLocked,
    setTitleSizeLocked,
    selectedBgmId,
    setSelectedBgmId,
    bgmVolume,
    setBgmVolume,
    enableBgm,
    setEnableBgm,
    selectedVideoId,
    setSelectedVideoId,
    selectedRefAudio,
  });

  // 加载素材列表和历史视频
  useEffect(() => {
    if (isAuthLoading) return;
    void Promise.allSettled([
      fetchMaterials(),
      fetchGeneratedVideos(),
      fetchRefAudios(),
      refreshSubtitleStyles(),
      refreshTitleStyles(),
      fetchBgmList(),
    ]);
  }, [isAuthLoading]);

  useEffect(() => {
    const material = materials.find((item) => item.id === selectedMaterial);
    if (!material?.path) {
      setMaterialDimensions(null);
      return;
    }
    const url = resolveMediaUrl(material.path);
    if (!url) {
      setMaterialDimensions(null);
      return;
    }

    let isActive = true;
    const video = document.createElement('video');
    video.crossOrigin = 'anonymous';
    video.preload = 'metadata';
    video.src = url;
    video.load();

    const handleLoaded = () => {
      if (!isActive) return;
      if (video.videoWidth && video.videoHeight) {
        setMaterialDimensions({ width: video.videoWidth, height: video.videoHeight });
      } else {
        setMaterialDimensions(null);
      }
    };

    const handleError = () => {
      if (!isActive) return;
      setMaterialDimensions(null);
    };

    video.addEventListener('loadedmetadata', handleLoaded);
    video.addEventListener('error', handleError);

    return () => {
      isActive = false;
      video.removeEventListener('loadedmetadata', handleLoaded);
      video.removeEventListener('error', handleError);
    };
  }, [selectedMaterial, materials]);

  useEffect(() => {
    if (!showStylePreview) return;
    const container = titlePreviewContainerRef.current;
    if (!container) return;

    const observer = new ResizeObserver((entries) => {
      const entry = entries[0];
      if (entry) {
        setPreviewContainerWidth(entry.contentRect.width);
      }
    });

    observer.observe(container);
    return () => observer.disconnect();
  }, [showStylePreview]);

  useEffect(() => {
    if (typeof window === 'undefined') return;
    if ('scrollRestoration' in window.history) {
      window.history.scrollRestoration = 'manual';
    }
    window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
  }, []);

  // 监听任务完成，自动显示视频
  useEffect(() => {
    if (currentTask?.status === 'completed' && currentTask.download_url) {
      const resolvedUrl = resolveMediaUrl(currentTask.download_url);
      const completedVideoId = currentTask.task_id ? `${currentTask.task_id}_output` : null;
      if (resolvedUrl) {
        setGeneratedVideo(resolvedUrl);
      }
      if (completedVideoId) {
        setSelectedVideoId(completedVideoId);
      }
      fetchGeneratedVideos(completedVideoId || undefined); // 刷新历史视频列表
    }
  }, [currentTask?.status, currentTask?.download_url, currentTask?.task_id, storageKey]);

  useEffect(() => {
    if (subtitleSizeLocked || subtitleStyles.length === 0) return;
    const active = subtitleStyles.find(s => s.id === selectedSubtitleStyleId)
      || subtitleStyles.find(s => s.is_default)
      || subtitleStyles[0];
    if (active?.font_size) {
      setSubtitleFontSize(active.font_size);
    }
  }, [subtitleStyles, selectedSubtitleStyleId, subtitleSizeLocked]);

  useEffect(() => {
    if (titleSizeLocked || titleStyles.length === 0) return;
    const active = titleStyles.find(s => s.id === selectedTitleStyleId)
      || titleStyles.find(s => s.is_default)
      || titleStyles[0];
    if (active?.font_size) {
      setTitleFontSize(active.font_size);
    }
  }, [titleStyles, selectedTitleStyleId, titleSizeLocked]);

  useEffect(() => {
    if (!enableBgm || selectedBgmId || bgmList.length === 0) return;
    const savedBgmId = localStorage.getItem(`vigent_${storageKey}_bgmId`);
    const savedItem = savedBgmId && bgmList.find((item) => item.id === savedBgmId);
    if (savedItem) {
      setSelectedBgmId(savedBgmId);
      return;
    }
    setSelectedBgmId(bgmList[0].id);
  }, [enableBgm, selectedBgmId, bgmList, storageKey]);

  useEffect(() => {
    if (!selectedBgmId) return;
    const container = bgmListContainerRef.current;
    const target = bgmItemRefs.current[selectedBgmId];
    if (container && target) {
      scrollContainerToItem(container, target);
    }
  }, [selectedBgmId, bgmList]);

  useEffect(() => {
    if (!selectedMaterial) return;
    const target = materialItemRefs.current[selectedMaterial];
    if (target) {
      target.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
    }
  }, [selectedMaterial, materials]);

  useEffect(() => {
    if (!selectedVideoId) return;
    const target = videoItemRefs.current[selectedVideoId];
    if (target) {
      target.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
    }
  }, [selectedVideoId, generatedVideos]);

  // 自动选择参考音频 (恢复上次选择 或 默认最新的)
  useEffect(() => {
    // 只有在数据加载完成且尚未选择时才执行
    if (refAudios.length > 0 && !selectedRefAudio && isRestored) {
      const savedId = localStorage.getItem(`vigent_${storageKey}_refAudioId`);
      let targetAudio = null;

      if (savedId) {
        targetAudio = refAudios.find(a => a.id === savedId);
      }

      // 如果没找到保存的，或者没有保存，则默认选第一个(最新的)
      if (!targetAudio) {
        targetAudio = refAudios[0];
      }

      if (targetAudio) {
        console.log("[Home] Auto selecting ref audio:", targetAudio.name);
        setSelectedRefAudio(targetAudio);
        setRefText(targetAudio.ref_text);
      }
    }
  }, [refAudios, isRestored, storageKey]); // 移除 selectedRefAudio 避免循环，但在逻辑中检查 !selectedRefAudio

  // 保存参考音频选择
  useEffect(() => {
    if (isRestored && selectedRefAudio) {
      localStorage.setItem(`vigent_${storageKey}_refAudioId`, selectedRefAudio.id);
    }
  }, [selectedRefAudio, storageKey, isRestored]);

  // 开始录音
  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm' });
      const chunks: BlobPart[] = [];

      mediaRecorder.ondataavailable = (e) => chunks.push(e.data);
      mediaRecorder.onstop = () => {
        const blob = new Blob(chunks, { type: 'audio/webm' });
        setRecordedBlob(blob);
        stream.getTracks().forEach(track => track.stop());
      };

      mediaRecorder.start();
      setIsRecording(true);
      setRecordingTime(0);
      mediaRecorderRef.current = mediaRecorder;

      // 计时器
      recordingIntervalRef.current = setInterval(() => {
        setRecordingTime(prev => prev + 1);
      }, 1000);
    } catch (err) {
      alert('无法访问麦克风，请检查权限设置');
      console.error(err);
    }
  };

  // 停止录音
  const stopRecording = () => {
    mediaRecorderRef.current?.stop();
    setIsRecording(false);
    if (recordingIntervalRef.current) {
      clearInterval(recordingIntervalRef.current);
      recordingIntervalRef.current = null;
    }
  };

  // 使用录音（上传到后端，使用固定参考文字）
  const useRecording = async () => {
    if (!recordedBlob) return;

    // 回归：使用固定文件名，依靠后端自动重命名 (recording(1).webm)
    const filename = 'recording.webm';

    const file = new File([recordedBlob], filename, { type: 'audio/webm' });
    await uploadRefAudio(file);
    setRecordedBlob(null);
    setRecordingTime(0);
  };

  // 格式化录音时长
  const formatRecordingTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${mins}:${secs.toString().padStart(2, '0')}`;
  };

  // AI 生成标题和标签
  const handleGenerateMeta = async () => {
    if (!text.trim()) {
      alert("请先输入口播文案");
      return;
    }

    console.log("[Home] AI生成标题 - userId:", userId, "isRestored:", isRestored);

    setIsGeneratingMeta(true);
    try {
      const { data } = await api.post('/api/ai/generate-meta', { text: text.trim() });

      console.log("[Home] AI生成结果:", data);

      // 更新首页标题
      setVideoTitle(data.title || "");

      // 同步到发布页 localStorage
      console.log("[Home] 保存到 publish localStorage - title:", data.title, "tags:", data.tags);
      localStorage.setItem(`vigent_${storageKey}_publish_title`, data.title || "");
      localStorage.setItem(`vigent_${storageKey}_publish_tags`, JSON.stringify(data.tags || []));

    } catch (err: any) {
      console.error("AI generate meta failed:", err);
      const errorMsg = err.response?.data?.detail || err.message || String(err);
      alert(`AI 生成失败: ${errorMsg}`);
    } finally {
      setIsGeneratingMeta(false);
    }
  };

  // 生成视频
  const handleGenerate = async () => {
    if (!selectedMaterial || !text.trim()) {
      alert("请选择素材并输入文案");
      return;
    }

    // 声音克隆模式校验
    if (ttsMode === 'voiceclone') {
      if (!selectedRefAudio) {
        alert("请选择或上传参考音频");
        return;
      }
    }

    if (enableBgm && !selectedBgmId) {
      alert("请选择背景音乐");
      return;
    }

    setGeneratedVideo(null);

    try {
      // 查找选中的素材对象以获取路径
      const materialObj = materials.find(m => m.id === selectedMaterial);
      if (!materialObj) {
        alert("素材数据异常");
        return;
      }

      // 构建请求参数
      const payload: Record<string, any> = {
        material_path: materialObj.path,
        text: text,
        tts_mode: ttsMode,
        title: videoTitle.trim() || undefined,
        enable_subtitles: enableSubtitles,
      };

      if (enableSubtitles && selectedSubtitleStyleId) {
        payload.subtitle_style_id = selectedSubtitleStyleId;
      }

      if (enableSubtitles && subtitleFontSize) {
        payload.subtitle_font_size = Math.round(subtitleFontSize);
      }

      if (videoTitle.trim() && selectedTitleStyleId) {
        payload.title_style_id = selectedTitleStyleId;
      }

      if (videoTitle.trim() && titleFontSize) {
        payload.title_font_size = Math.round(titleFontSize);
      }

      if (enableBgm && selectedBgmId) {
        payload.bgm_id = selectedBgmId;
        payload.bgm_volume = bgmVolume;
      }

      if (ttsMode === 'edgetts') {
        payload.voice = voice;
      } else {
        payload.ref_audio_id = selectedRefAudio!.id;
        payload.ref_text = refText;
      }

      // 创建生成任务
      const { data } = await api.post('/api/videos/generate', payload);

      const taskId = data.task_id;

      // 保存任务ID到 localStorage，以便页面切换后恢复
      localStorage.setItem(`vigent_${storageKey}_current_task`, taskId);

      // 使用全局 TaskContext 开始任务
      startTask(taskId);
    } catch (error) {
      console.error("生成失败:", error);
    }
  };

  return (
    <div className="min-h-dvh">
      <HomeHeader />

      <main className="max-w-6xl mx-auto px-6 py-8">
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
          {/* 左侧: 输入区域 */}
          <div className="space-y-6">
            {/* 素材选择 */}
            <MaterialSelector
              materials={materials}
              selectedMaterial={selectedMaterial}
              isUploading={isUploading}
              uploadProgress={uploadProgress}
              uploadError={uploadError}
              fetchError={fetchError}
              apiBase={API_BASE}
              onUploadChange={handleUpload}
              onRefresh={fetchMaterials}
              onSelectMaterial={setSelectedMaterial}
              onPreviewMaterial={(path) => {
                setPreviewMaterial(resolveMediaUrl(path));
              }}
              onDeleteMaterial={deleteMaterial}
              onClearUploadError={() => setUploadError(null)}
              registerMaterialRef={(id, el) => {
                materialItemRefs.current[id] = el;
              }}
            />

            {/* 文案输入 */}
            <ScriptEditor
              text={text}
              onChangeText={setText}
              onOpenExtractModal={() => setExtractModalOpen(true)}
              onGenerateMeta={handleGenerateMeta}
              isGeneratingMeta={isGeneratingMeta}
            />

            {/* 标题和字幕设置 */}
            <TitleSubtitlePanel
              showStylePreview={showStylePreview}
              onTogglePreview={() => setShowStylePreview((prev) => !prev)}
              videoTitle={videoTitle}
              onTitleChange={setVideoTitle}
              titleStyles={titleStyles}
              selectedTitleStyleId={selectedTitleStyleId}
              onSelectTitleStyle={setSelectedTitleStyleId}
              titleFontSize={titleFontSize}
              onTitleFontSizeChange={(value) => {
                setTitleFontSize(value);
                setTitleSizeLocked(true);
              }}
              subtitleStyles={subtitleStyles}
              selectedSubtitleStyleId={selectedSubtitleStyleId}
              onSelectSubtitleStyle={setSelectedSubtitleStyleId}
              subtitleFontSize={subtitleFontSize}
              onSubtitleFontSizeChange={(value) => {
                setSubtitleFontSize(value);
                setSubtitleSizeLocked(true);
              }}
              enableSubtitles={enableSubtitles}
              onToggleSubtitles={setEnableSubtitles}
              resolveAssetUrl={resolveAssetUrl}
              getFontFormat={getFontFormat}
              buildTextShadow={buildTextShadow}
              previewScale={previewContainerWidth && (materialDimensions?.width || 1280)
                ? previewContainerWidth / (materialDimensions?.width || 1280)
                : 1}
              previewAspectRatio={materialDimensions
                ? `${materialDimensions.width} / ${materialDimensions.height}`
                : '16 / 9'}
              previewBaseWidth={materialDimensions?.width || 1280}
              previewBaseHeight={materialDimensions?.height || 720}
              previewContainerRef={titlePreviewContainerRef}
            />

            {/* 配音方式选择 */}
            <VoiceSelector
              ttsMode={ttsMode}
              onSelectTtsMode={setTtsMode}
              voices={VOICES}
              voice={voice}
              onSelectVoice={setVoice}
              voiceCloneSlot={(
                <RefAudioPanel
                  refAudios={refAudios}
                  selectedRefAudio={selectedRefAudio}
                  onSelectRefAudio={(audio) => {
                    setSelectedRefAudio(audio);
                    setRefText(audio.ref_text);
                  }}
                  isUploadingRef={isUploadingRef}
                  uploadRefError={uploadRefError}
                  onClearUploadRefError={() => setUploadRefError(null)}
                  onUploadRefAudio={uploadRefAudio}
                  onFetchRefAudios={fetchRefAudios}
                  playingAudioId={playingAudioId}
                  onTogglePlayPreview={togglePlayPreview}
                  editingAudioId={editingAudioId}
                  editName={editName}
                  onEditNameChange={setEditName}
                  onStartEditing={startEditing}
                  onSaveEditing={saveEditing}
                  onCancelEditing={cancelEditing}
                  onDeleteRefAudio={deleteRefAudio}
                  recordedBlob={recordedBlob}
                  isRecording={isRecording}
                  recordingTime={recordingTime}
                  onStartRecording={startRecording}
                  onStopRecording={stopRecording}
                  onUseRecording={useRecording}
                  formatRecordingTime={formatRecordingTime}
                  fixedRefText={FIXED_REF_TEXT}
                />
              )}
            />

            {/* 背景音乐 */}
            <BgmPanel
              bgmList={bgmList}
              bgmLoading={bgmLoading}
              bgmError={bgmError}
              enableBgm={enableBgm}
              onToggleEnable={setEnableBgm}
              onRefresh={fetchBgmList}
              selectedBgmId={selectedBgmId}
              onSelectBgm={setSelectedBgmId}
              playingBgmId={playingBgmId}
              onTogglePreview={toggleBgmPreview}
              bgmVolume={bgmVolume}
              onVolumeChange={setBgmVolume}
              bgmListContainerRef={bgmListContainerRef}
              registerBgmItemRef={(id, el) => {
                bgmItemRefs.current[id] = el;
              }}
            />

            {/* 生成按钮 */}
            <GenerateActionBar
              isGenerating={isGenerating}
              progress={currentTask?.progress || 0}
              disabled={isGenerating || !selectedMaterial || (ttsMode === 'voiceclone' && !selectedRefAudio)}
              onGenerate={handleGenerate}
            />
          </div>

          {/* 右侧: 预览区域 */}
          <div className="space-y-6">
            <PreviewPanel
              currentTask={currentTask}
              isGenerating={isGenerating}
              generatedVideo={generatedVideo}
            />

            <HistoryList
              generatedVideos={generatedVideos}
              selectedVideoId={selectedVideoId}
              onSelectVideo={(video) => {
                setSelectedVideoId(video.id);
                setGeneratedVideo(resolveMediaUrl(video.path));
              }}
              onDeleteVideo={deleteVideo}
              onRefresh={() => fetchGeneratedVideos()}
              registerVideoRef={(id, el) => {
                videoItemRefs.current[id] = el;
              }}
              formatDate={formatDate}
            />
          </div>
        </div>
      </main >
      <VideoPreviewModal
        onClose={() => setPreviewMaterial(null)}
        videoUrl={previewMaterial}
        title="素材预览"
      />

      <ScriptExtractionModal
        isOpen={extractModalOpen}
        onClose={() => setExtractModalOpen(false)}
        onApply={(text) => setText(text)}
      />
    </div >
  );
}
