/* eslint-disable react-hooks/exhaustive-deps */
"use client";

import { useMemo, useState } from "react";

type FormatInfo = {
  format_id: string;
  ext?: string | null;
  resolution?: string | null;
  fps?: number | null;
  vcodec?: string | null;
  acodec?: string | null;
  filesize?: number | null;
  filesize_approx?: number | null;
};

type VideoInfo = {
  id: string;
  title: string;
  duration?: number | null;
  uploader?: string | null;
  thumbnail?: string | null;
  webpage_url?: string | null;
  formats: FormatInfo[];
};

type DownloadResponse = {
  file_name: string;
  download_url: string;
};

type DownloadState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; url: string; file: string }
  | { status: "error"; message: string };

const API_BASE =
  process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8000";

const DEFAULT_DOWNLOAD_KEY = "__default";

function formatFileSize(bytes?: number | null) {
  if (!bytes || bytes <= 0) return "未知";
  const units = ["B", "KB", "MB", "GB", "TB"];
  let value = bytes;
  let unitIndex = 0;
  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }
  return `${value.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
}

function formatDuration(seconds?: number | null) {
  if (!seconds || seconds <= 0) return null;
  const h = Math.floor(seconds / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = Math.floor(seconds % 60);
  if (h > 0) {
    return `${h}:${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
  }
  return `${m}:${String(s).padStart(2, "0")}`;
}

