import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useAuth } from "@/_core/hooks/useAuth";
import { trpc } from "@/lib/trpc";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Skeleton } from "@/components/ui/skeleton";
import { Slider } from "@/components/ui/slider";
import { Textarea } from "@/components/ui/textarea";
import { Input } from "@/components/ui/input";
import { toast } from "sonner";
import {
  BarChart3,
  Clock,
  Copy,
  Download,
  FileVideo,
  Play,
  PlayCircle,
  Scissors,
  Sparkles,
  Trash2,
  Video,
  Zap,
} from "lucide-react";
import { useLocation } from "wouter";

type ClipDraft = {
  id: string;
  startSec: number;
  endSec: number;
  label: string;
  notes: string;
  source: "manual" | "suggested";
};

const statusMap: Record<string, { label: string; color: string }> = {
  pending: { label: "待分析", color: "bg-yellow-100 text-yellow-700" },
  analyzing: { label: "分析中", color: "bg-blue-100 text-blue-700" },
  completed: { label: "已完成", color: "bg-green-100 text-green-700" },
  failed: { label: "失败", color: "bg-red-100 text-red-700" },
};

const exerciseTypeMap: Record<string, string> = {
  forehand: "正手挥拍",
  backhand: "反手挥拍",
  serve: "发球",
  volley: "截击",
  footwork: "脚步移动",
  shadow: "影子挥拍",
  wall: "墙壁练习",
  recording: "录制归档",
  live_analysis: "实时分析",
};

function formatSeconds(totalSeconds: number) {
  const seconds = Math.max(0, Math.floor(totalSeconds));
  const minutes = Math.floor(seconds / 60);
  const rest = seconds % 60;
  return `${minutes.toString().padStart(2, "0")}:${rest.toString().padStart(2, "0")}`;
}

function clamp(value: number, min: number, max: number) {
  return Math.max(min, Math.min(max, value));
}

function localStorageKey(videoId: number) {
  return `clip-plan:${videoId}`;
}

function resolveTimelineDurationSec(analysis: any, durationSec: number) {
  if (durationSec > 0) return durationSec;
  if (typeof analysis?.durationSec === "number" && analysis.durationSec > 0) return analysis.durationSec;
  if (typeof analysis?.durationMs === "number" && analysis.durationMs > 0) return analysis.durationMs / 1000;
  if (typeof analysis?.framesAnalyzed === "number" && analysis.framesAnalyzed > 0) {
    return Math.max(5, Math.round((analysis.framesAnalyzed / 30) * 10) / 10);
  }
  return 0;
}

function buildSuggestedClips(analysis: any, durationSec: number) {
  const timelineDurationSec = resolveTimelineDurationSec(analysis, durationSec);
  if (!analysis?.keyMoments || !Array.isArray(analysis.keyMoments) || timelineDurationSec <= 0) {
    return [] as ClipDraft[];
  }

  const framesAnalyzed = Math.max(analysis.framesAnalyzed || 0, 1);
  return analysis.keyMoments.slice(0, 6).map((moment: any, index: number) => {
    const centerSec = clamp(((moment.frame || 0) / framesAnalyzed) * timelineDurationSec, 0, timelineDurationSec);
    const startSec = clamp(centerSec - 1.5, 0, Math.max(0, timelineDurationSec - 0.5));
    const endSec = clamp(centerSec + 2.5, startSec + 0.5, timelineDurationSec);
    return {
      id: `suggested-${index}-${moment.frame || index}`,
      startSec,
      endSec,
      label: moment.description || `建议片段 ${index + 1}`,
      notes: moment.type ? `来源于分析事件：${moment.type}` : "来源于分析关键时刻",
      source: "suggested" as const,
    };
  });
}

function downloadJson(filename: string, data: unknown) {
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: "application/json" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.click();
  URL.revokeObjectURL(url);
}

