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

// Same base URL as rest of app (NEXT_PUBLIC_STRAPI_URL / getStrapiUrl)
const STRAPI_BASE =
  process.env.NEXT_PUBLIC_STRAPI_URL || "https://cms.navana-realestate.com";
const REDIRECTS_QUERY =
  "filters[isActive][$eq]=true&fields[0]=source&fields[1]=destination&fields[2]=type";

const CACHE_TTL_MS = 60_000; // 60 seconds
// Strapi REST API caps page size at config.api.rest.maxLimit (default 100).
// We page through results so the count of redirects is not silently truncated.
const PAGE_SIZE = 100;
const MAX_PAGES = 50; // hard ceiling: 5,000 redirects

type RedirectRule = { source: string; destination: string; type: string };

let cachedRedirects: RedirectRule[] | null = null;
let cacheExpiry = 0;

function parseRedirectItems(data: unknown): RedirectRule[] {
  if (!Array.isArray(data)) return [];
  return data
    .map((item: Record<string, unknown> & { attributes?: RedirectRule }) => {
      // Strapi 5: flat (source, destination, type); Strapi 4: item.attributes
      const attrs = item?.attributes ?? item;
      if (
        !attrs ||
        typeof attrs.source !== "string" ||
        typeof attrs.destination !== "string"
      )
        return null;
      return {
        source: attrs.source,
        destination: attrs.destination,
        type: typeof attrs.type === "string" ? attrs.type : "permanent",
      };
    })
    .filter(Boolean) as RedirectRule[];
}

async function fetchRedirects(): Promise<RedirectRule[]> {
  const now = Date.now();
  if (cachedRedirects !== null && now < cacheExpiry) {
    return cachedRedirects;
  }
  try {
    const all: RedirectRule[] = [];
    let page = 1;
    let pageCount = 1;
    while (page <= pageCount && page <= MAX_PAGES) {
      const url =
        `${STRAPI_BASE}/api/redirects?${REDIRECTS_QUERY}` +
        `&pagination[page]=${page}&pagination[pageSize]=${PAGE_SIZE}`;
      const res = await fetch(url, {
        next: { revalidate: 120 },
        headers: { Accept: "application/json" },
      });
      if (!res.ok) {
        // On any failure, return whatever we already collected, or fall back to last good cache
        if (all.length > 0) break;
        return cachedRedirects ?? [];
      }
      const json = await res.json();
      const items = parseRedirectItems(json?.data);
      all.push(...items);

      // Use Strapi's pagination meta to drive the loop; bail out on the last page
      // or if the response was short (defensive - no infinite loop).
      const meta = json?.meta?.pagination;
      if (meta && typeof meta.pageCount === "number" && meta.pageCount > 0) {
        pageCount = meta.pageCount;
      } else {
        // No meta -> stop once a partial page comes back
        if (items.length < PAGE_SIZE) break;
      }
      page += 1;
    }
    cachedRedirects = all;
    cacheExpiry = now + CACHE_TTL_MS;
    return all;
  } catch {
    return cachedRedirects ?? [];
  }
}

function shouldSkipRedirect(pathname: string): boolean {
  if (pathname.startsWith("/_next/static")) return true;
  if (pathname.startsWith("/_next/image")) return true;
  if (pathname === "/favicon.ico") return true;
  if (pathname.startsWith("/api")) return true;
  return false;
}

function statusFromType(type: string): 301 | 302 {
  return type === "temporary" ? 302 : 301;
}

/**
 * Runs redirect logic for the request. Call from middleware (Edge) or Node route handler.
 * Returns a NextResponse.redirect() when a rule matches, otherwise null.
 */
export default async function proxy(
  request: NextRequest
): Promise<NextResponse | null> {
  const pathname = request.nextUrl.pathname;
  if (shouldSkipRedirect(pathname)) return null;

  try {
    const redirects = await fetchRedirects();
    for (const rule of redirects) {
      const source = rule.source.replace(/\/$/, "") || "/";
      const pathNormalized = pathname.replace(/\/$/, "") || "/";
      if (pathNormalized !== source) continue;
      const status = statusFromType(rule.type);
      const destination = rule.destination.startsWith("http")
        ? rule.destination
        : new URL(rule.destination, request.url).toString();
      return NextResponse.redirect(destination, status);
    }
  } catch {
    // Fail silently; let the request continue
  }
  return null;
}
