import axios from 'axios';

interface AuthResponse {
  user: { id: string; email: string; name: string; role: string };
  accessToken?: string;
  refreshToken?: string;
}

export const api = axios.create({
  baseURL: '/api',
});

// Token accessor — set by auth store on init
let getTokens: () => { accessToken: string | null; refreshToken: string | null } = () => ({
  accessToken: null,
  refreshToken: null,
});
let onTokenRefresh: (accessToken: string, refreshToken: string) => void = () => {};
let onAuthFailure: () => void = () => {};

export function registerAuthCallbacks(callbacks: {
  getTokens: typeof getTokens;
  onTokenRefresh: typeof onTokenRefresh;
  onAuthFailure: typeof onAuthFailure;
}) {
  getTokens = callbacks.getTokens;
  onTokenRefresh = callbacks.onTokenRefresh;
  onAuthFailure = callbacks.onAuthFailure;
}

// Request interceptor: attach access token
api.interceptors.request.use((config) => {
  const { accessToken } = getTokens();
  if (accessToken) {
    config.headers.Authorization = `Bearer ${accessToken}`;
  }
  return config;
});

// Response interceptor: handle 401 with token refresh
let refreshPromise: Promise<AuthResponse> | null = null;

api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    const errorCode = error.response?.data?.error?.code;

    // Skip retry logic for the refresh endpoint itself to avoid circular await deadlock
    const isRefreshRequest = originalRequest.url?.includes('/auth/refresh');

    if (
      error.response?.status === 401 &&
      (errorCode === 'INVALID_TOKEN' || errorCode === 'AUTH_REQUIRED') &&
      !originalRequest._retry &&
      !isRefreshRequest
    ) {
      originalRequest._retry = true;

      const { refreshToken } = getTokens();
      if (!refreshToken) {
        onAuthFailure();
        return Promise.reject(error);
      }

      try {
        if (!refreshPromise) {
          refreshPromise = api
            .post<AuthResponse>('/auth/refresh', { refreshToken })
            .then((res) => res.data)
            .finally(() => {
              refreshPromise = null;
            });
        }

        const data = await refreshPromise;
        if (!data.accessToken || !data.refreshToken) {
          onAuthFailure();
          return Promise.reject(new Error('Missing tokens in refresh response'));
        }
        onTokenRefresh(data.accessToken, data.refreshToken);
        originalRequest.headers.Authorization = `Bearer ${data.accessToken}`;
        return api(originalRequest);
      } catch {
        onAuthFailure();
        return Promise.reject(error);
      }
    }

    return Promise.reject(error);
  }
);
