"use client"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useTheme } from "next-themes"
import {
  ReactFlow, Background, BackgroundVariant, Controls, MiniMap,
  useNodesState, useEdgesState,
  type Node, type Edge,
} from "@xyflow/react"
import { Toaster, toast } from "sonner"
import {
  InputNode, DownloadNode, SplitNode, KeyframeNode, ASRNode,
  TranslateNode, RewriteNode, ImageGenNode, VideoGenNode, ComposeNode,
  type NodeData,
} from "@/components/nodes"
import { ThemeToggle } from "@/components/theme-toggle"
import { analyzeJob, createJob, getJob, uploadJob, type Job } from "@/lib/api"

const NODE_TYPES = {
  input: InputNode,
  download: DownloadNode,
  split: SplitNode,
  keyframe: KeyframeNode,
  asr: ASRNode,
  translate: TranslateNode,
  rewrite: RewriteNode,
  imagegen: ImageGenNode,
  videogen: VideoGenNode,
  compose: ComposeNode,
}

// 手布局：DAG，从左到右
// 拆分后两路：上路 video → keyframe → imagegen → videogen ↘
//             下路 audio → asr → translate → rewrite ────→ compose
const LAYOUT: Array<{ id: string; type: keyof typeof NODE_TYPES; x: number; y: number }> = [
  { id: "input",     type: "input",     x:   40, y: 240 },
  { id: "download",  type: "download",  x:  400, y: 240 },
  { id: "split",     type: "split",     x:  720, y: 240 },
  { id: "keyframe",  type: "keyframe",  x: 1060, y:  60 },
  { id: "asr",       type: "asr",       x: 1060, y: 440 },
  { id: "translate", type: "translate", x: 1440, y: 440 },
  { id: "imagegen",  type: "imagegen",  x: 1480, y:  60 },
  { id: "rewrite",   type: "rewrite",   x: 1820, y: 440 },
  { id: "videogen",  type: "videogen",  x: 1860, y:  60 },
  { id: "compose",   type: "compose",   x: 2240, y: 240 },
]

const EDGES_RAW: Array<[string, string]> = [
  ["input", "download"],
  ["download", "split"],
  ["split", "keyframe"],
  ["split", "asr"],
  ["asr", "translate"],
  ["translate", "rewrite"],
  ["keyframe", "imagegen"],
  ["rewrite", "imagegen"],
  ["imagegen", "videogen"],
  ["videogen", "compose"],
  ["rewrite", "compose"],
]

