import { NextRequest, NextResponse } from "next/server";

const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? process.env.API_BASE_URL ?? "";
const ACCESS_COOKIE = "oudelaa_sa_access";
const REFRESH_COOKIE = "oudelaa_sa_refresh";
const ACCESS_MAX_AGE_SECONDS = 15 * 60;
const REFRESH_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;

function buildTargetUrl(pathSegments: string[], searchParams: URLSearchParams) {
  const base = API_BASE_URL.replace(/\/$/, "");
  const path = pathSegments.join("/");
  const query = searchParams.toString();
  return `${base}/${path}${query ? `?${query}` : ""}`;
}

function isSuperAdminLogin(pathSegments: string[]) {
  return pathSegments.join("/") === "auth/superadmin/login";
}

function isSuperAdminRefresh(pathSegments: string[]) {
  return pathSegments.join("/") === "auth/superadmin/refresh";
}

function isSuperAdminLogout(pathSegments: string[]) {
  return pathSegments.join("/") === "auth/superadmin/logout";
}

function isJsonContent(contentType: string | null) {
  return (contentType ?? "").toLowerCase().includes("application/json");
}

function parseJsonSafe<T>(value: string): T | null {
  try {
    return JSON.parse(value) as T;
  } catch {
    return null;
  }
}

function buildUpstreamHeaders(params: {
  req: NextRequest;
  pathSegments: string[];
  accessToken?: string;
  contentType: string | null;
}) {
  const headers = new Headers();
  const { req, pathSegments, accessToken, contentType } = params;

  const accept = req.headers.get("accept");
  if (accept) {
    headers.set("accept", accept);
  }

  if (contentType) {
    headers.set("content-type", contentType);
  }

  const authorization = req.headers.get("authorization");
  if (authorization) {
    headers.set("authorization", authorization);
  } else if (accessToken && !isSuperAdminLogin(pathSegments)) {
    headers.set("authorization", `Bearer ${accessToken}`);
  }

  return headers;
}

function applyAuthCookies(response: NextResponse, payload: {
  accessToken?: string;
  refreshToken?: string;
}) {
  const secure = process.env.NODE_ENV === "production";

  if (payload.accessToken) {
    response.cookies.set(ACCESS_COOKIE, payload.accessToken, {
      httpOnly: true,
      secure,
      sameSite: "lax",
      path: "/",
      maxAge: ACCESS_MAX_AGE_SECONDS,
    });
  }

  if (payload.refreshToken) {
    response.cookies.set(REFRESH_COOKIE, payload.refreshToken, {
      httpOnly: true,
      secure,
      sameSite: "lax",
      path: "/",
      maxAge: REFRESH_MAX_AGE_SECONDS,
    });
  }
}

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

async function proxyRequest(req: NextRequest, pathSegments: string[] = []) {
  if (!API_BASE_URL) {
    return new NextResponse("Missing API base URL", { status: 500 });
  }

  const url = new URL(req.url);
  const targetUrl = buildTargetUrl(pathSegments, url.searchParams);
  const isReadOnlyMethod = ["GET", "HEAD"].includes(req.method);
  const contentType = req.headers.get("content-type");
  const accessToken = req.cookies.get(ACCESS_COOKIE)?.value;
  const refreshToken = req.cookies.get(REFRESH_COOKIE)?.value;
  const headers = buildUpstreamHeaders({
    req,
    pathSegments,
    accessToken,
    contentType,
  });

  let body: BodyInit | undefined;

  if (!isReadOnlyMethod) {
    const bodyBuffer = await req.arrayBuffer();
    const hasBody = bodyBuffer.byteLength > 0;
    body = hasBody ? bodyBuffer : undefined;

    const shouldInjectRefreshToken =
      (isSuperAdminRefresh(pathSegments) || isSuperAdminLogout(pathSegments)) &&
      isJsonContent(contentType);

    if (shouldInjectRefreshToken) {
      const rawText = hasBody ? Buffer.from(bodyBuffer).toString("utf8") : "";
      const parsed = parseJsonSafe<Record<string, unknown>>(rawText) ?? {};
      if (!parsed.refreshToken && refreshToken) {
        parsed.refreshToken = refreshToken;
      }
      body = JSON.stringify(parsed);
      headers.set("content-type", "application/json");
    }
  }

  const init: RequestInit = {
    method: req.method,
    headers,
    cache: "no-store",
  } as RequestInit;

  if (body !== undefined) {
    init.body = body;
  }

  try {
    const upstream = await fetch(targetUrl, init);
    const responseHeaders = new Headers(upstream.headers);
    responseHeaders.delete("content-encoding");
    responseHeaders.delete("content-length");

    const isAuthResponse =
      isSuperAdminLogin(pathSegments) ||
      isSuperAdminRefresh(pathSegments) ||
      isSuperAdminLogout(pathSegments);

    if (isAuthResponse && isJsonContent(upstream.headers.get("content-type"))) {
      const payload = (await upstream.json()) as Record<string, unknown>;
      const response = NextResponse.json(payload, {
        status: upstream.status,
        headers: responseHeaders,
      });

      if (upstream.ok && (isSuperAdminLogin(pathSegments) || isSuperAdminRefresh(pathSegments))) {
        applyAuthCookies(response, {
          accessToken: typeof payload.accessToken === "string" ? payload.accessToken : undefined,
          refreshToken: typeof payload.refreshToken === "string" ? payload.refreshToken : undefined,
        });
      }

      if (upstream.ok && isSuperAdminLogout(pathSegments)) {
        clearAuthCookies(response);
      }

      return response;
    }

    const response = new NextResponse(upstream.body, {
      status: upstream.status,
      headers: responseHeaders,
    });

    if (upstream.ok && isSuperAdminLogout(pathSegments)) {
      clearAuthCookies(response);
    }

    return response;
  } catch (error) {
    const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
    return new NextResponse(`Upstream fetch failed: ${message}`, { status: 502 });
  }
}

export async function GET(
  req: NextRequest,
  context: { params: Promise<{ path: string[] }> },
) {
  const { path } = await context.params;
  return proxyRequest(req, path ?? []);
}

export async function POST(
  req: NextRequest,
  context: { params: Promise<{ path: string[] }> },
) {
  const { path } = await context.params;
  return proxyRequest(req, path ?? []);
}

export async function PATCH(
  req: NextRequest,
  context: { params: Promise<{ path: string[] }> },
) {
  const { path } = await context.params;
  return proxyRequest(req, path ?? []);
}

export async function DELETE(
  req: NextRequest,
  context: { params: Promise<{ path: string[] }> },
) {
  const { path } = await context.params;
  return proxyRequest(req, path ?? []);
}

export async function PUT(
  req: NextRequest,
  context: { params: Promise<{ path: string[] }> },
) {
  const { path } = await context.params;
  return proxyRequest(req, path ?? []);
}
