"use client"
import { useEffect, useState, useRef } from "react"
import { X, Loader2, Check, Wand2, GripHorizontal } from "lucide-react"
import {
  type Job, type StoryboardScene, type ImageRef,
  updateStoryboard, resolveImageRefUrl, uploadStoryboardAsset,
} from "@/lib/api"
import { ProductLibraryPicker } from "@/components/product-library-picker"
import { toast } from "sonner"

interface Props {
  job: Job | null
  selectedFrames: Set<number>
  open: boolean
  onClose: () => void
  onJobUpdate?: (j: Job) => void
  clipboard: ImageRef | null  // 全局剪贴板（page.tsx 提供）
  focusedFrame: number | null
  onGenerateVideo?: (frameIdx: number, scene: StoryboardScene, model: string) => Promise<void> | void
}

const emptyScene = (): StoryboardScene => ({
  subject: "", product: "", scene: "", action: "", duration: 0, reference_ids: [],
})

const VIDEO_MODELS = [
  { value: "seedance", label: "Seedance" },
  { value: "kling", label: "Kling" },
  { value: "veo3", label: "Veo / Voe" },
] as const

export function StoryboardWorkbench({ job, selectedFrames, open, onClose, onJobUpdate, clipboard, focusedFrame, onGenerateVideo }: Props) {
  const [mounted, setMounted] = useState(false)
  useEffect(() => setMounted(true), [])

  const [focusedIdx, setFocusedIdx] = useState<number | null>(null)
  const [form, setForm] = useState<StoryboardScene>(emptyScene())
  const [saving, setSaving] = useState(false)
  const [savedTick, setSavedTick] = useState(0)
  const [panelHeight, setPanelHeight] = useState(320)
  const [videoModel, setVideoModel] = useState<(typeof VIDEO_MODELS)[number]["value"]>("seedance")
  const [generating, setGenerating] = useState(false)
  const saveTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
  const loadedFormKey = useRef("")
  const productFileInput = useRef<HTMLInputElement | null>(null)

  // Esc 关闭
  useEffect(() => {
    if (!open) return
    const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose() }
    window.addEventListener("keydown", onKey)
    return () => window.removeEventListener("keydown", onKey)
  }, [open, onClose])

  // 外部点击某个分镜 / 元素时，直接定位到那一帧。
  useEffect(() => {
    if (!open || !job || focusedFrame === null) return
    if (!selectedFrames.has(focusedFrame)) return
    if (!job.frames.some((f) => f.index === focusedFrame)) return
    setFocusedIdx(focusedFrame)
  }, [open, job?.id, job?.frames, selectedFrames, focusedFrame])

  // 默认选第一个分镜
  useEffect(() => {
    if (!open || !job) return
    if (focusedIdx !== null && job.frames.find((f) => f.index === focusedIdx)) return
    const frames = job.frames
      .filter((f) => selectedFrames.has(f.index))
      .sort((a, b) => a.timestamp - b.timestamp)
    if (frames.length > 0) setFocusedIdx(frames[0].index)
    else setFocusedIdx(null)
  }, [open, job?.id, selectedFrames, focusedIdx, job?.frames])

  // 切换 focused 时加载表单数据。不要在每次 job 轮询/保存回包时重灌，
  // 否则用户刚粘贴到尾帧，外部旧 job 刷新会把本地表单闪回去。
  useEffect(() => {
    if (!job || focusedIdx === null) {
      loadedFormKey.current = ""
      setForm(emptyScene())
      return
    }
    const key = `${job.id}:${focusedIdx}`
    if (loadedFormKey.current === key) return
    const f = job.frames.find((x) => x.index === focusedIdx)
    setForm(f?.storyboard ? { ...emptyScene(), ...f.storyboard } : emptyScene())
    loadedFormKey.current = key
  }, [focusedIdx, job?.id])

  if (!mounted || !open || !job) return null

  const frames = job.frames
    .filter((f) => selectedFrames.has(f.index))
    .sort((a, b) => a.timestamp - b.timestamp)
  const focusFrame = focusedIdx !== null ? job.frames.find((f) => f.index === focusedIdx) ?? null : null
  const focusSeq = focusFrame ? frames.findIndex((f) => f.index === focusFrame.index) + 1 : 0
  const defaultFirstRef: ImageRef | null = focusFrame
    ? { kind: "keyframe", frame_idx: focusFrame.index, label: `分镜 ${focusSeq || focusFrame.index + 1} 首帧` }
    : null
  const nextFrame = focusFrame ? frames.find((f) => f.timestamp > focusFrame.timestamp) ?? null : null
  const defaultLastRef: ImageRef | null = nextFrame
    ? { kind: "keyframe", frame_idx: nextFrame.index, label: `分镜 ${frames.findIndex((f) => f.index === nextFrame.index) + 1} 尾帧` }
    : null

  const queueSave = (next: StoryboardScene) => {
    setForm(next)
    if (!job || focusedIdx === null) return
    if (saveTimer.current) clearTimeout(saveTimer.current)
    saveTimer.current = setTimeout(async () => {
      setSaving(true)
      try {
        const updated = await updateStoryboard(job.id, focusedIdx, next)
        onJobUpdate?.(updated)
        setSavedTick((t) => t + 1)
      } catch (e) {
        toast.error("保存失败：" + (e instanceof Error ? e.message : String(e)))
      } finally {
        setSaving(false)
      }
    }, 600)
  }

  const clampPanelHeight = (height: number) => {
    const max = typeof window === "undefined" ? 680 : Math.max(300, window.innerHeight - 190)
    return Math.max(180, Math.min(max, Math.round(height)))
  }

  const startResize = (e: React.PointerEvent) => {
    e.preventDefault()
    e.stopPropagation()
    const startY = e.clientY
    const startHeight = panelHeight
    const onMove = (ev: PointerEvent) => {
      setPanelHeight(clampPanelHeight(startHeight + ev.clientY - startY))
    }
    const onUp = () => {
      window.removeEventListener("pointermove", onMove)
      window.removeEventListener("pointerup", onUp)
    }
    window.addEventListener("pointermove", onMove)
    window.addEventListener("pointerup", onUp)
  }

  const currentModelLabel = VIDEO_MODELS.find((m) => m.value === videoModel)?.label ?? "Seedance"
  const productRefs = form.product_images?.length ? form.product_images : form.product_image ? [form.product_image] : []
  const setProductRefs = (refs: ImageRef[]) => {
    const next = refs.slice(0, 6)
    queueSave({ ...form, product_image: next[0] ?? null, product_images: next })
  }
  const addProductRef = (ref: ImageRef) => {
    if (productRefs.length >= 6) {
      toast.error("最多添加 6 张产品参考")
      return
    }
    setProductRefs([...productRefs, ref])
  }
  const addProductFiles = async (files: FileList | File[]) => {
    if (!job) return
    const room = 6 - productRefs.length
    if (room <= 0) {
      toast.error("最多添加 6 张产品参考")
      return
    }
    const imageFiles = Array.from(files).filter((file) => file.type.startsWith("image/")).slice(0, room)
    if (imageFiles.length === 0) {
      toast.error("请上传图片文件")
      return
    }
    try {
      const uploaded = await Promise.all(imageFiles.map((file) => uploadStoryboardAsset(job.id, file)))
      setProductRefs([...productRefs, ...uploaded])
      toast.success(`已上传 ${uploaded.length} 张产品参考`)
    } catch (e) {
      toast.error("产品图上传失败：" + (e instanceof Error ? e.message : String(e)))
    }
  }

  return (
    <div
      className="relative z-20 flex-shrink-0 border-t border-white/5 border-b border-white/10 bg-black/70 backdrop-blur-xl shadow-2xl"
      style={{ height: panelHeight, animation: "drawer-in 0.2s cubic-bezier(0.32, 0.72, 0, 1)" }}
    >
      <div className="h-full overflow-y-auto pb-4">
        {!focusFrame ? (
          <div className="px-4 py-5 text-[12px] text-white/40">在上方选择一个分镜开始编排</div>
        ) : (
          <div className="max-w-6xl mx-auto px-4 py-4 space-y-4">
              {/* 顶栏：分镜信息 + 剪贴板提示 + 时长 */}
              <div className="flex items-center justify-between gap-4">
                <div className="text-[15.5px] font-semibold text-white">
                  分镜 {focusSeq}
                  <span className="text-white/40 text-[12px] font-mono ml-2">{focusFrame.timestamp.toFixed(2)}s</span>
                </div>
                <div className="flex items-center gap-3">
                  {clipboard ? (
                    <div className="text-[11px] text-emerald-300 inline-flex items-center gap-1">
                      📋 剪贴板：<span className="text-white font-medium truncate max-w-[180px]">{clipboard.label || (clipboard.kind === "keyframe" ? "关键帧" : "元素")}</span>
                    </div>
                  ) : (
                    <div className="text-[11px] text-white/40">剪贴板为空 · 在 DAG / lightbox 上点 📋 复制</div>
                  )}
                  <label className="inline-flex items-center gap-1.5 text-[11px] text-white/55">
                    时长
                    <input
                      type="number"
                      step="0.1"
                      min="0"
                      value={form.duration || ""}
                      onChange={(e) => queueSave({ ...form, duration: parseFloat(e.target.value) || 0 })}
                      placeholder="3.5"
                      className="w-16 text-[12.5px] px-2 py-1 rounded-md bg-black/40 border border-white/15 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40 focus:border-violet-400/40 text-center"
                    />
                    秒
                  </label>
                  <span className="text-[11px] text-white/45 font-mono inline-flex items-center gap-1">
                    {saving ? (<><Loader2 className="h-2.5 w-2.5 animate-spin" /> 保存中</>)
                      : savedTick > 0 ? (<><Check className="h-2.5 w-2.5 text-emerald-300" /> 已保存</>)
                      : "自动保存"}
                  </span>
                  <button
                    onClick={onClose}
                    className="h-7 px-2.5 rounded-md bg-white/10 hover:bg-white/20 text-white inline-flex items-center gap-1 text-[11.5px]"
                    title="收起编排 (Esc)"
                  >
                    <X className="h-3 w-3" /> 收起
                  </button>
                </div>
              </div>

              {/* 首尾帧：图片直接参与视频生成 */}
              <div className="grid grid-cols-2 gap-4">
                {([
                  { key: "first_image" as const, label: "首帧", placeholder: "默认当前分镜关键帧" },
                  { key: "last_image" as const, label: "尾帧", placeholder: defaultLastRef ? "默认下一张已选分镜" : "粘贴一张结束画面" },
                ]).map(({ key, label, placeholder }) => {
                  const fallback = key === "first_image" ? defaultFirstRef : key === "last_image" ? defaultLastRef : null
                  const ref = form[key] ?? fallback
                  const url = ref ? resolveImageRefUrl(job.id, ref) : ""
                  return (
                    <div key={key} className="rounded-lg bg-white/[0.04] border border-white/10 p-2.5">
                      <div className="text-[12px] text-white font-semibold mb-2 flex items-center justify-between">
                        <span>{label}</span>
                        {form[key] && (
                          <button
                            onClick={() => queueSave({ ...form, [key]: null })}
                            className="text-[10px] text-white/40 hover:text-rose-300"
                            title="清空"
                          >
                            ✕ 清空
                          </button>
                        )}
                      </div>
                      <div
                        className="relative rounded-md overflow-hidden border-2 border-dashed border-white/15 bg-white/[0.03] flex items-center justify-center mb-2"
                        style={{ aspectRatio: "1/1" }}
                      >
                        {ref && url ? (
                          <img src={url} alt={label} className="absolute inset-0 w-full h-full object-contain bg-white" />
                        ) : (
                          <div className="text-center text-white/30 text-[10.5px] p-3 leading-relaxed">
                            空 · 点下方<br />「粘贴剪贴板」<br />填入图片
                          </div>
                        )}
                      </div>
                      <button
                        onClick={() => {
                          if (!clipboard) {
                            toast.error("先在某张图上点 📋 复制")
                            return
                          }
                          queueSave({ ...form, [key]: clipboard })
                          toast.success(`已粘贴到「${label}」`)
                        }}
                        disabled={!clipboard}
                        className={`w-full text-[11.5px] py-1.5 rounded-md inline-flex items-center justify-center gap-1 transition font-medium ${
                          clipboard
                            ? "bg-violet-500 hover:bg-violet-400 text-white"
                            : "bg-white/[0.04] text-white/30 cursor-not-allowed"
                        }`}
                        title={clipboard ? `粘贴剪贴板的图：${clipboard.label || ""}` : "剪贴板为空"}
                      >
                        📋 粘贴
                      </button>
                      <div className="mt-1 text-[9.5px] text-white/30 truncate text-center">
                        {ref?.label || placeholder}
                      </div>
                    </div>
                  )
                })}
              </div>
              <div className="rounded-md border border-violet-300/20 bg-violet-500/10 px-3 py-2 text-[11px] leading-relaxed text-violet-100/75">
                现在按首尾帧出片：首帧默认当前分镜，尾帧默认下一张已选分镜；产品参考组用于锁定 SKG 外观。
              </div>

              <section className="rounded-lg bg-white/[0.04] border border-white/10 p-2.5">
                <div className="mb-2 flex items-center justify-between gap-2">
                  <div className="text-[12px] text-white font-semibold">
                    SKG 产品参考
                    <span className="ml-1.5 text-[10px] font-mono text-white/35">{productRefs.length}/6</span>
                  </div>
                  <button
                    onClick={() => {
                      if (!clipboard) {
                        toast.error("先在产品图、关键帧或生成图上点 📋 复制")
                        return
                      }
                      if (productRefs.length >= 6) {
                        toast.error("最多添加 6 张产品参考")
                        return
                      }
                      addProductRef(clipboard)
                      toast.success("已添加产品参考")
                    }}
                    disabled={!clipboard || productRefs.length >= 6}
                    className={`rounded px-2 py-1 text-[10.5px] font-medium transition ${
                      clipboard && productRefs.length < 6
                        ? "bg-violet-500 text-white hover:bg-violet-400"
                        : "bg-white/[0.04] text-white/30 cursor-not-allowed"
                    }`}
                    title={clipboard ? "把剪贴板图片添加到产品参考组" : "剪贴板为空"}
                  >
                    📋 添加产品角度
                  </button>
                  <button
                    onClick={() => productFileInput.current?.click()}
                    disabled={productRefs.length >= 6}
                    className={`rounded px-2 py-1 text-[10.5px] font-medium transition ${
                      productRefs.length < 6
                        ? "bg-white/10 text-white/80 hover:bg-white/20 hover:text-white"
                        : "bg-white/[0.04] text-white/30 cursor-not-allowed"
                    }`}
                    title="从本地上传产品图"
                  >
                    上传产品图
                  </button>
                  <input
                    ref={productFileInput}
                    type="file"
                    accept="image/*"
                    multiple
                    className="hidden"
                    onChange={(e) => {
                      const files = e.target.files
                      if (files) void addProductFiles(files)
                      e.currentTarget.value = ""
                    }}
                  />
                </div>
                <div
                  onDragOver={(e) => {
                    e.preventDefault()
                    e.dataTransfer.dropEffect = productRefs.length < 6 ? "copy" : "none"
                  }}
                  onDrop={(e) => {
                    e.preventDefault()
                    if (e.dataTransfer.files?.length) void addProductFiles(e.dataTransfer.files)
                  }}
                >
                {productRefs.length === 0 ? (
                  <div className="rounded-md border border-dashed border-white/15 bg-black/25 px-3 py-4 text-center text-[11px] text-white/30">
                    可添加同一 SKG 产品的不同角度，最多 6 张
                  </div>
                ) : (
                  <div className="grid grid-cols-6 gap-2">
                    {productRefs.map((ref, i) => {
                      const url = resolveImageRefUrl(job.id, ref)
                      return (
                        <div key={`${ref.kind}-${ref.frame_idx}-${ref.element_id ?? ""}-${ref.cutout_id ?? ""}-${i}`} className="relative overflow-hidden rounded-md border border-white/10 bg-white" style={{ aspectRatio: "1/1" }}>
                          {url && <img src={url} alt={`产品参考 ${i + 1}`} className="absolute inset-0 h-full w-full object-contain" />}
                          <div className="absolute left-0 top-0 rounded-br bg-black/70 px-1 text-[9px] font-mono text-white">#{i + 1}</div>
                          <button
                            onClick={() => setProductRefs(productRefs.filter((_, idx) => idx !== i))}
                            className="absolute right-0 top-0 rounded-bl bg-rose-500/85 px-1 text-[10px] text-white hover:bg-rose-400"
                            title="移除这张产品参考"
                          >
                            ×
                          </button>
                        </div>
                      )
                    })}
                  </div>
                )}
                </div>
              </section>

              <ProductLibraryPicker
                jobId={job.id}
                compact
                buttonLabel="加入"
                title="产品融合 · SKG 白底图库"
                disabled={productRefs.length >= 6}
                onPick={(ref) => addProductRef(ref)}
              />

              {/* 改造 brief：明确“借鉴参考 → 变成 SKG 产品视频”，避免直接复刻 */}
              <section className="rounded-lg bg-white/[0.035] border border-white/10 p-3">
                <div className="text-[12.5px] font-semibold text-white mb-2">
                  改造目标
                  <span className="ml-2 text-[10px] font-normal text-white/35">
                    图片只是参考，生成时按这里把元素替换成 SKG 产品语境
                  </span>
                </div>
                <div className="grid grid-cols-2 gap-3">
                  <FieldTextarea
                    label="主体怎么改"
                    value={form.subject || ""}
                    onChange={(v) => queueSave({ ...form, subject: v })}
                    placeholder="例：保留手部拿取动作，但人物改为更干净的产品演示模特"
                    rows={2}
                  />
                  <FieldTextarea
                    label="产品怎么替换"
                    value={form.product || ""}
                    onChange={(v) => queueSave({ ...form, product: v })}
                    placeholder="例：把原视频里的瓶子 / 糖果替换成 SKG 颈椎按摩仪，突出佩戴形态"
                    rows={2}
                  />
                  <FieldTextarea
                    label="场景怎么借鉴"
                    value={form.scene || ""}
                    onChange={(v) => queueSave({ ...form, scene: v })}
                    placeholder="例：借鉴药店货架的可信感，但换成现代家居 / 办公桌场景"
                    rows={2}
                  />
                  <FieldTextarea
                    label="动作和镜头"
                    value={form.action || ""}
                    onChange={(v) => queueSave({ ...form, action: v })}
                    placeholder="例：缓慢推近，展示佩戴、按键、表情放松，镜头节奏参考原视频"
                    rows={2}
                  />
                </div>
              </section>

              {/* 快速生成：直接调用生视频 API，结果显示到 Video Gen 节点 */}
              <section>
                <div className="mb-2 flex items-center justify-between gap-3">
                  <div className="text-[12.5px] font-semibold text-white">生成视频</div>
                  <div className="flex items-center gap-1 rounded-md border border-white/10 bg-black/35 p-0.5">
                    {VIDEO_MODELS.map((m) => (
                      <button
                        key={m.value}
                        type="button"
                        onClick={() => setVideoModel(m.value)}
                        className={`h-6 rounded px-2 text-[10.5px] transition ${
                          videoModel === m.value
                            ? "bg-violet-500 text-white shadow"
                            : "text-white/50 hover:bg-white/10 hover:text-white"
                        }`}
                        title={`使用 ${m.label} 生成视频`}
                      >
                        {m.label}
                      </button>
                    ))}
                  </div>
                </div>
                <button
                  disabled={focusedIdx === null || generating}
                  onClick={async () => {
                    if (focusedIdx === null) return
                    queueSave(form)
                    setGenerating(true)
                    try {
                      await onGenerateVideo?.(focusedIdx, form, videoModel)
                    } finally {
                      setGenerating(false)
                    }
                  }}
                  className="w-full py-3 rounded-lg text-[13.5px] font-semibold inline-flex items-center justify-center gap-2 bg-gradient-to-r from-rose-500 to-violet-500 text-white border border-violet-300/40 shadow-lg shadow-violet-500/20 hover:from-rose-400 hover:to-violet-400 disabled:opacity-40 disabled:cursor-not-allowed"
                  title={`用首帧和尾帧调用 ${currentModelLabel} 生视频 API`}
                >
                  {generating ? <Loader2 className="h-4 w-4 animate-spin" /> : <Wand2 className="h-4 w-4" />}
                  用首尾帧生成视频
                </button>
                <div className="mt-2 text-[10.5px] text-white/35 leading-relaxed">
                  直接用首帧 + 尾帧快速生成连续过渡视频；改造目标和原视频链接只作为节奏 / 镜头参考，生成进度和 MP4 会显示在 Video Gen 节点。
                </div>
              </section>
          </div>
        )}
      </div>
      <button
        type="button"
        onPointerDown={startResize}
        className="absolute bottom-0 left-0 right-0 z-10 h-4 cursor-ns-resize border-t border-white/10 bg-black/50 text-white/45 hover:bg-violet-500/25 hover:text-white inline-flex items-center justify-center transition"
        title="拖动上推 / 下拉调整编排区高度"
      >
        <GripHorizontal className="h-3.5 w-3.5" />
      </button>
    </div>
  )
}

