"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import {
  ArrowRight,
  ArrowUp,
  Clapperboard,
  Copy,
  ExternalLink,
  FileText,
  Folder,
  Image as ImageIcon,
  Layers3,
  Loader2,
  Menu,
  Plus,
  RefreshCw,
  Search,
  Sparkles,
  Upload,
  Wand2,
  X,
  type LucideIcon,
} from "lucide-react"
import { Toaster, toast } from "sonner"
import { MediaAssetTile } from "@/components/media-asset-tile"
import {
  apiAssetUrl,
  createCreativeImageJob,
  deleteGeneratedImage,
  deleteGeneratedVideo,
  generateCreativeCopy,
  generateImage,
  generateStoryboardVideo,
  getJob,
  listJobs,
  type CreativeCopyVariant,
  type GeneratedImage,
  type GeneratedVideo,
  type Job,
  type JobSummary,
} from "@/lib/api"

type CreationMode = "video" | "image" | "copy"
type BusyTask = CreationMode | "job" | null

type ModeConfig = {
  id: CreationMode
  label: string
  short: string
  icon: LucideIcon
  accent: string
  active: string
  placeholder: string
}

type InspirationCard = {
  title: string
  tag: string
  mode: CreationMode
  prompt: string
  tone: string
}

const OUTPUT_MODES: ModeConfig[] = [
  {
    id: "video",
    label: "视频",
    short: "竖屏短片 / 产品动态",
    icon: Clapperboard,
    accent: "text-cyan-200",
    active: "border-cyan-300/60 bg-cyan-300/12 text-cyan-50",
    placeholder: "做一条 15 秒 TikTok 竖屏视频，办公室午休场景，人物戴上 SKG 颈部按摩仪，镜头干净，突出日常放松和产品佩戴清楚。",
  },
  {
    id: "image",
    label: "图片",
    short: "营销图 / 首帧 / 产品场景",
    icon: ImageIcon,
    accent: "text-emerald-200",
    active: "border-emerald-300/60 bg-emerald-300/12 text-emerald-50",
    placeholder: "生成一张 9:16 信息流营销图，SKG 颈部按摩仪佩戴清楚，真实办公室午休场景，画面干净，有高级感。",
  },
  {
    id: "copy",
    label: "图文",
    short: "标题 / 脚本 / caption",
    icon: FileText,
    accent: "text-orange-200",
    active: "border-orange-300/65 bg-orange-300/12 text-orange-50",
    placeholder: "写一组 SKG 颈部按摩仪的营销图文方案，面向久坐办公人群，语气真实直接，有前三秒 hook 和可用于生图/生视频的提示词。",
  },
]

const PROMPT_PRESETS: InspirationCard[] = [
  {
    title: "办公室午休",
    tag: "短视频",
    mode: "video",
    prompt: "做一条 15 秒 TikTok 竖屏视频，办公室午休场景，人物放下电脑后戴上 SKG 颈部按摩仪，镜头缓慢推进，突出日常放松。",
    tone: "from-cyan-500/22 via-slate-900 to-slate-950",
  },
  {
    title: "下班回家放松",
    tag: "短视频",
    mode: "video",
    prompt: "做一条 12 秒竖屏短片，年轻上班族下班回家后放松肩颈，先表现疲惫，再自然戴上 SKG 产品，动作可信。",
    tone: "from-orange-500/22 via-slate-900 to-slate-950",
  },
  {
    title: "白底功能图",
    tag: "图片",
    mode: "image",
    prompt: "生成一张白底产品功能图，高级电商质感，突出 SKG 颈部按摩仪外形、佩戴方式和日常使用，产品结构不能变形。",
    tone: "from-emerald-500/22 via-slate-900 to-slate-950",
  },
  {
    title: "前三秒 Hook",
    tag: "图文",
    mode: "copy",
    prompt: "写 3 套 SKG 颈部按摩仪信息流营销图文方案，每套包含前三秒 hook、中文脚本、caption、图片提示词和视频提示词。",
    tone: "from-fuchsia-500/22 via-slate-900 to-slate-950",
  },
  {
    title: "真实生活方式",
    tag: "图片",
    mode: "image",
    prompt: "生成一张真实生活方式营销图，人物在家中沙发放松，佩戴 SKG 颈部按摩仪，光线自然，产品清晰可见。",
    tone: "from-blue-500/20 via-slate-900 to-slate-950",
  },
]

