"use client"

import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import {
  ArrowUp,
  Clapperboard,
  ExternalLink,
  Image as ImageIcon,
  Loader2,
  Plus,
  Upload,
  X,
  type LucideIcon,
} from "lucide-react"
import { Toaster, toast } from "sonner"
import { MediaAssetTile } from "@/components/media-asset-tile"
import {
  apiAssetUrl,
  createCreativeImageJob,
  deleteGeneratedImage,
  deleteGeneratedVideo,
  generateImage,
  generateStoryboardVideo,
  getRuntimeHealth,
  getJob,
  type GeneratedImage,
  type GeneratedVideo,
  type Job,
  type RuntimeModelOption,
  type RuntimeSizeOption,
} from "@/lib/api"

type CreationMode = "text-image" | "text-video" | "image-video"
type BusyTask = CreationMode | "job" | null
type UploadSlot = "first"

type ModeConfig = {
  id: CreationMode
  label: string
  icon: LucideIcon
  placeholder: string
  needsImage?: boolean
}

const MODES: ModeConfig[] = [
  {
    id: "text-image",
    label: "文生图",
    icon: ImageIcon,
    placeholder: "写清楚画面、主体、构图、光线和比例。例如：9:16 信息流营销图，真实办公室场景，SKG 颈部按摩仪佩戴清楚。",
  },
  {
    id: "text-video",
    label: "文生视频",
    icon: Clapperboard,
    placeholder: "写清楚画面、人物动作、产品出现方式、镜头运动和风格。例如：15 秒竖屏，办公室午休，人物戴上 SKG 颈部按摩仪放松，镜头缓慢推进。",
  },
  {
    id: "image-video",
    label: "图生视频",
    icon: Upload,
    needsImage: true,
    placeholder: "上传图片后，写它要怎么动、镜头怎么运动、产品细节怎么保持、视频节奏和时长。",
  },
]

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 videoStatusText(video: GeneratedVideo) {
  if (video.status === "queued") {
    return video.queue_message || (video.queue_position && video.queue_position > 1 ? `排队中 · 前方 ${video.queue_position - 1} 个任务` : "排队中 · 即将开始")
  }
  if (video.status === "in_progress") {
    return video.queue_message ? `${video.queue_message} · ${Math.round(video.progress)}%` : `生成中 · ${Math.round(video.progress)}%`
  }
  if (video.status === "completed") return `${Math.round(video.duration)}s · 可播放`
  return "失败 · 可重试"
}

function isVideoMode(mode: CreationMode) {
  return mode !== "text-image"
}

const DEFAULT_IMAGE_SIZE_OPTIONS: RuntimeSizeOption[] = [
  { id: "1024x1536", label: "竖图 2:3", value: "1024x1536" },
  { id: "1024x1024", label: "方图 1:1", value: "1024x1024" },
  { id: "1536x1024", label: "横图 3:2", value: "1536x1024" },
  { id: "auto", label: "自动", value: "auto" },
]

const DEFAULT_VIDEO_SIZE_OPTIONS: RuntimeSizeOption[] = [
  { id: "720x1280", label: "竖屏 9:16", value: "720x1280" },
  { id: "1280x720", label: "横屏 16:9", value: "1280x720" },
  { id: "1024x1024", label: "方形 1:1", value: "1024x1024" },
]