export default function Home() {
  const [url, setUrl] = useState("");
  const [videoInfo, setVideoInfo] = useState<VideoInfo | null>(null);
  const [infoState, setInfoState] = useState<
    "idle" | "loading" | "success" | "error"
  >("idle");
  const [infoError, setInfoError] = useState<string | null>(null);
  const [downloads, setDownloads] = useState<Record<string, DownloadState>>({});

  const baseDownloadState = useMemo<DownloadState>(
    () => ({ status: "idle" }),
    []
  );

  const sortedFormats = useMemo(() => {
    if (!videoInfo) return [];
    if (!videoInfo.formats?.length) return [];

    const byQuality = [...videoInfo.formats].sort((a, b) => {
      const sizeA = a.filesize ?? a.filesize_approx ?? 0;
      const sizeB = b.filesize ?? b.filesize_approx ?? 0;

      if (sizeA !== sizeB) return sizeB - sizeA;

      const resA = (a.resolution ?? "").match(/\d+/g)?.map(Number) ?? [0, 0];
      const resB = (b.resolution ?? "").match(/\d+/g)?.map(Number) ?? [0, 0];
      if (resA[0] !== resB[0]) return resB[0] - resA[0];
      if (resA[1] !== resB[1]) return resB[1] - resA[1];

      return (b.fps ?? 0) - (a.fps ?? 0);
    });

    return byQuality.filter(
      (format, index, array) =>
        array.findIndex((item) => item.format_id === format.format_id) === index
    );
  }, [videoInfo]);

  const handleFetchInfo = async (event: React.FormEvent) => {
    event.preventDefault();
    if (!url.trim()) {
      setInfoError("请输入有效的视频链接。");
      setInfoState("error");
      return;
    }

    try {
      setInfoState("loading");
      setInfoError(null);
      setVideoInfo(null);
      setDownloads({});

      const response = await fetch(
        `${API_BASE}/api/info?url=${encodeURIComponent(url.trim())}`
      );
      if (!response.ok) {
        const detail = await response.text();
        throw new Error(
          detail || `获取失败，状态码 ${response.status.toString()}`
        );
      }

      const info = (await response.json()) as VideoInfo;
      setVideoInfo(info);
      setInfoState("success");
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "获取视频信息失败。";
      setInfoError(message);
      setInfoState("error");
    }
  };

  const startDownload = (formatId: string | null) => {
    const key = formatId ?? DEFAULT_DOWNLOAD_KEY;
    setDownloads((prev) => ({
      ...prev,
      [key]: { status: "loading" },
    }));
  };

  const finishDownload = (
    formatId: string | null,
    response: DownloadResponse
  ) => {
    const key = formatId ?? DEFAULT_DOWNLOAD_KEY;
    setDownloads((prev) => ({
      ...prev,
      [key]: {
        status: "success",
        url: response.download_url,
        file: response.file_name,
      },
    }));
  };

  const failDownload = (formatId: string | null, message: string) => {
    const key = formatId ?? DEFAULT_DOWNLOAD_KEY;
    setDownloads((prev) => ({
      ...prev,
      [key]: {
        status: "error",
        message,
      },
    }));
  };

  const handleDownload = async (formatId: string | null) => {
    if (!url.trim()) {
      failDownload(formatId, "请先输入视频链接。");
      return;
    }

    try {
      startDownload(formatId);
      const response = await fetch(`${API_BASE}/api/download`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          url: url.trim(),
          format_id: formatId ?? undefined,
        }),
      });

      if (!response.ok) {
        const detail = await response.text();
        throw new Error(
          detail || `下载失败，状态码 ${response.status.toString()}`
        );
      }

      const payload = (await response.json()) as DownloadResponse;
      finishDownload(formatId, payload);
    } catch (error) {
      const message =
        error instanceof Error ? error.message : "下载失败，请稍后再试。";
      failDownload(formatId, message);
    }
  };

  return (
    <main className="min-h-screen bg-gradient-to-br from-zinc-50 via-white to-zinc-100 py-16 px-4 font-sans text-zinc-900 dark:from-black dark:via-zinc-950 dark:to-black dark:text-zinc-100">
      <div className="mx-auto flex w-full max-w-4xl flex-col gap-8">
        <header className="flex flex-col gap-4 rounded-3xl border border-zinc-200 bg-white/70 px-8 py-10 shadow-lg backdrop-blur dark:border-zinc-800 dark:bg-zinc-950/70">
          <div className="flex flex-col gap-2">
            <span className="text-sm font-medium uppercase tracking-[0.35em] text-zinc-500 dark:text-zinc-400">
              Video Fetcher
            </span>
            <h1 className="text-3xl font-semibold tracking-tight md:text-4xl">
              YTB视频下载服务
            </h1>
            <p className="max-w-2xl text-base text-zinc-600 dark:text-zinc-400">
              输入任意公共视频链接。系统将列出可用清晰度与格式，支持一键最佳质量下载或按需选择单独下载。
            </p>
          </div>

          <form
            onSubmit={handleFetchInfo}
            className="flex flex-col gap-3 rounded-2xl border border-zinc-200/80 bg-white/80 p-4 shadow-inner dark:border-zinc-800/80 dark:bg-zinc-950/80 md:flex-row md:items-center"
          >
            <label className="flex-1">
              <span className="sr-only">视频链接</span>
              <input
                value={url}
                onChange={(event) => setUrl(event.target.value)}
                placeholder="https://www.youtube.com/watch?v=..."
                className="w-full rounded-xl border border-zinc-200 bg-white px-4 py-3 text-base outline-none ring-0 transition focus:border-zinc-400 focus:shadow-lg focus:shadow-zinc-200/70 dark:border-zinc-700 dark:bg-black dark:focus:border-zinc-500 dark:focus:shadow-zinc-800/70"
                autoComplete="off"
              />
            </label>
            <button
              type="submit"
              className="flex w-full items-center justify-center rounded-xl bg-zinc-900 px-5 py-3 text-sm font-medium uppercase tracking-widest text-white transition hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 dark:bg-zinc-200 dark:text-zinc-950 dark:hover:bg-white md:w-auto"
              disabled={infoState === "loading"}
            >
              {infoState === "loading" ? "获取中…" : "获取信息"}
            </button>
          </form>

          {infoState === "error" && infoError ? (
            <p className="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-600 dark:border-red-900 dark:bg-red-950/50 dark:text-red-400">
              {infoError}
            </p>
          ) : null}
        </header>

        {infoState === "loading" ? (
          <section className="rounded-3xl border border-zinc-200 bg-white/70 p-8 text-sm text-zinc-600 shadow-lg dark:border-zinc-800 dark:bg-zinc-950/70 dark:text-zinc-400">
            正在拉取视频信息，请稍候…
          </section>
        ) : null}

        {videoInfo ? (
          <section className="flex flex-col gap-6 rounded-3xl border border-zinc-200 bg-white/80 p-8 shadow-xl backdrop-blur-md dark:border-zinc-800 dark:bg-zinc-950/80">
            <div className="flex flex-col gap-6 md:flex-row md:items-start md:gap-8">
              {videoInfo.thumbnail ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={videoInfo.thumbnail}
                  alt={videoInfo.title}
                  className="aspect-video w-full max-w-sm rounded-2xl border border-zinc-200 object-cover shadow-md dark:border-zinc-800"
                />
              ) : null}

              <div className="flex flex-1 flex-col gap-4">
                <div>
                  <h2 className="text-2xl font-semibold tracking-tight">
                    {videoInfo.title}
                  </h2>
                  <div className="mt-2 flex flex-wrap gap-3 text-sm text-zinc-500 dark:text-zinc-400">
                    {videoInfo.uploader ? (
                      <span className="rounded-full border border-zinc-200 px-3 py-1 dark:border-zinc-700">
                        发布者 · {videoInfo.uploader}
                      </span>
                    ) : null}
                    {formatDuration(videoInfo.duration) ? (
                      <span className="rounded-full border border-zinc-200 px-3 py-1 dark:border-zinc-700">
                        时长 · {formatDuration(videoInfo.duration)}
                      </span>
                    ) : null}
                    <span className="rounded-full border border-zinc-200 px-3 py-1 dark:border-zinc-700">
                      可用格式 · {sortedFormats.length}
                    </span>
                  </div>
                </div>

                <div className="flex flex-col gap-3 rounded-2xl border border-zinc-200/80 bg-zinc-50/80 p-4 dark:border-zinc-800/80 dark:bg-black/50 md:flex-row md:items-center md:justify-between">
                  <div className="flex flex-col gap-1 text-sm text-zinc-600 dark:text-zinc-400">
                    <span className="font-medium text-zinc-800 dark:text-zinc-200">
                      一键最佳质量下载
                    </span>
                    <span>自动采用服务推荐的最佳格式，适合快速下载。</span>
                    {downloads[DEFAULT_DOWNLOAD_KEY]?.status === "success" ? (
                      <a
                        href={downloads[DEFAULT_DOWNLOAD_KEY].url}
                        target="_blank"
                        rel="noopener"
                        className="w-fit truncate text-left text-sm font-medium text-zinc-900 underline underline-offset-4 transition hover:text-zinc-700 dark:text-zinc-200 dark:hover:text-zinc-50"
                      >
                        {downloads[DEFAULT_DOWNLOAD_KEY].file}
                      </a>
                    ) : null}
                    {downloads[DEFAULT_DOWNLOAD_KEY]?.status === "error" ? (
                      <span className="text-sm text-red-500">
                        {downloads[DEFAULT_DOWNLOAD_KEY].message}
                      </span>
                    ) : null}
                  </div>
                  <button
                    type="button"
                    onClick={() => handleDownload(null)}
                    className="w-full rounded-xl bg-zinc-900 px-5 py-3 text-sm font-semibold text-white transition hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 dark:bg-zinc-200 dark:text-zinc-950 dark:hover:bg-white md:w-auto"
                    disabled={downloads[DEFAULT_DOWNLOAD_KEY]?.status === "loading"}
                  >
                    {downloads[DEFAULT_DOWNLOAD_KEY]?.status === "loading"
                      ? "下载中…"
                      : "立即下载"}
                  </button>
                </div>
              </div>
            </div>

            <div className="flex flex-col gap-4">
              <div className="flex items-center justify-between">
                <h3 className="text-lg font-semibold tracking-tight">
                  可选格式列表
                </h3>
                <span className="text-sm text-zinc-500 dark:text-zinc-400">
                  支持逐项下载，适合精准控制清晰度或格式。
                </span>
              </div>

              <div className="overflow-hidden rounded-2xl border border-zinc-200 shadow-sm dark:border-zinc-800">
                <table className="min-w-full border-collapse">
                  <thead className="bg-zinc-50 text-left text-xs uppercase tracking-wider text-zinc-500 dark:bg-zinc-900 dark:text-zinc-400">
                    <tr>
                      <th className="px-4 py-3 font-medium">格式 ID</th>
                      <th className="px-4 py-3 font-medium">分辨率 / FPS</th>
                      <th className="px-4 py-3 font-medium">编码</th>
                      <th className="px-4 py-3 font-medium">体积</th>
                      <th className="px-4 py-3 font-medium">操作</th>
                    </tr>
                  </thead>
                  <tbody className="divide-y divide-zinc-100 text-sm dark:divide-zinc-800">
                    {sortedFormats.map((format) => {
                      const key = format.format_id;
                      const downloadState = downloads[key] ?? baseDownloadState;
                      const videoCodec =
                        format.vcodec && format.vcodec !== "none"
                          ? format.vcodec.split(".")[0]
                          : "无";
                      const audioCodec =
                        format.acodec && format.acodec !== "none"
                          ? format.acodec.split(".")[0]
                          : "无";
                      const resolution = format.resolution ?? "未知";
                      const fps =
                        format.fps && format.fps > 0
                          ? `${format.fps.toFixed(
                              Number.isInteger(format.fps) ? 0 : 1
                            )} FPS`
                          : null;

                      return (
                        <tr
                          key={format.format_id}
                          className="bg-white transition hover:bg-zinc-50/70 dark:bg-zinc-950 dark:hover:bg-zinc-900/60"
                        >
                          <td className="px-4 py-4 font-medium text-zinc-800 dark:text-zinc-100">
                            <div className="flex flex-col">
                              <span>{format.format_id}</span>
                              {format.ext ? (
                                <span className="text-xs uppercase text-zinc-400">
                                  {format.ext}
                                </span>
                              ) : null}
                            </div>
                          </td>
                          <td className="px-4 py-4 text-zinc-600 dark:text-zinc-300">
                            <div className="flex flex-col gap-1">
                              <span>{resolution}</span>
                              {fps ? (
                                <span className="text-xs text-zinc-400">
                                  {fps}
                                </span>
                              ) : null}
                            </div>
                          </td>
                          <td className="px-4 py-4 text-zinc-600 dark:text-zinc-300">
                            <div className="flex flex-col gap-1">
                              <span>视频 · {videoCodec}</span>
                              <span>音频 · {audioCodec}</span>
                            </div>
                          </td>
                          <td className="px-4 py-4 text-zinc-600 dark:text-zinc-300">
                            {formatFileSize(format.filesize ?? format.filesize_approx)}
                          </td>
                          <td className="px-4 py-4">
                            <div className="flex flex-col gap-2">
                              <button
                                type="button"
                                onClick={() => handleDownload(format.format_id)}
                                className="w-full rounded-lg bg-zinc-900 px-4 py-2 text-xs font-semibold uppercase tracking-wide text-white transition hover:bg-zinc-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-900 dark:bg-zinc-200 dark:text-zinc-950 dark:hover:bg-white"
                                disabled={downloadState.status === "loading"}
                              >
                                {downloadState.status === "loading"
                                  ? "下载中…"
                                  : "下载"}
                              </button>
                              {downloadState.status === "success" ? (
                                <a
                                  href={downloadState.url}
                                  target="_blank"
                                  rel="noopener"
                                  className="truncate text-left text-xs font-medium text-zinc-900 underline underline-offset-4 transition hover:text-zinc-700 dark:text-zinc-200 dark:hover:text-zinc-50"
                                >
                                  {downloadState.file}
                                </a>
                              ) : null}
                              {downloadState.status === "error" ? (
                                <span className="text-xs text-red-500">
                                  {downloadState.message}
                                </span>
                              ) : null}
                            </div>
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>
          </section>
        ) : null}
      </div>
    </main>
  );
}
