import { NextRequest, NextResponse } from "next/server";
import { MODAL_TYPES } from "./lib/modal-system/ModalRegistery";
import { authenticate } from "./lib/auth/authenticate";
import { hasAccess } from "./lib/auth/helper";

const protectedRoutes = [
  "/profile",
  "/edit-profile",
  "/change-password",
  "/credit-history",
  "/dashboard",
  "/admin",
  "/admin/users",
  "/admin/packages",
  "/admin/transactions",
  "/admin/contacts",
  "/admin/settings",
];

export async function proxy(request: NextRequest) {
  const { pathname, searchParams } = request.nextUrl;

  const isPrefetch =
    request.headers.get("purpose") === "prefetch" ||
    request.headers.get("next-router-prefetch") === "1";

  if (isPrefetch) {
    return NextResponse.next();
  }

  // -----------------------------
  // VERIFY EMAIL
  // -----------------------------
  // Must run before the auth checks below: users clicking the verify-email
  // link from their inbox are almost always logged out, so this redirect
  // can't depend on an accessToken/protected-route check.
  if (pathname === "/verify-email") {
    const token = searchParams.get("token");

    const url = request.nextUrl.clone();
    url.pathname = "/";

    if (!token) {
      url.searchParams.set("modal", MODAL_TYPES.LOGIN);
      url.searchParams.set("status", "verify-failed");

      return NextResponse.redirect(url);
    }

    url.searchParams.set("modal", MODAL_TYPES.VERIFY_EMAIL);
    url.searchParams.set("token", token);

    return NextResponse.redirect(url);
  }

  // -----------------------------
  // RESET PASSWORD
  // -----------------------------
  // Same reasoning as VERIFY EMAIL above: must not be gated by auth state.
  if (pathname === "/reset-password") {
    const token = searchParams.get("token");

    const url = request.nextUrl.clone();
    url.pathname = "/";

    if (!token) {
      url.searchParams.set("modal", MODAL_TYPES.LOGIN);
      return NextResponse.redirect(url);
    }

    url.searchParams.set("modal", MODAL_TYPES.RESET_PASSWORD);
    url.searchParams.set("token", token);

    return NextResponse.redirect(url);
  }

  const accessToken = request.cookies.get("accessToken")?.value;

  const isProtectedRoute = protectedRoutes.some(
    (route) => pathname === route || pathname.startsWith(route + "/"),
  );

  // -----------------------------
  // PUBLIC PAGE WITHOUT TOKEN
  // -----------------------------
  if (!isProtectedRoute && !accessToken) {
    return NextResponse.next();
  }

  const authResult = await authenticate(request);

  // -----------------------------
  // CLEAN HOME MODAL
  // -----------------------------
  if (accessToken && pathname === "/") {
    const hasModal = searchParams.has("modal");
    const hasToken = searchParams.has("token");
    const hasStatus = searchParams.has("status");
    const modalParam = searchParams.get("modal");

    const isVerifyEmailFlow = modalParam === MODAL_TYPES.VERIFY_EMAIL;

    if (!isVerifyEmailFlow && (hasModal || hasToken || hasStatus)) {
      const url = request.nextUrl.clone();

      url.searchParams.delete("modal");
      url.searchParams.delete("token");
      url.searchParams.delete("status");

      return NextResponse.redirect(url);
    }
  }

  // -----------------------------
  // PROTECTED ROUTE BUT AUTH FAILED
  // -----------------------------
  if (!authResult && isProtectedRoute) {
    const response = NextResponse.redirect(new URL("/logout", request.url));

    response.cookies.set("accessToken", "", {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      path: "/",
      maxAge: 0,
    });

    response.cookies.set("refreshToken", "", {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      path: "/",
      maxAge: 0,
    });

    return response;
  }

  // -----------------------------
  // PUBLIC PAGE AUTH FAILED
  // -----------------------------
  if (!authResult) {
    return NextResponse.next();
  }

  const { response, role } = authResult;

  const allowed = hasAccess(pathname, role);

  if (!allowed) {
    return NextResponse.redirect(new URL("/", request.url));
  }

  return response;
}
