import { type NextRequest, NextResponse } from "next/server";
import { env } from "~/env";
import type { ProxyFn } from "~/proxy";
import { TOKEN_CONFIG } from "~/server/auth/configs";
import { verifyToken } from "~/server/auth/jwt";

const STALE_KEY = "stale-resource";
export const apisProxy: ProxyFn = async (req: NextRequest) => {
	const { pathname, searchParams } = req.nextUrl;

	// Handle Storage API requests
	if (pathname.startsWith("/storage-api/")) {
		const params = new URLSearchParams(searchParams);
		const isImageRequest = params.get("media") === "image";
		const isVideoRequest = params.get("media") === "video";

		const purpose = req.headers.get("purpose");
		const isNextImageRequest =
			purpose === "prefetch" || req.headers.get("x-vercel-id");

		if (!isNextImageRequest && !isImageRequest && !isVideoRequest) {
			const accessToken = req.cookies.get(
				TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME,
			)?.value;

			if (!accessToken) {
				console.log(
					"No access token found, referrer:",
					req.referrer,
					" url:",
					req.url,
				);
				return new NextResponse("Unauthorized", { status: 401 });
			}

			const { expired, session } = await verifyToken(accessToken);
			if (!session || expired) {
				console.log("Invalid token, referrer:", req.referrer, " url:", req.url);
				return new NextResponse("Unauthorized", { status: 401 });
			}
		}

		const slug = pathname.replace("/storage-api/", "");
		params.set("token", env.STORAGE_TOKEN);
		const storageUrl = `${env.STORAGE_URL}/${slug}?${params.toString()}`;

		try {
			const headers = new Headers(req.headers);
			headers.delete("host");
			headers.delete("cookie");
			const rangeHeader = req.headers.get("range");

			const response = await fetch(storageUrl, {
				method: req.method,
				headers: headers,
				body:
					req.method !== "GET" && req.method !== "HEAD" ? req.body : undefined,
				// @ts-expect-error - duplex needed for request streaming
				duplex: "half",
			});

			if (!response.ok) {
				const isStaleResource =
					response.status === 404 || response.status === 410;

				if (isImageRequest || isNextImageRequest) {
					const url = req.nextUrl.clone();
					url.pathname = "/fallback-image.png";
					url.search = "";
					const response = NextResponse.rewrite(url);
					if (isStaleResource) {
						response.cookies.set(STALE_KEY, "1", {
							maxAge: 5,
							path: "/",
						});
					}

					return response;
				}

				if (isVideoRequest) {
					const url = req.nextUrl.clone();
					url.pathname = "/fallback-video.png";
					url.search = "";
					const response = NextResponse.rewrite(url);
					if (isStaleResource) {
						response.cookies.set(STALE_KEY, "1", {
							maxAge: 5,
							path: "/",
						});
					}

					return response;
				}

				if (isStaleResource) {
					return NextResponse.json(
						{ message: "Stale resource, please reload." },
						{ status: 410 },
					);
				}
				return new NextResponse(`Storage API error: ${response.status}`, {
					status: response.status,
				});
			}

			if (response.status === 204) {
				return new NextResponse(null, { status: 200 });
			}

			const data = await response.arrayBuffer();

			if (!data || data.byteLength === 0) {
				console.error(
					"Received empty response from storage API, referrer:",
					req.referrer,
					" url:",
					req.url,
				);

				if (isImageRequest || isNextImageRequest) {
					const url = req.nextUrl.clone();
					url.pathname = "/fallback-image.png";
					url.search = "";
					return NextResponse.rewrite(url);
				}

				if (isVideoRequest) {
					const url = req.nextUrl.clone();
					url.pathname = "/fallback-video.png";
					url.search = "";
					return NextResponse.rewrite(url);
				}

				return new NextResponse("Empty response", { status: 500 });
			}

			const status =
				rangeHeader && response.status === 206 ? 206 : response.status;

			const proxyResponse = new NextResponse(data, {
				status: status,
				statusText: response.statusText,
			});

			const contentType = response.headers.get("Content-Type");
			const contentDisposition = response.headers.get("Content-Disposition");
			const contentLength = response.headers.get("Content-Length");
			const acceptRanges = response.headers.get("Accept-Ranges");
			const contentRange = response.headers.get("Content-Range");

			if (contentType) {
				proxyResponse.headers.set("Content-Type", contentType);
			}

			if (contentDisposition) {
				proxyResponse.headers.set("Content-Disposition", contentDisposition);
			}

			if (contentLength) {
				proxyResponse.headers.set("Content-Length", contentLength);
			}

			if (acceptRanges) {
				proxyResponse.headers.set("Accept-Ranges", acceptRanges);
			} else if (isVideoRequest) {
				proxyResponse.headers.set("Accept-Ranges", "bytes");
			}

			if (contentRange) {
				proxyResponse.headers.set("Content-Range", contentRange);
			}

			proxyResponse.headers.set("Access-Control-Allow-Origin", "*");

			if (isVideoRequest) {
				proxyResponse.headers.set(
					"Cache-Control",
					"public, max-age=31536000, immutable",
				);
			} else {
				proxyResponse.headers.set(
					"Cache-Control",
					"public, max-age=31536000, immutable",
				);
			}

			proxyResponse.headers.delete("X-Frame-Options");
			proxyResponse.headers.set(
				"Content-Security-Policy",
				"frame-ancestors 'self'",
			);

			return proxyResponse;
		} catch (error) {
			console.error("Storage proxy error:", error);

			if (isImageRequest || isNextImageRequest) {
				const url = req.nextUrl.clone();
				url.pathname = "/fallback-image.png";
				url.search = "";
				return NextResponse.rewrite(url);
			}

			if (isVideoRequest) {
				const url = req.nextUrl.clone();
				url.pathname = "/fallback-video.png";
				url.search = "";
				return NextResponse.rewrite(url);
			}

			return new NextResponse("Failed to proxy request", { status: 500 });
		}
	}
	return;
};
