import { add } from "date-fns";
import { type NextRequest, NextResponse } from "next/server";
import { env } from "~/env";
import type { ProxyFn } from "~/proxy";

import { TOKEN_CONFIG } from "~/server/auth/configs";
import { signToken, verifyToken } from "~/server/auth/jwt";

export const authProxy: ProxyFn = async (req: NextRequest) => {
	const path = req.nextUrl.pathname;

	const isOverridableRoute =
		path.startsWith("/area-riservata/scheda-annuncio-stampa/") ||
		path.startsWith("/servizio/condizioni/") ||
		path.startsWith("/servizio/ricevuta-cortesia/");
	// permette a puppeteer di accedere alla pagina di generazione PDF bypassando l'autenticazione normale
	if (isOverridableRoute) {
		const overrideToken = req.cookies.get(
			TOKEN_CONFIG.OVERRIDE_TOKEN_COOKIE_NAME,
		)?.value;
		if (overrideToken && overrideToken === env.EXP_API_PASS) {
			return;
		}
	}
	const refreshToken = req.cookies.get(
		TOKEN_CONFIG.REFRESH_TOKEN_COOKIE_NAME,
	)?.value;

	const accessToken = req.cookies.get(
		TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME,
	)?.value;

	const isProtectedRoute =
		(path.startsWith("/area-riservata") || path.startsWith("/servizio")) &&
		!path.startsWith("/servizio/pre-onboard");

	if (isProtectedRoute) {
		if (!accessToken) {
			if (!refreshToken) {
				// If no access token and no refresh token, redirect to login
				const destination = new URL("/login", req.nextUrl);
				destination.searchParams.set("redirect", path);
				const response = NextResponse.redirect(destination);
				response.cookies.delete(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
				response.cookies.delete(TOKEN_CONFIG.REFRESH_TOKEN_COOKIE_NAME);
				return response;
			}
			// if refresh token is present, handle refresh token logic
			return await refreshAuthToken(req, refreshToken, false);
		}

		// If access token is present, check if it's valid
		const { expired, session } = await verifyToken(accessToken);
		if (expired && refreshToken) {
			// If access token is expired but refresh token is present, attempt to refresh
			return await refreshAuthToken(req, refreshToken, false);
		}
		if (!session) {
			// If access token is invalid, delete it and redirect to login
			const destination = new URL("/login", req.nextUrl);
			destination.searchParams.set("redirect", path);
			const response = NextResponse.redirect(destination);
			response.cookies.delete(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
			return response;
		}

		if (path.startsWith("/area-riservata/admin")) {
			if (!session.isAdmin) {
				return NextResponse.redirect(
					new URL("/area-riservata/dashboard", req.nextUrl),
				);
			}
			return;
		}
	} else {
		if (path.startsWith("/login")) {
			if (!accessToken) {
				if (refreshToken) {
					return await refreshAuthToken(req, refreshToken, true);
				}
				const response = NextResponse.next();
				response.cookies.delete(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
				response.cookies.delete(TOKEN_CONFIG.REFRESH_TOKEN_COOKIE_NAME);

				return response;
			}
			// if redirect is present, redirect to the specified path
			const redirect = req.nextUrl.searchParams.get("redirect");
			if (redirect && redirect !== "") {
				return NextResponse.redirect(new URL(redirect, req.nextUrl));
			}

			// If no redirect present, redirect to dashboard
			const { expired, session } = await verifyToken(accessToken);
			if (expired && refreshToken) {
				return await refreshAuthToken(req, refreshToken, true);
			}
			if (session && !expired) {
				if (session.isAdmin) {
					return NextResponse.redirect(
						new URL("/area-riservata/dashboard", req.nextUrl),
					);
				}
				return NextResponse.redirect(
					new URL("/area-riservata/dashboard", req.nextUrl),
				);
			}
			// If access token is invalid, delete it
			const destination = new URL("/login", req.nextUrl);
			destination.searchParams.set("redirect", path);
			const response = NextResponse.redirect(destination);
			response.cookies.delete(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
			return response;
		}
		if (path.startsWith("/auth/new-password-reset")) {
			if (!accessToken) {
				return;
			}
			return NextResponse.redirect(new URL("/", req.nextUrl));
		}

		// All other routes are public
		if (!accessToken) {
			if (refreshToken) {
				return await refreshAuthToken(req, refreshToken, false);
			}
		} else {
			const { expired, session } = await verifyToken(accessToken);
			if (!session || expired) {
				if (refreshToken) {
					return await refreshAuthToken(req, refreshToken, false);
				}
				const response = NextResponse.next();
				response.cookies.delete(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME);
				return response;
			}
		}

		return;
	}
};

const refreshAuthToken = async (
	req: NextRequest,
	refreshToken: string,
	onSuccessDashboard: boolean,
) => {
	//console.log("Attempting to refresh access token")
	// If refresh token is present, verify it
	const { expired, session } = await verifyToken(refreshToken);
	if (!session || expired) {
		// If refresh token is invalid, delete it and redirect to login
		const destination = new URL("/login", req.nextUrl);
		destination.searchParams.set("redirect", req.nextUrl.pathname);
		const response = NextResponse.redirect(destination);
		response.cookies.delete(TOKEN_CONFIG.REFRESH_TOKEN_COOKIE_NAME);
		return response;
	}
	// If refresh token is valid, sign a new access token
	const redirect = req.nextUrl.searchParams.get("redirect");
	const destination = onSuccessDashboard
		? "/area-riservata/dashboard"
		: redirect || req.nextUrl.pathname;
	const response = NextResponse.redirect(new URL(destination, req.nextUrl));

	const newAccessToken = await signToken(
		session,
		TOKEN_CONFIG.ACCESS_TOKEN_EXPIRY,
		"accessToken",
	);
	response.cookies.set(TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_NAME, newAccessToken, {
		expires: add(new Date(), {
			hours: TOKEN_CONFIG.ACCESS_TOKEN_COOKIE_EXPIRY,
		}),
		...TOKEN_CONFIG.COOKIE_OPTIONS,
		//secure: env.NODE_ENV === "production",
	});
	return response;
};