function downloadText(filename: string, data: string) {
  const blob = new Blob([data], { type: "text/plain;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.click();
  URL.revokeObjectURL(url);
}

function buildClipCueSheet(title: string, clips: ClipDraft[]) {
  return clips.map((clip, index) => (
    `${index + 1}. ${clip.label}\n` +
    `   区间: ${formatSeconds(clip.startSec)} - ${formatSeconds(clip.endSec)}\n` +
    `   时长: ${formatSeconds(Math.max(0, clip.endSec - clip.startSec))}\n` +
    `   来源: ${clip.source === "manual" ? "手动" : "分析建议"}\n` +
    `   备注: ${clip.notes || "无"}`
  )).join("\n\n") + `\n\n视频: ${title}\n导出时间: ${new Date().toLocaleString("zh-CN")}\n`;
}

export default function Videos() {
  useAuth();
  const { data: videos, isLoading } = trpc.video.list.useQuery();
  const { data: analyses } = trpc.analysis.list.useQuery();
  const [, setLocation] = useLocation();

  const previewRef = useRef<HTMLVideoElement>(null);
  const [editorOpen, setEditorOpen] = useState(false);
  const [selectedVideo, setSelectedVideo] = useState<any | null>(null);
  const [videoDurationSec, setVideoDurationSec] = useState(0);
  const [playbackSec, setPlaybackSec] = useState(0);
  const [clipRange, setClipRange] = useState<[number, number]>([0, 5]);
  const [clipLabel, setClipLabel] = useState("");
  const [clipNotes, setClipNotes] = useState("");
  const [clipDrafts, setClipDrafts] = useState<ClipDraft[]>([]);
  const [activePreviewRange, setActivePreviewRange] = useState<[number, number] | null>(null);

  const getAnalysis = useCallback((videoId: number) => {
    return analyses?.find((analysis: any) => analysis.videoId === videoId);
  }, [analyses]);

  const activeAnalysis = selectedVideo ? getAnalysis(selectedVideo.id) : null;
  const timelineDurationSec = useMemo(
    () => resolveTimelineDurationSec(activeAnalysis, videoDurationSec),
    [activeAnalysis, videoDurationSec],
  );
  const suggestedClips = useMemo(
    () => buildSuggestedClips(activeAnalysis, timelineDurationSec),
    [activeAnalysis, timelineDurationSec],
  );

  useEffect(() => {
    if (!editorOpen || timelineDurationSec <= 0) return;
    setClipRange((current) => {
      const start = clamp(current[0] ?? 0, 0, Math.max(0, timelineDurationSec - 0.5));
      const minEnd = clamp(start + 0.5, 0.5, timelineDurationSec);
      const end = clamp(current[1] ?? Math.min(timelineDurationSec, 5), minEnd, timelineDurationSec);
      if (start === current[0] && end === current[1]) {
        return current;
      }
      return [start, end];
    });
  }, [editorOpen, timelineDurationSec]);

  useEffect(() => {
    if (!selectedVideo) return;
    try {
      const saved = localStorage.getItem(localStorageKey(selectedVideo.id));
      if (saved) {
        const parsed = JSON.parse(saved) as ClipDraft[];
        setClipDrafts(parsed);
        return;
      }
    } catch {
      // Ignore corrupted local clip drafts and fall back to suggested clips.
    }
    setClipDrafts(suggestedClips);
  }, [selectedVideo, suggestedClips]);

  useEffect(() => {
    if (!selectedVideo) return;
    localStorage.setItem(localStorageKey(selectedVideo.id), JSON.stringify(clipDrafts));
  }, [clipDrafts, selectedVideo]);

  useEffect(() => {
    const video = previewRef.current;
    if (!video || !activePreviewRange) return;

    const handleTimeUpdate = () => {
      if (video.currentTime >= activePreviewRange[1]) {
        video.currentTime = activePreviewRange[0];
      }
    };

    video.addEventListener("timeupdate", handleTimeUpdate);
    return () => {
      video.removeEventListener("timeupdate", handleTimeUpdate);
    };
  }, [activePreviewRange]);

  const openEditor = useCallback((video: any) => {
    setSelectedVideo(video);
    setEditorOpen(true);
    setVideoDurationSec(0);
    setPlaybackSec(0);
    setClipLabel("");
    setClipNotes("");
    setClipRange([0, 5]);
    setActivePreviewRange(null);
  }, []);

  const addClip = useCallback((source: "manual" | "suggested", preset?: ClipDraft) => {
    const nextStart = preset?.startSec ?? clipRange[0];
    const nextEnd = preset?.endSec ?? clipRange[1];
    const clip: ClipDraft = {
      id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
      startSec: nextStart,
      endSec: nextEnd,
      label: preset?.label || clipLabel || `片段 ${clipDrafts.length + 1}`,
      notes: preset?.notes || clipNotes,
      source,
    };

    setClipDrafts((current) => [...current, clip].sort((a, b) => a.startSec - b.startSec));
    setClipLabel("");
    setClipNotes("");
    toast.success("片段已加入轻剪辑草稿");
  }, [clipDrafts.length, clipLabel, clipNotes, clipRange]);

  const totalClipDurationSec = useMemo(
    () => clipDrafts.reduce((sum, clip) => sum + Math.max(0, clip.endSec - clip.startSec), 0),
    [clipDrafts],
  );

  if (isLoading) {
    return (
      <div className="space-y-4">
        <Skeleton className="h-20 w-full" />
        {[1, 2, 3].map((index) => <Skeleton key={index} className="h-32 w-full" />)}
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <section className="rounded-[28px] border border-border/60 bg-[radial-gradient(circle_at_top_left,_rgba(14,165,233,0.12),_transparent_28%),linear-gradient(180deg,rgba(255,255,255,1),rgba(248,250,252,0.96))] p-5 shadow-sm md:p-6">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
          <div>
            <h1 className="text-2xl font-semibold tracking-tight" data-testid="videos-title">训练视频库</h1>
            <p className="mt-2 max-w-2xl text-sm leading-6 text-muted-foreground">
              集中管理录制归档、上传分析和实时分析视频。桌面端已提供轻剪辑工作台，可按建议片段或手动入点/出点生成剪辑草稿。
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <Button data-testid="videos-upload-button" onClick={() => setLocation("/analysis")} className="gap-2">
              <Video className="h-4 w-4" />
              上传新视频
            </Button>
          </div>
        </div>
      </section>

      {(!videos || videos.length === 0) ? (
        <Card className="border-0 shadow-sm">
          <CardContent className="py-16 text-center">
            <FileVideo className="mx-auto mb-4 h-12 w-12 text-muted-foreground/30" />
            <h3 className="mb-2 text-lg font-semibold">还没有训练视频</h3>
            <p className="mb-4 text-sm text-muted-foreground">上传训练视频后，这里会自动汇总分析结果，并提供轻剪辑入口。</p>
            <Button onClick={() => setLocation("/analysis")} className="gap-2">
              <Video className="h-4 w-4" />
              上传第一个视频
            </Button>
          </CardContent>
        </Card>
      ) : (
        <div className="space-y-3">
          {videos.map((video: any) => {
            const analysis = getAnalysis(video.id);
            const status = statusMap[video.analysisStatus] || statusMap.pending;

            return (
              <Card key={video.id} className="border-0 shadow-sm transition-shadow hover:shadow-md" data-testid="video-card">
                <CardContent className="p-4">
                  <div className="flex items-start gap-4">
                    <div className="flex h-20 w-28 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-black/5">
                      {video.url ? (
                        <video src={video.url} className="h-full w-full object-cover" muted preload="metadata" />
                      ) : (
                        <Play className="h-6 w-6 text-muted-foreground/40" />
                      )}
                    </div>

                    <div className="min-w-0 flex-1">
                      <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
                        <div>
                          <h3 className="truncate text-sm font-medium">{video.title}</h3>
                          <div className="mt-1 flex flex-wrap items-center gap-2">
                            <Badge className={`${status.color} border text-xs`}>{status.label}</Badge>
                            {video.exerciseType ? (
                              <Badge variant="outline" className="text-xs">
                                {exerciseTypeMap[video.exerciseType] || video.exerciseType}
                              </Badge>
                            ) : null}
                            <span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
                              <Clock className="h-3 w-3" />
                              {new Date(video.createdAt).toLocaleDateString("zh-CN")}
                            </span>
                            <span className="text-xs text-muted-foreground">
                              {((video.fileSize || 0) / 1024 / 1024).toFixed(1)}MB
                            </span>
                          </div>
                        </div>
                        <div className="flex flex-wrap gap-2">
                          {video.url ? (
                            <Button variant="outline" size="sm" className="gap-2" onClick={() => window.open(video.url, "_blank", "noopener,noreferrer")}>
                              <PlayCircle className="h-4 w-4" />
                              播放
                            </Button>
                          ) : null}
                          <Button variant="outline" size="sm" className="gap-2" onClick={() => openEditor(video)}>
                            <Scissors className="h-4 w-4" />
                            轻剪辑
                          </Button>
                        </div>
                      </div>

                      {analysis ? (
                        <div className="mt-3 flex flex-wrap items-center gap-4 text-xs">
                          <div className="flex items-center gap-1">
                            <BarChart3 className="h-3 w-3 text-primary" />
                            <span className="font-medium">{Math.round(analysis.overallScore || 0)}分</span>
                          </div>
                          {(analysis.shotCount ?? 0) > 0 ? (
                            <div className="flex items-center gap-1">
                              <Zap className="h-3 w-3 text-orange-500" />
                              <span>{analysis.shotCount} 次击球</span>
                            </div>
                          ) : null}
                          {(analysis.strokeConsistency ?? 0) > 0 ? (
                            <div className="text-muted-foreground">
                              一致性 {Math.round(analysis.strokeConsistency ?? 0)}%
                            </div>
                          ) : null}
                          {Array.isArray(analysis.keyMoments) && analysis.keyMoments.length > 0 ? (
                            <Badge variant="outline" className="gap-1 text-xs">
                              <Sparkles className="h-3 w-3" />
                              {analysis.keyMoments.length} 个建议片段
                            </Badge>
                          ) : null}
                        </div>
                      ) : null}
                    </div>
                  </div>
                </CardContent>
              </Card>
            );
          })}
        </div>
      )}

      <Dialog open={editorOpen} onOpenChange={setEditorOpen}>
        <DialogContent className="max-h-[92vh] max-w-5xl overflow-y-auto">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <Scissors className="h-5 w-5 text-primary" />
              PC 轻剪辑工作台
            </DialogTitle>
            <DialogDescription>
              支持手动设置入点/出点、按分析关键时刻生成建议片段，并把剪辑草稿导出为 JSON。
            </DialogDescription>
          </DialogHeader>

          {selectedVideo ? (
            <div className="grid gap-4 xl:grid-cols-[minmax(0,1.35fr)_minmax(320px,0.9fr)]">
              <section className="space-y-4">
                <div className="overflow-hidden rounded-3xl border border-border/60 bg-black">
                  <video
                    ref={previewRef}
                    src={selectedVideo.url}
                    className="aspect-video w-full object-contain"
                    controls
                    playsInline
                    onLoadedMetadata={(event) => {
                      const duration = event.currentTarget.duration || 0;
                      setVideoDurationSec(duration);
                      setClipRange([0, Math.min(duration, 5)]);
                    }}
                    onTimeUpdate={(event) => setPlaybackSec(event.currentTarget.currentTime || 0)}
                  />
                </div>

                  <Card className="border-0 shadow-sm">
                  <CardHeader className="pb-3">
                    <CardTitle className="text-base">片段设置</CardTitle>
                    <CardDescription>建议先在播放器中定位，再设置入点和出点。</CardDescription>
                  </CardHeader>
                  <CardContent className="space-y-4">
                    <div className="grid gap-3 md:grid-cols-4">
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">草稿片段</div>
                        <div className="mt-2 text-lg font-semibold">{clipDrafts.length}</div>
                      </div>
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">总剪辑时长</div>
                        <div className="mt-2 text-lg font-semibold">{formatSeconds(totalClipDurationSec)}</div>
                      </div>
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">建议片段</div>
                        <div className="mt-2 text-lg font-semibold">{suggestedClips.length}</div>
                      </div>
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">当前区间时长</div>
                        <div className="mt-2 text-lg font-semibold">{formatSeconds(Math.max(0, clipRange[1] - clipRange[0]))}</div>
                      </div>
                    </div>

                    <div className="grid gap-3 md:grid-cols-3">
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">当前播放</div>
                        <div className="mt-2 text-lg font-semibold">{formatSeconds(playbackSec)}</div>
                      </div>
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">入点</div>
                        <div className="mt-2 text-lg font-semibold">{formatSeconds(clipRange[0])}</div>
                      </div>
                      <div className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                        <div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">出点</div>
                        <div className="mt-2 text-lg font-semibold">{formatSeconds(clipRange[1])}</div>
                      </div>
                    </div>

                    {timelineDurationSec > 0 ? (
                      <Slider
                        value={clipRange}
                        min={0}
                        max={timelineDurationSec}
                        step={0.1}
                        onValueChange={(value) => {
                          if (value.length === 2) {
                            setClipRange([value[0] || 0, value[1] || Math.max(0.5, timelineDurationSec)]);
                          }
                        }}
                      />
                    ) : null}

                    <div className="flex flex-wrap gap-2">
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => setClipRange(([_, end]) => [clamp(playbackSec, 0, Math.max(0, end - 0.5)), end])}
                      >
                        设为入点
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => setClipRange(([start]) => [start, clamp(playbackSec, start + 0.5, timelineDurationSec || playbackSec + 0.5)])}
                      >
                        设为出点
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => {
                          if (previewRef.current) previewRef.current.currentTime = clipRange[0];
                        }}
                      >
                        跳到入点
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={async () => {
                          if (!previewRef.current) return;
                          setActivePreviewRange([clipRange[0], clipRange[1]]);
                          previewRef.current.currentTime = clipRange[0];
                          await previewRef.current.play().catch(() => undefined);
                        }}
                      >
                        循环预览当前区间
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => {
                          setActivePreviewRange(null);
                          previewRef.current?.pause();
                        }}
                      >
                        停止循环
                      </Button>
                    </div>

                    <div className="grid gap-3 md:grid-cols-2">
                      <Input
                        value={clipLabel}
                        onChange={(event) => setClipLabel(event.target.value)}
                        placeholder="片段名称，例如：正手节奏稳定段"
                        className="h-11 rounded-2xl"
                      />
                      <Button onClick={() => addClip("manual")} className="h-11 rounded-2xl gap-2">
                        <Scissors className="h-4 w-4" />
                        加入剪辑草稿
                      </Button>
                    </div>
                    <Textarea
                      value={clipNotes}
                      onChange={(event) => setClipNotes(event.target.value)}
                      placeholder="记录这个片段为什么要保留，或后续想怎么讲解"
                      className="min-h-24 rounded-2xl"
                    />
                  </CardContent>
                </Card>
              </section>

              <aside className="space-y-4">
                <Card className="border-0 shadow-sm">
                  <CardHeader className="pb-3">
                    <CardTitle className="text-base">建议片段</CardTitle>
                    <CardDescription>来自视频分析关键时刻，可一键加入剪辑草稿。</CardDescription>
                  </CardHeader>
                  <CardContent className="space-y-3">
                    {suggestedClips.length === 0 ? (
                      <div className="rounded-2xl border border-dashed border-border/60 px-4 py-8 text-center text-sm text-muted-foreground">
                        当前视频暂无自动建议片段。
                      </div>
                    ) : (
                      suggestedClips.map((clip: ClipDraft) => (
                        <div key={clip.id} className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                          <div className="font-medium">{clip.label}</div>
                          <div className="mt-1 text-xs text-muted-foreground">
                            {formatSeconds(clip.startSec)} - {formatSeconds(clip.endSec)}
                          </div>
                          <div className="mt-2 text-sm text-muted-foreground">{clip.notes}</div>
                          <div className="mt-3 flex gap-2">
                            <Button
                              variant="outline"
                              size="sm"
                              onClick={() => {
                                setClipRange([clip.startSec, clip.endSec]);
                                if (previewRef.current) previewRef.current.currentTime = clip.startSec;
                              }}
                            >
                              载入区间
                            </Button>
                            <Button
                              variant="outline"
                              size="sm"
                              onClick={async () => {
                                setActivePreviewRange([clip.startSec, clip.endSec]);
                                if (previewRef.current) {
                                  previewRef.current.currentTime = clip.startSec;
                                  await previewRef.current.play().catch(() => undefined);
                                }
                              }}
                            >
                              循环预览
                            </Button>
                            <Button size="sm" onClick={() => addClip("suggested", clip)}>加入草稿</Button>
                          </div>
                        </div>
                      ))
                    )}
                  </CardContent>
                </Card>

                <Card className="border-0 shadow-sm">
                  <CardHeader className="pb-3">
                    <CardTitle className="text-base">剪辑草稿</CardTitle>
                    <CardDescription>草稿保存在浏览器本地，可随时导出给后续后台剪辑任务使用。</CardDescription>
                  </CardHeader>
                  <CardContent className="space-y-3">
                    {clipDrafts.length === 0 ? (
                      <div className="rounded-2xl border border-dashed border-border/60 px-4 py-8 text-center text-sm text-muted-foreground">
                        还没有片段草稿。
                      </div>
                    ) : (
                      clipDrafts.map((clip: ClipDraft) => (
                        <div key={clip.id} className="rounded-2xl border border-border/60 bg-muted/20 p-4">
                          <div className="flex items-start justify-between gap-3">
                            <div>
                              <div className="flex items-center gap-2">
                                <span className="font-medium">{clip.label}</span>
                                <Badge variant="outline">{clip.source === "manual" ? "手动" : "建议"}</Badge>
                                <Badge variant="secondary">{formatSeconds(Math.max(0, clip.endSec - clip.startSec))}</Badge>
                              </div>
                              <div className="mt-1 text-xs text-muted-foreground">
                                {formatSeconds(clip.startSec)} - {formatSeconds(clip.endSec)}
                              </div>
                            </div>
                            <div className="flex items-center gap-1">
                              <Button
                                variant="ghost"
                                size="icon"
                                onClick={() => {
                                  setClipRange([clip.startSec, clip.endSec]);
                                  setClipLabel(clip.label);
                                  setClipNotes(clip.notes);
                                  if (previewRef.current) {
                                    previewRef.current.currentTime = clip.startSec;
                                  }
                                }}
                              >
                                <Play className="h-4 w-4" />
                              </Button>
                              <Button
                                variant="ghost"
                                size="icon"
                                onClick={() => {
                                  const value = `${clip.label} ${formatSeconds(clip.startSec)}-${formatSeconds(clip.endSec)} ${clip.notes || ""}`.trim();
                                  if (!navigator.clipboard) {
                                    toast.error("当前浏览器不支持剪贴板复制");
                                    return;
                                  }
                                  void navigator.clipboard.writeText(value).then(
                                    () => toast.success("片段信息已复制"),
                                    () => toast.error("片段复制失败"),
                                  );
                                }}
                              >
                                <Copy className="h-4 w-4" />
                              </Button>
                              <Button
                                variant="ghost"
                                size="icon"
                                onClick={() => setClipDrafts((current) => current.filter((item) => item.id !== clip.id))}
                              >
                                <Trash2 className="h-4 w-4" />
                              </Button>
                            </div>
                          </div>
                          {clip.notes ? <div className="mt-2 text-sm text-muted-foreground">{clip.notes}</div> : null}
                        </div>
                      ))
                    )}
                  </CardContent>
                </Card>
              </aside>
            </div>
          ) : null}

          <DialogFooter className="flex gap-2">
            <Button
              variant="outline"
              onClick={() => {
                if (!selectedVideo) return;
                const payload = {
                  videoId: selectedVideo.id,
                  title: selectedVideo.title,
                  url: selectedVideo.url,
                  clipDrafts,
                  exportedAt: new Date().toISOString(),
                };
                downloadJson(`${selectedVideo.title}-clip-plan.json`, payload);
              }}
              className="gap-2"
            >
              <Download className="h-4 w-4" />
              导出草稿
            </Button>
            <Button
              variant="outline"
              onClick={() => {
                if (!selectedVideo) return;
                downloadText(`${selectedVideo.title}-clip-cuesheet.txt`, buildClipCueSheet(selectedVideo.title, clipDrafts));
              }}
              className="gap-2"
            >
              <Download className="h-4 w-4" />
              导出清单
            </Button>
            <Button variant="outline" onClick={() => setEditorOpen(false)}>关闭</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
