import {
  BaseQueryFn,
  FetchArgs,
  fetchBaseQuery,
  FetchBaseQueryError,
} from "@reduxjs/toolkit/query";
import { AppConstants } from "./app-constants";
import { isTokenValid } from "../utils/decodeToken";
import { clearAuthStorage, getStoredToken } from "../utils/storage";

const PUBLIC_AUTH_PATHS = [
  "/auth/login",
  "/auth/forgot-password",
  "/auth/reset-password",
  "/auth/verify-email",
  "/auth/accept-invite",
  "/auth/bootstrap",
];

function isPublicEndpoint(url: string | undefined, method: string | undefined): boolean {
  if (!url) return false;
  const m = method?.toUpperCase();
  // Guest submission endpoints: only the POST is public, not the admin list/PATCH/DELETE.
  if (m === "POST" && (url.endsWith("/reservations") || url === "/reservations")) {
    return true;
  }
  if (m === "POST" && (url.endsWith("/contact") || url === "/contact")) {
    return true;
  }
  return PUBLIC_AUTH_PATHS.some((p) => url.startsWith(p));
}

function isAdminRoute(): boolean {
  if (typeof window === "undefined") return false;
  return window.location.pathname.startsWith("/admin");
}

function redirectToLogin(): void {
  if (typeof window === "undefined") return;
  const next = encodeURIComponent(window.location.pathname + window.location.search);
  window.location.href = `${AppConstants.adminLoginPath}?next=${next}`;
}

const rawBaseQuery = fetchBaseQuery({
  baseUrl: AppConstants.baseUrl,
  credentials: "include",
  prepareHeaders: (headers) => {
    const token = getStoredToken();
    if (token) headers.set("Authorization", `Bearer ${token}`);
    return headers;
  },
});

export const baseQueryWithAuth: BaseQueryFn<
  string | FetchArgs,
  unknown,
  FetchBaseQueryError
> = async (args, api, extraOptions) => {
  const url = typeof args === "string" ? args : args.url;
  const method = typeof args === "string" ? "GET" : args.method ?? "GET";
  const isPublic = isPublicEndpoint(url, method);

  if (!isPublic) {
    const token = getStoredToken();
    if (!token || !isTokenValid(token)) {
      clearAuthStorage();
      if (isAdminRoute()) redirectToLogin();
      return {
        error: {
          status: 401,
          data: {
            success: false,
            error: { code: "unauthorized", message: "Session expired" },
          },
        } as FetchBaseQueryError,
      };
    }
  }

  const result = await rawBaseQuery(args, api, extraOptions);

  if (
    result.error &&
    result.error.status === 401 &&
    !isPublic &&
    isAdminRoute()
  ) {
    clearAuthStorage();
    redirectToLogin();
  }

  // Unwrap the standard API envelope { success: true, data: <payload> } → <payload>
  if (
    result.data != null &&
    typeof result.data === "object" &&
    "success" in (result.data as object) &&
    "data" in (result.data as object)
  ) {
    return {
      ...result,
      data: (result.data as { success: boolean; data: unknown }).data,
    };
  }

  return result;
};
