import axios from 'axios';
import type { AuthResponse } from '@/types/api';

export const api = axios.create({
  baseURL: '/api',
  withCredentials: true, // Send httpOnly cookies with all requests
});

// Token accessor — set by auth store on init to break circular dependency
let getAccessToken: () => string | null = () => null;
let onTokenRefresh: (accessToken: string) => void = () => {};
let onAuthFailure: () => void = () => {};

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

// Helper to get current callbacks (for use in other API clients)
export function getAuthCallbacks() {
  return { getAccessToken, onTokenRefresh, onAuthFailure };
}

// Request interceptor: attach access token
api.interceptors.request.use((config) => {
  const accessToken = getAccessToken();
  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;

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

      try {
        if (!refreshPromise) {
          // Refresh token sent automatically as httpOnly cookie
          refreshPromise = api
            .post<AuthResponse>('/auth/refresh')
            .then((res) => res.data)
            .finally(() => {
              refreshPromise = null;
            });
        }

        const data = await refreshPromise;
        onTokenRefresh(data.accessToken!);

        originalRequest.headers.Authorization = `Bearer ${data.accessToken}`;
        return api(originalRequest);
      } catch {
        onAuthFailure();
        return Promise.reject(error);
      }
    }

    return Promise.reject(error);
  }
);
