// The Lucia project.
// Copyright 2023-2026 DSP, inc.  All rights reserved.
// Authors:
//   imacat.yang@dsp.im (imacat), 2023/9/23
/**
 * @module apiClient Centralized axios instance with request/response
 *   interceptors for authentication token management and automatic
 *   401 token refresh with request queuing.
 */

import axios from "axios";
import { getCookie, deleteCookie } from "@/utils/cookieUtil.js";

/** Axios instance configured with auth interceptors. */
const apiClient = axios.create();

// Request interceptor: automatically attach Authorization header
apiClient.interceptors.request.use((config) => {
  const token = getCookie("luciaToken");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Response interceptor: handle 401 by attempting token refresh
let isRefreshing = false;
let pendingRequests = [];

/**
 * Resolves all pending requests with the new access token.
 * @param {string} newToken - The refreshed access token.
 */
function onRefreshSuccess(newToken) {
  pendingRequests.forEach((cb) => cb(newToken));
  pendingRequests = [];
}

/**
 * Rejects all pending requests with the refresh error.
 * @param {Error} error - The token refresh error.
 */
function onRefreshFailure(error) {
  pendingRequests.forEach((cb) => cb(null, error));
  pendingRequests = [];
}

apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;

    // Only attempt refresh on 401, and not for auth endpoints or already-retried requests
    if (
      error.response?.status !== 401 ||
      originalRequest._retried ||
      originalRequest.url === "/api/oauth/token"
    ) {
      throw error;
    }

    if (isRefreshing) {
      // Queue this request until the refresh completes
      return new Promise((resolve, reject) => {
        pendingRequests.push((newToken, err) => {
          if (err) return reject(err);
          originalRequest.headers.Authorization = `Bearer ${newToken}`;
          originalRequest._retried = true;
          resolve(apiClient(originalRequest));
        });
      });
    }

    isRefreshing = true;
    originalRequest._retried = true;

    try {
      // Dynamic import to avoid circular dependency with login store
      const { refreshTokenAndGetNew } = await import("@/api/auth.js");
      const newToken = await refreshTokenAndGetNew();
      isRefreshing = false;
      onRefreshSuccess(newToken);
      originalRequest.headers.Authorization = `Bearer ${newToken}`;
      return apiClient(originalRequest);
    } catch (refreshError) {
      isRefreshing = false;
      onRefreshFailure(refreshError);

      // Refresh failed: clear auth and redirect to login
      deleteCookie("luciaToken");
      deleteCookie("luciaRefreshToken");
      deleteCookie("isLuciaLoggedIn");
      globalThis.location.href = "/login";
      throw refreshError;
    }
  },
);

export default apiClient;
