import { PUBLIC_API_URL } from "$env/static/public";
import { browser } from "$app/environment";
import { goto } from "$app/navigation";
import axios, { AxiosInstance, type InternalAxiosRequestConfig } from "axios";

const api: AxiosInstance = axios.create({
  baseURL: PUBLIC_API_URL || "",
});

// ── Client-side 401 refresh interceptor ──────────────────────────────────────
// Only runs in the browser. On a 401 from the external API, we ask our own
// SvelteKit server for a fresh token (the server hook handles the actual
// refresh), then retry the original request once.  Multiple concurrent 401s
// are queued so only one refresh call is made.
if (browser) {
  let isRefreshing = false;
  let queue: Array<(token: string) => void> = [];

  function drainQueue(token: string) {
    queue.forEach((cb) => cb(token));
    queue = [];
  }

  async function fetchFreshToken(): Promise<string> {
    const res = await fetch("/api/auth/refresh");
    if (!res.ok) {
      // Truly unauthenticated — send to login
      goto("/login");
      throw new Error("Session expired");
    }
    const data = await res.json();
    return data.accessToken as string;
  }

  api.interceptors.response.use(
    (response) => response,
    async (error) => {
      const original: InternalAxiosRequestConfig & { _retry?: boolean } =
        error.config;

      const isExpired =
        error.response?.data?.error === "ExpiredAccessTokenError";

      if (!isExpired || original._retry) {
        return Promise.reject(error);
      }

      // Mark so we don't retry more than once
      original._retry = true;

      if (isRefreshing) {
        // Another request is already refreshing — wait for it
        return new Promise((resolve, reject) => {
          queue.push((token) => {
            original.headers["Authorization"] = `Bearer ${token}`;
            resolve(api(original));
          });
        });
      }

      isRefreshing = true;
      try {
        const token = await fetchFreshToken();
        original.headers["Authorization"] = `Bearer ${token}`;
        drainQueue(token);
        return api(original);
      } catch (refreshError) {
        queue = [];
        return Promise.reject(refreshError);
      } finally {
        isRefreshing = false;
      }
    },
  );
}

export { api };
export default api;
