import { Layout } from "@/components/Layout";
import { useCallback, useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { formatDateTime } from "@/components/SearchResults";
import { treaty } from "@elysiajs/eden";
import type { App } from "@backend/src";
import { Skeleton } from "@/components/ui/skeleton";
import { Error } from "@/components/Error";
import { Title } from "@/components/Title";
import { toast } from "sonner";
import { ChevronLeft, ChevronRight, Check, X } from "lucide-react";

// @ts-expect-error anyway...
const app = treaty<App>(import.meta.env.VITE_API_URL!);

type VideosResponse = Awaited<ReturnType<Awaited<typeof app.videos.unlabelled>["get"]>>["data"];

export default function Home() {
	const [videos, setVideos] = useState<Exclude<VideosResponse, null>>([]);
	const [currentIndex, setCurrentIndex] = useState(0);
	const [loading, setLoading] = useState(true);
	const [error, setError] = useState<any>(null);
	const [hasMore, setHasMore] = useState(true);

	const fetchVideos = useCallback(async () => {
		try {
			setLoading(true);
			const { data, error } = await app.videos.unlabelled.get({
				headers: {
					Authorization: `Bearer ${localStorage.getItem("sessionID") || ""}`,
				},
			});

			if (error) {
				setError(error);
				return;
			}

			if (data && data.length > 0) {
				setVideos((prev) => [...prev, ...data]);
				setHasMore(data.length === 20);
			} else {
				setHasMore(false);
			}
		} catch (err) {
			setError({ status: 500, value: { message: "网络错误" } });
		} finally {
			setLoading(false);
		}
	}, []);

	const loadMoreIfNeeded = useCallback(() => {
		if (hasMore && videos.length - currentIndex <= 6) {
			fetchVideos();
		}
	}, [hasMore, videos.length, currentIndex, fetchVideos]);

	const labelVideo = async (videoId: string, label: boolean) => {
		const videoKey = `${videoId}-${label}`;

		const maxRetries = 5;
		let retries = 0;

		const attemptLabel = async (): Promise<boolean> => {
			try {
				const { error } = await app.video({ id: videoId }).label.post(
					{ label },
					{
						headers: {
							Authorization: `Bearer ${localStorage.getItem("sessionID") || ""}`,
						},
					},
				);

				if (error) {
					throw error;
				}

				toast.success(`已标记视频 ${label ? "是" : "否"}`);
				return true;
			} catch (err) {
				retries++;
				if (retries < maxRetries) {
					await new Promise((resolve) => setTimeout(resolve, 1000 * retries));
					return attemptLabel();
				}
				return false;
			}
		};

		const success = await attemptLabel();

		if (!success) {
			toast.error(`标记失败，请稍后重试`);
		}
	};

	const handleLabel = async (label: boolean) => {
		const currentVideo = videos[currentIndex];
		if (!currentVideo) return;

		labelVideo(currentVideo.bvid!, label);
		if (currentIndex < videos.length - 1) {
			setCurrentIndex((prev) => prev + 1);
			loadMoreIfNeeded();
		} else {
			fetchVideos();
			if (videos.length > currentIndex + 1) {
				setCurrentIndex((prev) => prev + 1);
			}
		}
	};

	const navigateTo = (index: number) => {
		if (index >= 0 && index < videos.length) {
			setCurrentIndex(index);
			loadMoreIfNeeded();
		}
	};

	useEffect(() => {
		fetchVideos();
	}, [fetchVideos]);

	useEffect(() => {
		loadMoreIfNeeded();
	}, [currentIndex, loadMoreIfNeeded]);

	if (loading && videos.length === 0) {
		return (
			<Layout>
				<Title title="视频打标工具" />
				<div className="space-y-6">
					<Skeleton className="mt-6 w-full aspect-video rounded-lg" />
					<div className="mt-6 flex justify-between items-baseline">
						<Skeleton className="w-60 h-10 rounded-sm" />
						<Skeleton className="w-25 h-10 rounded-sm" />
					</div>
					<Skeleton className="w-full h-20 rounded-lg" />
				</div>
			</Layout>
		);
	}

	if (error && videos.length === 0) {
		return <Error error={error} />;
	}

	const currentVideo = videos[currentIndex];

	return (
		<Layout>
			<Title title="视频打标工具" />

			{currentVideo ? (
				<>
					<div className="mb-24">
						<p className="mt-4 mb-3">
							该视频是否包含一首<b>中V歌曲</b>？
							<Label className="text-secondary-foreground mt-1 leading-5">
								中V歌曲意味着它是由中文虚拟歌姬演唱，或歌词中包含中文。歌曲可以是原创，也可以是非原创（如翻唱、翻调等）。
							</Label>
						</p>
						<div className="flex flex-col sm:flex-row sm:gap-4">
							{currentVideo.cover_url && (
								<a
									href={`https://www.bilibili.com/video/${currentVideo.bvid}`}
									target="_blank"
									rel="noopener noreferrer"
									className="min-w-full sm:min-w-60 md:min-w-80 max-w-full
									sm:max-w-60 md:max-w-80 aspect-video"
								>
									<img
										src={currentVideo.cover_url}
										referrerPolicy="no-referrer"
										className="w-full h-full object-cover rounded-lg"
										alt="Video cover"
									/>
								</a>
							)}
							<div>
								<div className="max-sm:mt-6 flex items-center gap-2">
									<h1 className="text-2xl font-medium">
										<a
											href={`https://www.bilibili.com/video/${currentVideo.bvid}`}
											target="_blank"
											rel="noopener noreferrer"
											className="hover:underline"
										>
											{currentVideo.title ? currentVideo.title : "未知视频标题"}
										</a>
									</h1>
								</div>

								<div className="flex justify-between mt-3">
									<div>
										<p>
											<span>{currentVideo.bvid}</span> · <span>av{currentVideo.aid}</span>
										</p>
										<p>
											<span>发布于 {formatDateTime(new Date(currentVideo.published_at!))}</span><br/>
											<span>播放：{(currentVideo.views ?? 0).toLocaleString()}</span>
										</p>
										<p>
											UP主：
											<a
												className="underline"
												href={`https://space.bilibili.com/${currentVideo.uid}`}
												target="_blank"
												rel="noopener noreferrer"
											>
												{currentVideo.username}
											</a>
										</p>
										<p>
											<span>
												<b>标签</b>
												<br />
												{currentVideo.tags?.replaceAll(",","，")}
											</span>
										</p>
									</div>
								</div>
							</div>
						</div>

						<div className="mt-6">
							<h3 className="font-medium text-lg mb-2">简介</h3>
							<pre className="max-w-full wrap-anywhere break-all text-on-surface-variant text-sm md:text-base whitespace-pre-wrap dark:text-dark-on-surface-variant font-zh">
								{currentVideo.description || "暂无简介"}
							</pre>
						</div>
					</div>

					<div className="fixed bottom-0 left-0 right-0 bg-background border-t p-4 shadow-lg">
						<div className="max-w-4xl mx-auto flex items-center justify-between gap-4">
							<Button
								variant="outline"
								onClick={() => navigateTo(currentIndex - 1)}
								disabled={currentIndex === 0}
								className="flex items-center gap-2"
							>
								<ChevronLeft className="h-4 w-4" />
								上一个
							</Button>

							<div className="flex gap-4">
								<Button
									variant="destructive"
									onClick={() => handleLabel(false)}
									className="flex items-center gap-2"
								>
									<X className="h-4 w-4" />否
								</Button>
								<Button
									variant="default"
									onClick={() => handleLabel(true)}
									className="flex items-center gap-2 bg-green-600 hover:bg-green-700"
								>
									<Check className="h-4 w-4" />是
								</Button>
							</div>

							<Button
								variant="outline"
								onClick={() => navigateTo(currentIndex + 1)}
								disabled={currentIndex === videos.length - 1 && !hasMore}
								className="flex items-center gap-2"
							>
								下一个
								<ChevronRight className="h-4 w-4" />
							</Button>
						</div>
					</div>
				</>
			) : (
				<div className="text-center py-12">
					<p className="text-lg">没有更多视频需要打标</p>
					<Button onClick={fetchVideos} className="mt-4" disabled={loading}>
						{loading ? "加载中..." : "重新加载"}
					</Button>
				</div>
			)}
		</Layout>
	);
}