export default function Home() {
  const { resolvedTheme } = useTheme()
  const [job, setJob] = useState<Job | null>(null)
  const [submitting, setSubmitting] = useState(false)
  const [analyzing, setAnalyzing] = useState(false)
  const [selectedFrames, setSelectedFrames] = useState<Set<number>>(new Set())
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)

  const handleSubmit = useCallback(async (url: string) => {
    setSubmitting(true)
    setSelectedFrames(new Set())
    try {
      const created = await createJob(url)
      setJob(created)
      toast.success(`已创建任务 ${created.id.slice(0, 8)}`)
    } catch (e) {
      toast.error("提交失败：" + (e instanceof Error ? e.message : String(e)))
    } finally {
      setSubmitting(false)
    }
  }, [])

  const handleUpload = useCallback(async (file: File) => {
    setSubmitting(true)
    setSelectedFrames(new Set())
    try {
      toast.info(`上传中：${file.name} (${(file.size / 1024 / 1024).toFixed(1)} MB)`)
      const created = await uploadJob(file)
      setJob(created)
      toast.success(`已上传 ${created.id.slice(0, 8)}`)
    } catch (e) {
      toast.error("上传失败：" + (e instanceof Error ? e.message : String(e)))
    } finally {
      setSubmitting(false)
    }
  }, [])

  const handleAnalyze = useCallback(async () => {
    if (!job) return
    setAnalyzing(true)
    setSelectedFrames(new Set())
    try {
      await analyzeJob(job.id, 5)
      toast.info("开始解析：拆轨 → 抽帧 → ASR → 翻译")
    } catch (e) {
      toast.error("解析触发失败：" + (e instanceof Error ? e.message : String(e)))
    } finally {
      setAnalyzing(false)
    }
  }, [job?.id])

  const handleToggleFrame = useCallback((idx: number) => {
    setSelectedFrames((prev) => {
      const next = new Set(prev)
      if (next.has(idx)) next.delete(idx)
      else next.add(idx)
      return next
    })
  }, [])

  // 轮询 Job（downloaded / transcribed / failed 三态停止）
  useEffect(() => {
    if (!job) return
    const TERMINAL: Job["status"][] = ["downloaded", "transcribed", "failed"]
    if (TERMINAL.includes(job.status)) {
      if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null }
      return
    }
    pollRef.current = setInterval(async () => {
      try {
        const latest = await getJob(job.id)
        setJob(latest)
      } catch { /* silent */ }
    }, 1500)
    return () => { if (pollRef.current) clearInterval(pollRef.current) }
  }, [job?.id, job?.status])

  const nodeData: NodeData = useMemo(() => ({
    job,
    submitting,
    analyzing,
    selectedFrames,
    onSubmitUrl: handleSubmit,
    onUploadFile: handleUpload,
    onAnalyze: handleAnalyze,
    onToggleFrame: handleToggleFrame,
  }), [job, submitting, analyzing, selectedFrames, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame])

  // 用 useNodesState 让 ReactFlow 自己管位置（避免轮询时重置 drag）
  const [nodes, setNodes, onNodesChange] = useNodesState<Node>(
    LAYOUT.map((n) => ({
      id: n.id,
      type: n.type,
      position: { x: n.x, y: n.y },
      data: nodeData,
      draggable: true,
    })),
  )
  const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>(
    EDGES_RAW.map(([from, to], i) => ({
      id: `e${i}`, source: from, target: to, animated: false, type: "default",
    })),
  )

  // Job 数据变化时只更新节点 data 不动 position
  useEffect(() => {
    setNodes((prev) => prev.map((n) => ({ ...n, data: nodeData })))
  }, [nodeData, setNodes])

  // 边的 animated 状态跟 Job 进度联动
  useEffect(() => {
    const doneOf: Record<string, boolean> = {
      input: !!job,
      download: !!job?.video_url,
      split: !!job && ["frames_extracted", "transcribing", "transcribed"].includes(job.status),
      keyframe: !!job && job.frames.length > 0,
      asr: !!job && job.transcript.length > 0,
      translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
    }
    setEdges((prev) => prev.map((e) => ({ ...e, animated: !!doneOf[e.source] })))
  }, [job, setEdges])

  return (
    <>
      <div className="canvas-bg" />
      <main className="relative h-screen w-screen overflow-hidden">
        {/* 顶部栏 */}
        <header className="absolute top-4 left-6 right-6 z-20 flex items-center justify-between pointer-events-none">
          <div className="pointer-events-auto">
            <div className="text-[10px] uppercase tracking-[0.3em] text-[var(--text-faint)]">SKG · AI Material Pipeline</div>
            <h1 className="font-serif text-[26px] leading-none mt-1 text-[var(--text-strong)]">
              TK 二创工作台
              <span className="text-[var(--text-faint)] ml-3 text-[14px] font-sans tracking-tight">/ Node Workflow</span>
            </h1>
          </div>
          <div className="pointer-events-auto flex items-center gap-2">
            {job && (
              <div className="glass-node flex items-center gap-2 px-3 h-9" style={{ borderRadius: 12 }}>
                <span className="text-[10px] uppercase tracking-widest text-[var(--text-faint)]">JOB</span>
                <span className="text-[11.5px] font-mono text-[var(--text-strong)]">{job.id.slice(0, 8)}</span>
                <span className="text-[10.5px] text-[var(--text-faint)]">·</span>
                <span className="text-[11.5px] text-[var(--text-soft)]">{job.message || job.status}</span>
              </div>
            )}
            <ThemeToggle />
          </div>
        </header>

        {/* 画布 */}
        <ReactFlow
          nodes={nodes}
          edges={edges}
          onNodesChange={onNodesChange}
          onEdgesChange={onEdgesChange}
          nodeTypes={NODE_TYPES}
          colorMode={resolvedTheme === "light" ? "light" : "dark"}
          fitView
          fitViewOptions={{ padding: 0.12 }}
          minZoom={0.4}
          maxZoom={1.5}
          proOptions={{ hideAttribution: true }}
        >
          <Background variant={BackgroundVariant.Dots} gap={28} size={1.4} />
          <Controls position="bottom-left" />
          <MiniMap position="bottom-right" pannable zoomable nodeStrokeWidth={2} />
        </ReactFlow>

        {/* 底部说明 */}
        <footer className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 text-[10.5px] font-mono text-[var(--text-faint)] pointer-events-none">
          MVP 第一冲刺：步骤 1-6 已通 · 7-10 占位 · 拖拽节点 · 滚轮缩放
        </footer>

        <Toaster theme="system" position="top-right" />
      </main>
    </>
  )
}