function FieldText({ label, value, onChange, placeholder }: { label: string; value: string; onChange: (v: string) => void; placeholder?: string }) {
  return (
    <label className="block">
      <div className="text-[10.5px] text-white/55 mb-1">{label}</div>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        className="w-full text-[12.5px] px-2.5 py-1.5 rounded-md bg-black/40 border border-white/15 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40 focus:border-violet-400/40"
      />
    </label>
  )
}

function FieldNum({ label, value, onChange, placeholder }: { label: string; value: number; onChange: (v: number) => void; placeholder?: string }) {
  return (
    <label className="block">
      <div className="text-[10.5px] text-white/55 mb-1">{label}</div>
      <input
        type="number"
        step="0.1"
        min="0"
        value={value || ""}
        onChange={(e) => onChange(parseFloat(e.target.value) || 0)}
        placeholder={placeholder}
        className="w-full text-[12.5px] px-2.5 py-1.5 rounded-md bg-black/40 border border-white/15 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40 focus:border-violet-400/40"
      />
    </label>
  )
}

function FieldTextarea({ label, value, onChange, placeholder, rows = 2 }: { label: string; value: string; onChange: (v: string) => void; placeholder?: string; rows?: number }) {
  return (
    <label className="block">
      <div className="text-[10.5px] text-white/55 mb-1">{label}</div>
      <textarea
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        rows={rows}
        className="w-full text-[12.5px] px-2.5 py-1.5 rounded-md bg-black/40 border border-white/15 outline-none text-white placeholder:text-white/30 focus:ring-2 focus:ring-violet-400/40 focus:border-violet-400/40 resize-none"
      />
    </label>
  )
}
