import { useCallback, useEffect, useRef, useState } from "react";
import { DownloadMediaButton } from "../components/DownloadMediaButton";

function formatTime(sec: number): string {
  if (!Number.isFinite(sec)) return "0:00";
  const s = Math.floor(sec % 60);
  const m = Math.floor(sec / 60);
  return `${m}:${s.toString().padStart(2, "0")}`;
}

export function ToolsVideoFrame() {
  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const [file, setFile] = useState<File | null>(null);
  const [url, setUrl] = useState<string | null>(null);
  const [duration, setDuration] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [previewUrl, setPreviewUrl] = useState<string | null>(null);
  const [err, setErr] = useState<string | null>(null);

  useEffect(() => {
    return () => {
      if (url) URL.revokeObjectURL(url);
    };
  }, [url]);

  const drawFrame = useCallback(() => {
    const video = videoRef.current;
    const canvas = canvasRef.current;
    if (!video || !canvas || video.readyState < 2) return;
    const w = video.videoWidth;
    const h = video.videoHeight;
    if (w === 0 || h === 0) return;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext("2d");
    if (!ctx) return;
    ctx.drawImage(video, 0, 0, w, h);
    setPreviewUrl(canvas.toDataURL("image/png"));
  }, []);

  useEffect(() => {
    const v = videoRef.current;
    if (!v || !url) return;
    const onMeta = () => {
      const d = v.duration;
      setDuration(Number.isFinite(d) ? d : 0);
      setCurrentTime(0);
      v.currentTime = 0;
      requestAnimationFrame(() => drawFrame());
    };
    const onSeeked = () => {
      setCurrentTime(v.currentTime);
      drawFrame();
    };
    const onTime = () => setCurrentTime(v.currentTime);
    v.addEventListener("loadedmetadata", onMeta);
    v.addEventListener("seeked", onSeeked);
    v.addEventListener("timeupdate", onTime);
    return () => {
      v.removeEventListener("loadedmetadata", onMeta);
      v.removeEventListener("seeked", onSeeked);
      v.removeEventListener("timeupdate", onTime);
    };
  }, [url, drawFrame]);

  function onPickVideo(f: File | null) {
    setErr(null);
    setPreviewUrl(null);
    if (url) URL.revokeObjectURL(url);
    setUrl(null);
    setFile(f);
    if (!f) return;
    if (!f.type.startsWith("video/")) {
      setErr("请选择视频文件。");
      return;
    }
    const u = URL.createObjectURL(f);
    setUrl(u);
  }

  function onScrub(t: number) {
    const v = videoRef.current;
    if (!v) return;
    v.currentTime = t;
  }

  return (
    <div className="max-w-3xl">
      <h1 className="font-display text-2xl font-semibold text-ink mb-2">提取视频帧</h1>
      <p className="text-mist text-sm mb-6 leading-relaxed">
        本地选视频，拖动进度条选时刻，预览后下载 PNG。不上传服务器。
      </p>

      <div className="space-y-5">
        <div>
          <label className="block text-sm font-semibold text-ink mb-2">视频（必选）</label>
          <input
            type="file"
            accept="video/*"
            className="text-sm text-ink file:mr-3 file:rounded-lg file:border-0 file:bg-slate-200 file:px-3 file:py-1.5 file:text-sm file:text-ink"
            onChange={(e) => onPickVideo(e.target.files?.[0] ?? null)}
          />
          {file && (
            <p className="text-xs text-mist mt-1">
              已选：{file.name}（{(file.size / (1024 * 1024)).toFixed(2)} MB）
            </p>
          )}
        </div>

        {url && (
          <>
            <div className="rounded-xl overflow-hidden border border-slate-200 bg-black">
              <video
                ref={videoRef}
                src={url}
                className="w-full max-h-[360px] object-contain"
                playsInline
                muted
                preload="metadata"
              />
            </div>

            <div>
              <div className="flex justify-between text-xs text-mist mb-1">
                <span>{formatTime(currentTime)}</span>
                <span>/ {formatTime(duration)}</span>
              </div>
              <input
                type="range"
                min={0}
                max={duration || 0}
                step={0.01}
                value={currentTime}
                onInput={(e) => onScrub(Number((e.target as HTMLInputElement).value))}
                onChange={(e) => onScrub(Number(e.target.value))}
                className="w-full accent-ink h-2 rounded-full appearance-none bg-slate-400/90"
              />
              <p className="text-xs text-mist mt-1">停稳后显示当前帧预览。</p>
            </div>

            <canvas ref={canvasRef} className="hidden" aria-hidden />

            {previewUrl && (
              <div>
                <p className="text-sm font-semibold text-ink mb-2">当前帧预览</p>
                <img
                  src={previewUrl}
                  alt="当前帧"
                  className="max-w-full max-h-64 rounded-lg border border-slate-200 object-contain bg-slate-100"
                />
                <div className="mt-3">
                  <DownloadMediaButton
                    dataUrl={previewUrl}
                    filenameBase="video-frame"
                    label="下载当前帧 PNG"
                    className="rounded-lg bg-ink text-paper px-5 py-2 text-sm font-medium hover:bg-slate-800"
                  />
                </div>
              </div>
            )}
          </>
        )}

        {err && <p className="text-sm text-red-700">{err}</p>}
      </div>
    </div>
  );
}
