import { fetchBaseQuery, type BaseQueryFn } from "@reduxjs/toolkit/query/react";
import type { FetchArgs, FetchBaseQueryError } from "@reduxjs/toolkit/query";
import { resolveSessionContext } from "../session";

/**
 * The one place the backend URL is resolved: VITE_BASE_API_URL from the env,
 * falling back to the local dev API (3001 — the portal itself owns 3000 for
 * the Fayda redirect). Import this; do not re-derive it.
 */
export const BASE_API_URL =
  (import.meta as { env?: Record<string, string> }).env?.[
    "VITE_BASE_API_URL"
  ]?.trim() || "http://localhost:3000/api";

let _onTokenExpired: (() => Promise<string>) | null = null;
let _onAuthFailure: (() => void) | null = null;

export function configureTokenRefresh(config: {
  onTokenExpired: () => Promise<string>;
  onAuthFailure: () => void;
}) {
  _onTokenExpired = config.onTokenExpired;
  _onAuthFailure = config.onAuthFailure;
}

export const baseQueryWithReauth: BaseQueryFn<
  string | FetchArgs,
  unknown,
  FetchBaseQueryError
> = async (args, api, extraOptions) => {
  const baseQuery = fetchBaseQuery({
    baseUrl: BASE_API_URL,
    prepareHeaders: (headers) => {
      const { token, sessionHeaders } = resolveSessionContext(
        api.getState() as { auth?: { token?: string } },
      );
      if (token) headers.set("Authorization", `Bearer ${token}`);
      Object.entries(sessionHeaders).forEach(([k, v]) => headers.set(k, v));
      return headers;
    },
  });

  let result = await baseQuery(args, api, extraOptions);

  if (result.error?.status === 401) {
    if (_onTokenExpired) {
      try {
        await _onTokenExpired();
        result = await baseQuery(args, api, extraOptions);
      } catch (err) {
        // Only a rejected refresh token ends the session. A network blip or a
        // 5xx leaves the original 401 for the screen to report, rather than
        // throwing the user out of a session that is still valid.
        if ((err as { sessionExpired?: boolean })?.sessionExpired) {
          _onAuthFailure?.();
        }
      }
    } else {
      _onAuthFailure?.();
    }
  }

  return result;
};