function cx(...items: Array<string | false | null | undefined>) {
  return items.filter(Boolean).join(" ")
}

function allGeneratedImages(job: Job | null): GeneratedImage[] {
  if (!job) return []
  return job.frames.flatMap((frame) => frame.generated_images ?? []).sort((a, b) => b.created_at - a.created_at)
}

function latestGeneratedImage(job: Job | null): GeneratedImage | null {
  return allGeneratedImages(job)[0] ?? null
}

function latestGeneratedVideo(job: Job | null): GeneratedVideo | null {
  return [...(job?.generated_videos ?? [])].sort((a, b) => b.created_at - a.created_at)[0] ?? null
}

function videoSrc(job: Job, video: GeneratedVideo) {
  return apiAssetUrl(video.url || `/jobs/${job.id}/storyboard-videos/${video.id}.mp4`)
}

function jobTitle(item: Job | JobSummary | null) {
  if (!item) return "未选择任务"
  const raw = item.url.replace(/^creative:\/\//, "").replace(/^upload:\/\//, "")
  return raw || item.id
}

function sourceFrameSrc(job: Job | null) {
  return job?.frames?.[0]?.url ? apiAssetUrl(job.frames[0].url) : ""
}

function statusLabel(status?: string) {
  if (!status) return "就绪"
  const map: Record<string, string> = {
    created: "已创建",
    downloading: "下载中",
    downloaded: "已下载",
    splitting: "拆轨中",
    frames_extracted: "可创作",
    transcribing: "识别中",
    transcribed: "已解析",
    failed: "失败",
  }
  return map[status] ?? status
}

export default function Home() {
  const [mode, setMode] = useState<CreationMode>("video")
  const [prompt, setPrompt] = useState("")
  const [product, setProduct] = useState("SKG 颈部按摩仪")
  const [audience, setAudience] = useState("久坐办公、低头刷手机的人群")
  const [platform, setPlatform] = useState("TikTok / Reels")
  const [tone, setTone] = useState("真实自然、有购买理由")
  const [seconds, setSeconds] = useState(15)
  const [referenceFile, setReferenceFile] = useState<File | null>(null)
  const [referencePreview, setReferencePreview] = useState("")
  const [job, setJob] = useState<Job | null>(null)
  const [busy, setBusy] = useState<BusyTask>(null)
  const [copyVariants, setCopyVariants] = useState<CreativeCopyVariant[]>([])
  const [recentJobs, setRecentJobs] = useState<JobSummary[]>([])
  const [showSettings, setShowSettings] = useState(false)
  const [error, setError] = useState("")
  const fileInputRef = useRef<HTMLInputElement>(null)

  const activeMode = OUTPUT_MODES.find((item) => item.id === mode) ?? OUTPUT_MODES[0]
  const ActiveIcon = activeMode.icon
  const images = useMemo(() => allGeneratedImages(job), [job])
  const latestImage = latestGeneratedImage(job)
  const latestVideo = latestGeneratedVideo(job)
  const runningVideo = (job?.generated_videos ?? []).some((item) => item.status === "queued" || item.status === "in_progress")
  const currentReference = referencePreview || sourceFrameSrc(job)
  const canUseReference = !!referenceFile || !!sourceFrameSrc(job)
  const firstCopy = copyVariants[0]

  const refreshJobs = useCallback(async () => {
    try {
      setRecentJobs(await listJobs(14))
    } catch {
      setRecentJobs([])
    }
  }, [])

  useEffect(() => {
    refreshJobs()
  }, [refreshJobs, job?.id, images.length, job?.generated_videos?.length])

  useEffect(() => {
    if (!referenceFile) {
      setReferencePreview("")
      return
    }
    const url = URL.createObjectURL(referenceFile)
    setReferencePreview(url)
    return () => URL.revokeObjectURL(url)
  }, [referenceFile])

  useEffect(() => {
    if (!job || !runningVideo) return
    const timer = window.setInterval(async () => {
      try {
        setJob(await getJob(job.id))
      } catch {
        window.clearInterval(timer)
      }
    }, 2600)
    return () => window.clearInterval(timer)
  }, [job, runningVideo])

  const ensureJob = useCallback(async () => {
    if (job) return job
    setBusy("job")
    const created = await createCreativeImageJob(referenceFile)
    setJob(created)
    await refreshJobs()
    return created
  }, [job, referenceFile, refreshJobs])

  const onFileChange = (file: File | null) => {
    setReferenceFile(file)
    setJob(null)
    setCopyVariants([])
    setError("")
  }

  const loadJob = async (id: string) => {
    setBusy("job")
    setError("")
    try {
      const loaded = await getJob(id)
      setJob(loaded)
      setReferenceFile(null)
      setCopyVariants([])
    } catch (e) {
      const message = e instanceof Error ? e.message : "读取任务失败"
      setError(message)
      toast.error(message)
    } finally {
      setBusy(null)
    }
  }

  const promptWithContext = () => (
    `${prompt.trim()}\n\nProduct: ${product}. Audience: ${audience}. Platform: ${platform}. Tone: ${tone}. Keep the SKG product shape stable and visible.`
  )

  const validatePrompt = () => {
    if (!prompt.trim()) {
      toast.error("先写一句生成要求")
      return false
    }
    return true
  }

  const runImage = async () => {
    if (!validatePrompt()) return
    setBusy("image")
    setError("")
    try {
      const target = await ensureJob()
      const updated = await generateImage(target.id, 0, {
        prompt: promptWithContext(),
        mode: canUseReference ? "edit" : "text",
      })
      setJob(updated)
      toast.success("图片已生成")
    } catch (e) {
      const message = e instanceof Error ? e.message : "生图失败"
      setError(message)
      toast.error(message)
    } finally {
      setBusy(null)
    }
  }

  const runVideo = async () => {
    if (!validatePrompt()) return
    setBusy("video")
    setError("")
    try {
      const target = await ensureJob()
      const updated = await generateStoryboardVideo(target.id, 0, {
        prompt: promptWithContext(),
        duration: seconds,
        count: 1,
        first_image: { kind: "keyframe", frame_idx: 0 },
        size: "720x1280",
      })
      setJob(updated)
      toast.success("视频已提交")
    } catch (e) {
      const message = e instanceof Error ? e.message : "生视频失败"
      setError(message)
      toast.error(message)
    } finally {
      setBusy(null)
    }
  }

  const runCopy = async () => {
    const goal = prompt.trim() || `${product} ${audience} ${platform}`
    setBusy("copy")
    setError("")
    try {
      const result = await generateCreativeCopy({
        goal,
        product,
        audience,
        platform,
        tone,
        seconds,
      })
      setCopyVariants(result.variants)
      toast.success("图文方案已生成")
    } catch (e) {
      const message = e instanceof Error ? e.message : "写图文失败"
      setError(message)
      toast.error(message)
    } finally {
      setBusy(null)
    }
  }

  const runPrimary = () => {
    if (mode === "image") return runImage()
    if (mode === "copy") return runCopy()
    return runVideo()
  }

  const deleteImage = async (image: GeneratedImage) => {
    if (!job) return
    try {
      setJob(await deleteGeneratedImage(job.id, 0, image.id))
      toast.success("图片已删除")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "删除失败")
    }
  }

  const deleteVideo = async (video: GeneratedVideo) => {
    if (!job) return
    try {
      setJob(await deleteGeneratedVideo(job.id, video.id))
      toast.success("视频已删除")
    } catch (e) {
      toast.error(e instanceof Error ? e.message : "删除失败")
    }
  }

  const copyText = async (text: string) => {
    try {
      await navigator.clipboard.writeText(text)
      toast.success("已复制")
    } catch {
      toast.error("复制失败")
    }
  }

  const useInspiration = (item: InspirationCard) => {
    setMode(item.mode)
    setPrompt(item.prompt)
    setError("")
  }

  const useVariant = (variant: CreativeCopyVariant, nextMode: CreationMode) => {
    setMode(nextMode)
    setPrompt(nextMode === "image" ? variant.image_prompt_en : nextMode === "video" ? variant.video_prompt_en : variant.script_zh)
  }

  return (
    <main className="min-h-screen bg-[#090a0f] text-white">
      <Toaster richColors position="top-center" />
      <div className="grid min-h-screen grid-cols-[78px_minmax(0,1fr)]">
        <aside className="flex min-h-screen flex-col items-center border-r border-white/8 bg-[#0b0c11] px-3 py-6">
          <div className="mb-24 flex h-9 w-9 items-center justify-center rounded-xl bg-cyan-400/15 text-cyan-200 ring-1 ring-cyan-200/20">
            <Sparkles className="h-5 w-5" />
          </div>
          <nav className="grid gap-7 text-[11px] text-white/58">
            <a href="#inspiration" className="group grid justify-items-center gap-1.5 transition hover:text-white">
              <Sparkles className="h-5 w-5 text-white/80 group-hover:text-cyan-200" />
              灵感
            </a>
            <a href="#generate" className="group grid justify-items-center gap-1.5 text-white transition">
              <Wand2 className="h-5 w-5 text-cyan-200" />
              生成
            </a>
            <a href="#assets" className="group grid justify-items-center gap-1.5 transition hover:text-white">
              <Folder className="h-5 w-5 text-white/80 group-hover:text-cyan-200" />
              资产
            </a>
          </nav>
          <div className="mt-auto grid justify-items-center gap-6 text-white/42">
            <a href="/agent/" className="grid justify-items-center gap-1 text-[10px] transition hover:text-white" title="高级复刻">
              <Layers3 className="h-4 w-4" />
              Agent
            </a>
            <button type="button" className="rounded-lg p-2 transition hover:bg-white/8 hover:text-white" aria-label="菜单">
              <Menu className="h-4 w-4" />
            </button>
          </div>
        </aside>

        <section className="min-h-screen overflow-y-auto">
          <header className="flex items-center justify-between px-10 py-6">
            <div className="flex items-center gap-3 text-sm text-white/52">
              <span className="flex h-8 w-8 items-center justify-center rounded-lg bg-white text-xs font-black text-black">SKG</span>
              <span>营销内容工作台</span>
            </div>
            <div className="flex items-center gap-2">
              <a
                href="#assets"
                className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/10 bg-white/[0.04] px-4 text-sm font-semibold text-white/78 transition hover:border-white/20 hover:bg-white/[0.07]"
              >
                最近任务
              </a>
              <a
                href="/agent/"
                className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/10 bg-white/[0.04] px-4 text-sm font-semibold text-white/78 transition hover:border-white/20 hover:bg-white/[0.07]"
              >
                高级复刻
                <ExternalLink className="h-3.5 w-3.5" />
              </a>
            </div>
          </header>

          <div className="mx-auto grid w-full max-w-[1280px] gap-10 px-8 pb-12 pt-4">
            <section id="generate" className="grid justify-items-center gap-8">
              <div className="text-center">
                <h1 className="text-[28px] font-semibold leading-tight tracking-normal text-white sm:text-[34px]">
                  开启你的 <span className="text-cyan-300">SKG 创作模式</span> 即刻生成！
                </h1>
                <p className="mt-3 text-sm text-white/44">上传素材是图生图 / 图生视频，不上传就是文生图 / 文生视频。</p>
              </div>

              <section className="relative w-full max-w-[1010px] rounded-[28px] border border-white/8 bg-[#1b1d24] p-5 shadow-[0_30px_90px_rgba(0,0,0,0.34)]">
                <div className="absolute left-7 top-7 flex h-16 w-12 -rotate-6 items-center justify-center rounded bg-[#2a2d37] text-white/42 shadow-lg">
                  {currentReference ? (
                    <MediaAssetTile
                      src={currentReference}
                      alt="reference"
                      objectFit="cover"
                      previewObjectFit="contain"
                      className="h-full w-full rounded"
                      onDelete={referenceFile ? () => onFileChange(null) : undefined}
                    />
                  ) : (
                    <Plus className="h-5 w-5" />
                  )}
                </div>

                <input
                  ref={fileInputRef}
                  type="file"
                  accept="image/png,image/jpeg,image/webp,video/mp4,video/webm,video/quicktime"
                  className="hidden"
                  onChange={(event) => onFileChange(event.target.files?.[0] ?? null)}
                />

                <div className="min-h-[132px] pl-20">
                  <textarea
                    value={prompt}
                    onChange={(event) => setPrompt(event.target.value)}
                    placeholder={activeMode.placeholder}
                    className="h-32 w-full resize-none bg-transparent pr-4 pt-1 text-base leading-7 text-white outline-none placeholder:text-white/28"
                  />
                </div>

                <div className="flex flex-wrap items-center justify-between gap-3 border-t border-white/8 pt-4">
                  <div className="flex flex-wrap items-center gap-2">
                    {OUTPUT_MODES.map((item) => {
                      const Icon = item.icon
                      const selected = item.id === mode
                      return (
                        <button
                          key={item.id}
                          type="button"
                          onClick={() => setMode(item.id)}
                          className={cx(
                            "inline-flex h-9 items-center gap-2 rounded-xl border px-3 text-sm font-semibold transition focus:outline-none focus:ring-2 focus:ring-cyan-200/25",
                            selected ? item.active : "border-white/8 bg-black/16 text-white/62 hover:border-white/18 hover:bg-white/[0.06] hover:text-white",
                          )}
                        >
                          <Icon className={cx("h-4 w-4", selected ? item.accent : "text-white/44")} />
                          {item.label}
                        </button>
                      )
                    })}
                    <button
                      type="button"
                      onClick={() => fileInputRef.current?.click()}
                      className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/8 bg-black/16 px-3 text-sm font-semibold text-white/62 transition hover:border-white/18 hover:bg-white/[0.06] hover:text-white"
                    >
                      <Upload className="h-4 w-4" />
                      {referenceFile ? referenceFile.name.slice(0, 18) : "上传素材"}
                    </button>
                    {referenceFile ? (
                      <button
                        type="button"
                        onClick={() => onFileChange(null)}
                        className="inline-flex h-9 w-9 items-center justify-center rounded-xl border border-white/8 bg-black/16 text-white/52 transition hover:border-rose-200/30 hover:text-rose-100"
                        aria-label="移除素材"
                        title="移除素材"
                      >
                        <X className="h-4 w-4" />
                      </button>
                    ) : null}
                  </div>

                  <button
                    type="button"
                    onClick={runPrimary}
                    disabled={!!busy}
                    className="inline-flex h-11 w-11 items-center justify-center rounded-full bg-[#3d4252] text-white transition hover:bg-cyan-400 hover:text-black disabled:cursor-not-allowed disabled:opacity-60"
                    aria-label="开始生成"
                    title="开始生成"
                  >
                    {busy === mode || busy === "job" ? <Loader2 className="h-5 w-5 animate-spin" /> : <ArrowUp className="h-5 w-5" />}
                  </button>
                </div>
              </section>

              <div className="grid w-full max-w-[1010px] gap-3 md:grid-cols-[minmax(0,1fr)_auto]">
                <div className="flex flex-wrap gap-2">
                  {PROMPT_PRESETS.slice(0, 4).map((item) => (
                    <button
                      key={item.title}
                      type="button"
                      onClick={() => useInspiration(item)}
                      className="rounded-2xl border border-white/8 bg-white/[0.04] px-4 py-3 text-left text-xs font-semibold text-white/58 transition hover:border-cyan-200/25 hover:bg-white/[0.07] hover:text-white"
                    >
                      {item.title}
                    </button>
                  ))}
                </div>
                <button
                  type="button"
                  onClick={() => setShowSettings((value) => !value)}
                  className="inline-flex h-10 items-center justify-center rounded-2xl border border-white/8 bg-white/[0.04] px-4 text-sm font-semibold text-white/62 transition hover:border-white/18 hover:bg-white/[0.07] hover:text-white"
                >
                  {showSettings ? "收起设置" : "默认设置"}
                </button>
              </div>

              {showSettings ? (
                <section className="grid w-full max-w-[1010px] gap-3 rounded-3xl border border-white/8 bg-white/[0.04] p-4 md:grid-cols-2 lg:grid-cols-5">
                  <label className="grid gap-1.5 lg:col-span-1">
                    <span className="text-xs font-medium text-white/42">产品</span>
                    <input
                      value={product}
                      onChange={(event) => setProduct(event.target.value)}
                      className="h-10 rounded-xl border border-white/10 bg-black/20 px-3 text-sm text-white outline-none focus:border-cyan-200/40"
                    />
                  </label>
                  <label className="grid gap-1.5 lg:col-span-2">
                    <span className="text-xs font-medium text-white/42">人群</span>
                    <input
                      value={audience}
                      onChange={(event) => setAudience(event.target.value)}
                      className="h-10 rounded-xl border border-white/10 bg-black/20 px-3 text-sm text-white outline-none focus:border-cyan-200/40"
                    />
                  </label>
                  <label className="grid gap-1.5">
                    <span className="text-xs font-medium text-white/42">平台</span>
                    <select
                      value={platform}
                      onChange={(event) => setPlatform(event.target.value)}
                      className="h-10 rounded-xl border border-white/10 bg-black/20 px-3 text-sm text-white outline-none focus:border-cyan-200/40"
                    >
                      {["TikTok / Reels", "Amazon", "独立站", "小红书", "抖音"].map((value) => <option key={value}>{value}</option>)}
                    </select>
                  </label>
                  <label className="grid gap-1.5">
                    <span className="text-xs font-medium text-white/42">时长</span>
                    <select
                      value={seconds}
                      onChange={(event) => setSeconds(Number(event.target.value))}
                      className="h-10 rounded-xl border border-white/10 bg-black/20 px-3 text-sm text-white outline-none focus:border-cyan-200/40"
                    >
                      {[8, 12, 15, 20, 30, 45].map((value) => <option key={value} value={value}>{value} 秒</option>)}
                    </select>
                  </label>
                  <label className="grid gap-1.5 md:col-span-2 lg:col-span-5">
                    <span className="text-xs font-medium text-white/42">语气</span>
                    <input
                      value={tone}
                      onChange={(event) => setTone(event.target.value)}
                      className="h-10 rounded-xl border border-white/10 bg-black/20 px-3 text-sm text-white outline-none focus:border-cyan-200/40"
                    />
                  </label>
                </section>
              ) : null}

              {error ? (
                <div className="w-full max-w-[1010px] rounded-2xl border border-rose-300/25 bg-rose-500/10 px-4 py-3 text-sm text-rose-100">{error}</div>
              ) : null}
            </section>

            <section className="grid gap-4">
              <div className="grid gap-3 md:grid-cols-5">
                {recentJobs.slice(0, 5).map((item) => (
                  <button
                    key={item.id}
                    type="button"
                    onClick={() => loadJob(item.id)}
                    className={cx(
                      "grid h-[74px] grid-cols-[68px_minmax(0,1fr)] items-center gap-3 rounded-3xl border bg-white/[0.04] p-2 text-left transition hover:border-cyan-200/24 hover:bg-white/[0.07]",
                      job?.id === item.id ? "border-cyan-200/40" : "border-white/6",
                    )}
                  >
                    <MediaAssetTile
                      src={item.thumbnail ? apiAssetUrl(item.thumbnail) : undefined}
                      alt=""
                      objectFit="cover"
                      className="h-[56px] w-[68px] rounded-2xl"
                      disablePreview={!item.thumbnail}
                    />
                    <span className="min-w-0">
                      <span className="block truncate text-xs font-semibold text-white/74">{jobTitle(item)}</span>
                      <span className="mt-1 block truncate text-[11px] text-white/34">{statusLabel(item.status)} · {item.frame_count} 图源 · {item.video_count} 视频</span>
                    </span>
                  </button>
                ))}
                {!recentJobs.length ? Array.from({ length: 5 }).map((_, index) => (
                  <div key={index} className="h-[74px] rounded-3xl border border-white/6 bg-white/[0.04] p-3">
                    <div className="mb-2 h-4 w-16 rounded bg-white/8" />
                    <div className="h-3 w-24 rounded bg-white/6" />
                  </div>
                )) : null}
              </div>
            </section>

            <section id="assets" className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_360px]">
              <div className="rounded-[28px] border border-white/8 bg-[#14161d] p-4">
                <div className="mb-4 flex items-center justify-between gap-3">
                  <div>
                    <h2 className="text-base font-semibold">当前结果</h2>
                    <p className="mt-1 text-xs text-white/38">{job ? jobTitle(job) : "生成后只展示最新结果，全部内容进详情页整理。"}</p>
                  </div>
                  {job ? (
                    <a
                      href={`/detail/?job=${job.id}`}
                      className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/10 bg-white/[0.04] px-3 text-sm font-semibold text-white/74 transition hover:border-cyan-200/24 hover:bg-white/[0.07]"
                    >
                      详情页
                      <ArrowRight className="h-3.5 w-3.5" />
                    </a>
                  ) : null}
                </div>

                <div className="grid gap-3 md:grid-cols-3">
                  <div className="rounded-3xl border border-white/8 bg-black/18 p-3">
                    <div className="mb-2 flex items-center gap-2 text-xs font-semibold text-white/56">
                      <ImageIcon className="h-3.5 w-3.5" />
                      图片
                    </div>
                    {latestImage ? (
                      <MediaAssetTile
                        src={apiAssetUrl(latestImage.url)}
                        alt="generated image"
                        objectFit="cover"
                        previewObjectFit="contain"
                        className="aspect-[4/5] w-full rounded-2xl"
                        label={latestImage.model}
                        meta={latestImage.mode}
                        onDelete={() => deleteImage(latestImage)}
                      />
                    ) : (
                      <div className="flex aspect-[4/5] items-center justify-center rounded-2xl border border-dashed border-white/10 bg-white/[0.03] text-sm text-white/28">暂无图片</div>
                    )}
                  </div>

                  <div className="rounded-3xl border border-white/8 bg-black/18 p-3">
                    <div className="mb-2 flex items-center gap-2 text-xs font-semibold text-white/56">
                      <Clapperboard className="h-3.5 w-3.5" />
                      视频
                    </div>
                    {latestVideo && job ? (
                      <div className="grid gap-2">
                        <MediaAssetTile
                          kind="video"
                          src={latestVideo.status === "completed" ? videoSrc(job, latestVideo) : undefined}
                          poster={apiAssetUrl(latestVideo.poster_url)}
                          objectFit="cover"
                          previewObjectFit="contain"
                          className="aspect-[4/5] w-full rounded-2xl"
                          label={latestVideo.model}
                          meta={`${latestVideo.status} · ${Math.round(latestVideo.progress)}%`}
                          busy={latestVideo.status === "queued" || latestVideo.status === "in_progress"}
                          onDelete={() => deleteVideo(latestVideo)}
                        />
                        <div className="h-1 overflow-hidden rounded-full bg-white/8">
                          <div className="h-full rounded-full bg-cyan-300" style={{ width: `${Math.max(4, latestVideo.progress)}%` }} />
                        </div>
                      </div>
                    ) : (
                      <div className="flex aspect-[4/5] items-center justify-center rounded-2xl border border-dashed border-white/10 bg-white/[0.03] text-sm text-white/28">暂无视频</div>
                    )}
                  </div>

                  <div className="rounded-3xl border border-white/8 bg-black/18 p-3">
                    <div className="mb-2 flex items-center gap-2 text-xs font-semibold text-white/56">
                      <FileText className="h-3.5 w-3.5" />
                      图文
                    </div>
                    {firstCopy ? (
                      <article className="grid min-h-[320px] content-start gap-3 rounded-2xl border border-white/8 bg-white/[0.04] p-4">
                        <div className="flex items-start justify-between gap-2">
                          <h3 className="text-sm font-semibold text-white">{firstCopy.title || "营销方案"}</h3>
                          <button
                            type="button"
                            onClick={() => copyText([firstCopy.hook_zh, firstCopy.script_zh, firstCopy.caption_zh].filter(Boolean).join("\n\n"))}
                            className="rounded-lg p-1 text-white/42 transition hover:bg-white/8 hover:text-white"
                            aria-label="复制文案"
                            title="复制文案"
                          >
                            <Copy className="h-4 w-4" />
                          </button>
                        </div>
                        <p className="text-sm leading-6 text-white/72">{firstCopy.hook_zh}</p>
                        <p className="line-clamp-[8] whitespace-pre-wrap text-xs leading-5 text-white/44">{firstCopy.script_zh}</p>
                        <div className="mt-auto grid grid-cols-2 gap-2">
                          <button
                            type="button"
                            onClick={() => useVariant(firstCopy, "image")}
                            className="inline-flex h-9 items-center justify-center gap-2 rounded-xl bg-emerald-300/14 text-xs font-semibold text-emerald-100 transition hover:bg-emerald-300/20"
                          >
                            去生图
                          </button>
                          <button
                            type="button"
                            onClick={() => useVariant(firstCopy, "video")}
                            className="inline-flex h-9 items-center justify-center gap-2 rounded-xl bg-cyan-300/14 text-xs font-semibold text-cyan-100 transition hover:bg-cyan-300/20"
                          >
                            去生视频
                          </button>
                        </div>
                      </article>
                    ) : (
                      <div className="flex aspect-[4/5] items-center justify-center rounded-2xl border border-dashed border-white/10 bg-white/[0.03] text-sm text-white/28">暂无图文</div>
                    )}
                  </div>
                </div>
              </div>

              <aside className="rounded-[28px] border border-white/8 bg-[#14161d] p-4">
                <div className="mb-4 flex items-center justify-between">
                  <h2 className="text-base font-semibold">任务资产</h2>
                  <button
                    type="button"
                    onClick={refreshJobs}
                    className="rounded-xl p-2 text-white/42 transition hover:bg-white/8 hover:text-white"
                    aria-label="刷新任务"
                    title="刷新任务"
                  >
                    <RefreshCw className="h-4 w-4" />
                  </button>
                </div>
                <div className="grid max-h-[430px] gap-2 overflow-y-auto pr-1">
                  {recentJobs.length ? recentJobs.map((item) => (
                    <button
                      key={item.id}
                      type="button"
                      onClick={() => loadJob(item.id)}
                      className={cx(
                        "grid grid-cols-[54px_minmax(0,1fr)] gap-3 rounded-2xl border bg-white/[0.04] p-2 text-left transition hover:border-cyan-200/24 hover:bg-white/[0.07]",
                        job?.id === item.id ? "border-cyan-200/38" : "border-white/6",
                      )}
                    >
                      <MediaAssetTile
                        src={item.thumbnail ? apiAssetUrl(item.thumbnail) : undefined}
                        alt=""
                        objectFit="cover"
                        className="aspect-square rounded-xl"
                        disablePreview={!item.thumbnail}
                      />
                      <span className="min-w-0 self-center">
                        <span className="block truncate text-sm font-semibold text-white/76">{jobTitle(item)}</span>
                        <span className="mt-1 block text-xs text-white/34">{statusLabel(item.status)} · {item.frame_count} 图源 · {item.video_count} 视频</span>
                      </span>
                    </button>
                  )) : (
                    <div className="rounded-2xl border border-dashed border-white/10 bg-white/[0.03] px-4 py-8 text-center text-sm text-white/30">暂无任务</div>
                  )}
                </div>
              </aside>
            </section>

            <section id="inspiration" className="grid gap-5">
              <div className="flex flex-wrap items-center justify-between gap-3">
                <div className="flex items-center gap-3">
                  <button type="button" className="rounded-2xl bg-white/10 px-5 py-3 text-sm font-semibold text-white">发现</button>
                  <button type="button" className="rounded-2xl px-4 py-3 text-sm font-semibold text-white/42 transition hover:text-white">短片</button>
                </div>
                <div className="flex h-10 w-full max-w-[330px] items-center gap-2 rounded-xl border border-white/10 bg-black/18 px-3 text-white/42">
                  <Search className="h-4 w-4" />
                  <span className="text-sm">搜索模板、场景、平台</span>
                </div>
              </div>

              <div className="grid auto-rows-[190px] grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
                {PROMPT_PRESETS.map((item, index) => (
                  <button
                    key={item.title}
                    type="button"
                    onClick={() => useInspiration(item)}
                    className={cx(
                      "group relative overflow-hidden rounded-[28px] border border-white/8 bg-gradient-to-br p-5 text-left transition hover:-translate-y-0.5 hover:border-cyan-200/24",
                      item.tone,
                      index === 0 ? "lg:col-span-2 lg:row-span-2" : "",
                    )}
                  >
                    <div className="absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-black/74 to-transparent" />
                    <div className="relative z-10 flex h-full flex-col justify-between">
                      <span className="w-fit rounded-full border border-white/10 bg-black/24 px-3 py-1 text-xs font-semibold text-white/64">{item.tag}</span>
                      <div>
                        <h3 className="text-lg font-semibold text-white">{item.title}</h3>
                        <p className="mt-2 line-clamp-2 text-xs leading-5 text-white/52">{item.prompt}</p>
                      </div>
                    </div>
                  </button>
                ))}
              </div>
            </section>
          </div>
        </section>
      </div>
    </main>
  )
}