export default function Home() {
  const [mode, setMode] = useState<CreationMode>("text-video")
  const [prompt, setPrompt] = useState("")
  const [seconds, setSeconds] = useState(12)
  const [firstFrameFile, setFirstFrameFile] = useState<File | null>(null)
  const [firstFramePreview, setFirstFramePreview] = useState("")
  const [imageModel, setImageModel] = useState("auto")
  const [videoModel, setVideoModel] = useState("seedance")
  const [imageSize, setImageSize] = useState("1024x1536")
  const [videoSize, setVideoSize] = useState("720x1280")
  const [videoDurationOptions, setVideoDurationOptions] = useState<number[]>([5, 8, 10, 12, 15])
  const [imageOptions, setImageOptions] = useState<RuntimeModelOption[]>([
    { id: "auto", label: "自动", model: "gpt-image-2", available: true },
  ])
  const [videoOptions, setVideoOptions] = useState<RuntimeModelOption[]>([
    { id: "seedance", label: "Seedance", model: "seedance", available: true },
  ])
  const [imageSizeOptions, setImageSizeOptions] = useState<RuntimeSizeOption[]>(DEFAULT_IMAGE_SIZE_OPTIONS)
  const [videoSizeOptions, setVideoSizeOptions] = useState<RuntimeSizeOption[]>(DEFAULT_VIDEO_SIZE_OPTIONS)
  const [job, setJob] = useState<Job | null>(null)
  const [busy, setBusy] = useState<BusyTask>(null)
  const [error, setError] = useState("")
  const firstInputRef = useRef<HTMLInputElement>(null)

  const activeMode = MODES.find((item) => item.id === mode) ?? MODES[0]
  const latestImage = latestGeneratedImage(job)
  const latestVideo = latestGeneratedVideo(job)
  const runningVideo = (job?.generated_videos ?? []).some((item) => item.status === "queued" || item.status === "in_progress")
  const submitting = busy === mode || busy === "job"

  useEffect(() => {
    getRuntimeHealth()
      .then((health) => {
        const models = health.models
        const nextImageOptions = models?.image_options?.length
          ? models.image_options
          : [
              { id: "auto", label: "自动", model: models?.image || "gpt-image-2", available: true },
              { id: models?.image || "gpt-image-2", label: "GPT Image 2", model: models?.image || "gpt-image-2", available: true },
            ]
        const nextVideoOptions = models?.video_options?.length
          ? models.video_options
          : [{ id: models?.video || "seedance", label: "Seedance", model: models?.video || "seedance", available: !!models?.video_configured }]
        const nextImageSizeOptions = models?.image_size_options?.length ? models.image_size_options : DEFAULT_IMAGE_SIZE_OPTIONS
        const nextVideoSizeOptions = models?.video_size_options?.length ? models.video_size_options : DEFAULT_VIDEO_SIZE_OPTIONS
        const nextDurationOptions = models?.video_duration_options?.length ? models.video_duration_options : [5, 8, 10, 12, 15]
        setImageOptions(nextImageOptions)
        setVideoOptions(nextVideoOptions)
        setImageSizeOptions(nextImageSizeOptions)
        setVideoSizeOptions(nextVideoSizeOptions)
        setVideoDurationOptions(nextDurationOptions)
        if (!nextImageOptions.some((item) => item.id === imageModel)) setImageModel(nextImageOptions[0]?.id || "auto")
        if (!nextVideoOptions.some((item) => item.id === videoModel)) setVideoModel(nextVideoOptions[0]?.id || "seedance")
        if (!nextImageSizeOptions.some((item) => item.value === imageSize)) setImageSize(nextImageSizeOptions[0]?.value || "1024x1536")
        if (!nextVideoSizeOptions.some((item) => item.value === videoSize)) setVideoSize(nextVideoSizeOptions[0]?.value || "720x1280")
        if (!nextDurationOptions.includes(seconds)) setSeconds(nextDurationOptions.includes(12) ? 12 : (nextDurationOptions[0] ?? 5))
      })
      .catch(() => {
        setImageOptions([{ id: "auto", label: "自动", model: "gpt-image-2", available: true }])
        setVideoOptions([{ id: "seedance", label: "Seedance", model: "seedance", available: true }])
        setImageSizeOptions(DEFAULT_IMAGE_SIZE_OPTIONS)
        setVideoSizeOptions(DEFAULT_VIDEO_SIZE_OPTIONS)
        setVideoDurationOptions([5, 8, 10, 12, 15])
      })
  }, [])

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

  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 resetResult = () => {
    setJob(null)
    setError("")
  }

  const onModeChange = (nextMode: CreationMode) => {
    setMode(nextMode)
    resetResult()
    if (nextMode !== "image-video") {
      setFirstFrameFile(null)
    }
  }

  const setUploadFile = (slot: UploadSlot, file: File | null) => {
    if (slot === "first") setFirstFrameFile(file)
    resetResult()
  }

  const validate = () => {
    if (!prompt.trim()) {
      toast.error("先写提示词")
      return false
    }
    if (activeMode.needsImage && !firstFrameFile) {
      toast.error("先上传图片")
      return false
    }
    return true
  }

  const promptWithGuardrails = () => (
    `${prompt.trim()}\n\nKeep the product shape stable when a product appears. Use a clean vertical marketing composition unless the prompt says otherwise.`
  )

  const prepareJob = useCallback(async () => {
    setBusy("job")
    const created = await createCreativeImageJob(firstFrameFile)
    setJob(created)
    return created
  }, [firstFrameFile])

  const runImage = async () => {
    if (!validate()) return
    setBusy("text-image")
    setError("")
    try {
      const target = await prepareJob()
      const updated = await generateImage(target.id, 0, {
        prompt: promptWithGuardrails(),
        mode: "text",
        model: imageModel,
        size: imageSize,
      })
      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 (!validate()) return
    setBusy(mode)
    setError("")
    try {
      const target = await prepareJob()
      const updated = await generateStoryboardVideo(target.id, 0, {
        prompt: promptWithGuardrails(),
        duration: seconds,
        count: 1,
        first_image: activeMode.needsImage ? { kind: "keyframe", frame_idx: 0 } : null,
        last_image: null,
        size: videoSize,
        model: videoModel,
      })
      setJob(updated)
      toast.success("已加入生成队列")
    } catch (e) {
      const message = e instanceof Error ? e.message : "生视频失败"
      setError(message)
      toast.error(message)
    } finally {
      setBusy(null)
    }
  }

  const runPrimary = () => {
    if (mode === "text-image") return runImage()
    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 : "删除失败")
    }
  }

  return (
    <main className="min-h-screen bg-[#090a0f] text-white">
      <Toaster richColors position="top-center" />
      <div className="flex min-h-screen flex-col">
        <header className="flex h-14 shrink-0 items-center justify-between px-4 text-xs text-white/42 sm:px-6">
          <div className="inline-flex h-8 items-center rounded-full bg-white px-3 shadow-[0_10px_30px_rgba(0,0,0,0.24)]">
            <img src="/skg-logo-black.svg" alt="SKG" className="h-4 w-auto" />
          </div>
          {job ? (
            <a href={`/detail/?job=${job.id}`} className="inline-flex items-center gap-1.5 rounded-lg px-2 py-1.5 text-white/52 transition hover:bg-white/8 hover:text-white">
              详情 <ExternalLink className="h-3.5 w-3.5" />
            </a>
          ) : null}
        </header>

        <section className="flex flex-1 items-center justify-center px-4 pb-16 pt-6">
          <div className="grid w-full max-w-[760px] gap-5">
            <div className="grid justify-items-center gap-2 text-center">
              <h1 className="text-xl font-semibold tracking-normal text-white/92">想生成什么？</h1>
              <p className="text-sm text-white/34">选一种方式，写提示词，直接生成。</p>
            </div>

            <section className="rounded-[18px] border border-white/8 bg-[#1c1f28] p-3 shadow-[0_28px_90px_rgba(0,0,0,0.32)]">
              <div className="mb-3 grid grid-cols-2 gap-2 sm:grid-cols-4">
                {MODES.map((item) => {
                  const Icon = item.icon
                  const selected = item.id === mode
                  return (
                    <button
                      key={item.id}
                      type="button"
                      onClick={() => onModeChange(item.id)}
                      className={cx(
                        "inline-flex h-10 items-center justify-center gap-2 rounded-xl border px-2 text-sm font-semibold transition",
                        selected ? "border-cyan-300/28 bg-cyan-300/12 text-cyan-100" : "border-white/7 bg-black/14 text-white/48 hover:border-white/14 hover:text-white",
                      )}
                    >
                      <Icon className="h-4 w-4" />
                      {item.label}
                    </button>
                  )
                })}
              </div>

              {activeMode.needsImage ? (
                <div className="mb-3 grid gap-2">
                  <FrameUpload
                    label="图片"
                    preview={firstFramePreview}
                    required
                    onPick={() => firstInputRef.current?.click()}
                    onClear={() => setUploadFile("first", null)}
                  />
                </div>
              ) : null}

              <input
                ref={firstInputRef}
                type="file"
                accept="image/png,image/jpeg,image/webp"
                className="hidden"
                onChange={(event) => setUploadFile("first", event.target.files?.[0] ?? null)}
              />
              <textarea
                value={prompt}
                onChange={(event) => {
                  setPrompt(event.target.value)
                  setError("")
                }}
                placeholder={activeMode.placeholder}
                className="min-h-36 w-full resize-none rounded-xl border border-white/7 bg-black/18 px-4 py-3 text-[15px] leading-7 text-white outline-none placeholder:text-white/24 focus:border-cyan-200/28"
              />

              <div className="mt-3 flex flex-wrap items-center justify-between gap-3">
                <div className="flex flex-wrap items-center gap-2 text-xs text-white/38">
                  <label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">
                    模型
                    <select
                      value={isVideoMode(mode) ? videoModel : imageModel}
                      onChange={(event) => {
                        if (isVideoMode(mode)) setVideoModel(event.target.value)
                        else setImageModel(event.target.value)
                      }}
                      className="max-w-36 bg-transparent text-white/76 outline-none"
                    >
                      {(isVideoMode(mode) ? videoOptions : imageOptions).map((item) => (
                        <option key={item.id} value={item.id} disabled={item.available === false}>
                          {item.label}
                        </option>
                      ))}
                    </select>
                  </label>
                  {isVideoMode(mode) ? (
                    <>
                      <label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">
                        画幅
                        <select
                          value={videoSize}
                          onChange={(event) => setVideoSize(event.target.value)}
                          className="max-w-32 bg-transparent text-white/76 outline-none"
                        >
                          {videoSizeOptions.map((item) => (
                            <option key={item.value} value={item.value}>
                              {item.label}
                            </option>
                          ))}
                        </select>
                      </label>
                      <label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">
                        时长
                        <select
                          value={seconds}
                          onChange={(event) => setSeconds(Number(event.target.value))}
                          className="bg-transparent text-white/76 outline-none"
                        >
                          {videoDurationOptions.map((value) => <option key={value} value={value}>{value}s</option>)}
                        </select>
                      </label>
                    </>
                  ) : (
                    <label className="inline-flex h-9 items-center gap-2 rounded-xl border border-white/7 bg-black/14 px-3">
                      尺寸
                      <select
                        value={imageSize}
                        onChange={(event) => setImageSize(event.target.value)}
                        className="max-w-32 bg-transparent text-white/76 outline-none"
                      >
                        {imageSizeOptions.map((item) => (
                          <option key={item.value} value={item.value}>
                            {item.label}
                          </option>
                        ))}
                      </select>
                    </label>
                  )}
                  <span>{activeMode.needsImage ? "图片作为视频参考" : "只根据文字生成"}</span>
                </div>

                <div className="flex items-center gap-2">
                  <a
                    href="/"
                    className="inline-flex h-10 items-center justify-center gap-2 rounded-full border border-white/10 bg-white/6 px-4 text-sm font-semibold text-white/72 transition hover:border-cyan-200/24 hover:text-cyan-100"
                  >
                    <ExternalLink className="h-4 w-4" />
                    画布
                  </a>
                  <button
                    type="button"
                    onClick={runPrimary}
                    disabled={!!busy}
                    className="inline-flex h-10 min-w-28 items-center justify-center gap-2 rounded-full bg-cyan-200 px-5 text-sm font-semibold text-black transition hover:bg-white disabled:cursor-not-allowed disabled:opacity-60"
                  >
                    {submitting ? <Loader2 className="h-4 w-4 animate-spin" /> : <ArrowUp className="h-4 w-4" />}
                    生成
                  </button>
                </div>
              </div>
            </section>

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

            {(latestImage || latestVideo) && (
              <section className="rounded-[18px] border border-white/8 bg-[#161922] p-3">
                <div className="mb-3 flex items-center justify-between gap-2">
                  <h2 className="text-sm font-semibold text-white/82">生成结果</h2>
                  {job ? <a href={`/detail/?job=${job.id}`} className="text-xs font-semibold text-cyan-200/82 hover:text-cyan-100">打开详情页</a> : null}
                </div>
                {latestVideo && job ? (
                  <div className="grid gap-2">
                    {latestVideo.status === "queued" || latestVideo.status === "in_progress" ? (
                      <div className="flex items-center justify-between gap-3 rounded-xl border border-cyan-200/12 bg-cyan-200/8 px-3 py-2 text-xs text-cyan-50/78">
                        <span>{videoStatusText(latestVideo)}</span>
                        {latestVideo.status === "queued" && latestVideo.queue_size ? <span className="text-cyan-100/46">队列 {latestVideo.queue_position || 0}/{latestVideo.queue_size}</span> : null}
                      </div>
                    ) : null}
                    <MediaAssetTile
                      kind="video"
                      src={latestVideo.status === "completed" ? videoSrc(job, latestVideo) : undefined}
                      poster={apiAssetUrl(latestVideo.poster_url)}
                      objectFit="cover"
                      previewObjectFit="contain"
                      className="aspect-video w-full rounded-xl"
                      videoControls={latestVideo.status === "completed"}
                      label={latestVideo.model}
                      meta={videoStatusText(latestVideo)}
                      previewDetail={latestVideo.error || undefined}
                      emptyText={latestVideo.status === "failed" ? "失败" : undefined}
                      busy={latestVideo.status === "queued" || latestVideo.status === "in_progress"}
                      onDelete={() => deleteVideo(latestVideo)}
                    />
                  </div>
                ) : latestImage ? (
                  <MediaAssetTile
                    src={apiAssetUrl(latestImage.url)}
                    alt="generated image"
                    objectFit="cover"
                    previewObjectFit="contain"
                    className="aspect-video w-full rounded-xl"
                    label={latestImage.model}
                    meta={latestImage.mode}
                    onDelete={() => deleteImage(latestImage)}
                  />
                ) : null}
              </section>
            )}
          </div>
        </section>
      </div>
    </main>
  )
}

function FrameUpload({
  label,
  preview,
  required,
  onPick,
  onClear,
}: {
  label: string
  preview: string
  required: boolean
  onPick: () => void
  onClear: () => void
}) {
  return (
    <div className="relative">
      <button
        type="button"
        onClick={onPick}
        className="flex h-24 w-full items-center justify-center overflow-hidden rounded-xl border border-dashed border-white/12 bg-black/16 text-sm font-semibold text-white/44 transition hover:border-cyan-200/30 hover:text-white"
      >
        {preview ? (
          <MediaAssetTile
            src={preview}
            alt={label}
            objectFit="cover"
            previewObjectFit="contain"
            className="h-full w-full rounded-xl"
          />
        ) : (
          <span className="inline-flex items-center gap-2">
            <Plus className="h-4 w-4" />
            上传{label}{required ? "" : "（可选）"}
          </span>
        )}
      </button>
      {preview ? (
        <button
          type="button"
          onClick={onClear}
          className="absolute right-2 top-2 rounded-lg bg-black/60 p-1 text-white/70 transition hover:bg-black hover:text-white"
          aria-label={`移除${label}`}
          title={`移除${label}`}
        >
          <X className="h-3.5 w-3.5" />
        </button>
      ) : null}
    </div>
  )
}
