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

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

	if (!pathname.startsWith("/storage-api/")) {
		return;
	}

	const params = new URLSearchParams(searchParams);
	const isImageRequest = params.get("media") === "image";
	const isVideoRequest = params.get("media") === "video";

	// Check if this is a Next.js Image Optimization request
	const purpose = req.headers.get("purpose");
	const isNextImageRequest =
		purpose === "prefetch" || req.headers.get("x-vercel-id");

	// For regular requests (not from Next Image Optimization), check auth
	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 payload = await verifyToken(accessToken);
		if (!payload) {
			console.log("Invalid token, referrer:", req.referrer, " url:", req.url);
			return new NextResponse("Unauthorized", { status: 401 });
		}
	}

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

	try {
		// Forward the request to storage API
		const headers = new Headers(req.headers);
		headers.delete("host");
		headers.delete("cookie");

		// **CRITICAL: Preserve Range header for video streaming**
		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",
		});

		// Handle failed responses
		if (!response.ok) {
			// console.error(
			// 	`Storage API error: ${response.status} for ${storageUrl}, referrer: ${req.referrer}, url: ${req.url}`,
			// );
			// 404 = File not found (likely stale URL after media update)
			// 410 = Gone (explicitly removed)
			const isStaleResource =
				response.status === 404 || response.status === 410;

			// Return fallback for image requests
			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;
			}

			// Return fallback for video requests
			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;
			}

			// For non-media requests (e.g., documents), return JSON with reload hint
			if (isStaleResource) {
				return NextResponse.json(
					{ message: "Stale resource, please reload." },
					{ status: 410 },
				);
			}
			return new NextResponse(`Storage API error: ${response.status}`, {
				status: response.status,
			});
		}

		//ignore if 204 no content, is the favicon request
		if (response.status === 204) {
			return new NextResponse(null, { status: 200 });
		}

		// Get response data
		const data = await response.arrayBuffer();

		// Check if we got valid data
		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 });
		}

		// **IMPORTANT: Use correct status code for partial content**
		const status =
			rangeHeader && response.status === 206 ? 206 : response.status;

		// Create response with proper headers
		const proxyResponse = new NextResponse(data, {
			status: status,
			statusText: response.statusText,
		});

		// Copy relevant headers
		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);
		}

		// **CRITICAL: Copy Range-related headers for video streaming**
		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);
		}

		// Set CORS and caching headers
		proxyResponse.headers.set("Access-Control-Allow-Origin", "*");

		// Different cache strategy for videos
		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);

		// Return fallback on 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 });
	}
};
