import axios, { AxiosError } from 'axios'
import type { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios'
import { useAuthStore } from '@/stores/authStore'

const API_URL = import.meta.env['VITE_API_URL'] ?? 'http://localhost:5212'

export const axiosClient = axios.create({
  baseURL: API_URL,
  headers: { 'Content-Type': 'application/json' },
})

// --- Request interceptor: attach Bearer from authStore
axiosClient.interceptors.request.use((config: InternalAxiosRequestConfig) => {
  const token = useAuthStore.getState().accessToken
  if (token && !config.headers.Authorization) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

// --- Singleton promise queue for refresh
// N concurrent 401s share the same refresh promise — only ONE call to /auth/refresh
let refreshPromise: Promise<string> | null = null

async function performRefresh(): Promise<string> {
  const { refreshToken, accessToken, updateAccess, clearAuth } = useAuthStore.getState()
  if (!refreshToken || !accessToken) {
    clearAuth()
    throw new Error('no tokens available for refresh')
  }
  try {
    // IMPORTANT: use plain axios, NOT axiosClient, to avoid the response interceptor loop
    const res = await axios.post<{ accessToken: string; refreshToken: string; expiresIn: number }>(
      `${API_URL}/api/v1/auth/refresh`,
      { accessToken, refreshToken },
      { headers: { 'Content-Type': 'application/json' } },
    )
    const { accessToken: newAccess, refreshToken: newRefresh, expiresIn } = res.data
    updateAccess(newAccess, newRefresh, Date.now() + expiresIn * 1000)
    return newAccess
  } catch (e) {
    clearAuth()
    if (typeof window !== 'undefined') {
      window.location.assign('/login')
    }
    throw e
  }
}

interface RetryConfig extends AxiosRequestConfig {
  _retry?: boolean
}

// --- Response interceptor: handle 401 with token refresh
axiosClient.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const original = error.config as RetryConfig | undefined
    const status = error.response?.status
    const url = original?.url ?? ''

    // Only attempt refresh for 401s on non-auth endpoints
    if (
      status !== 401 ||
      !original ||
      original._retry ||
      url.endsWith('/auth/refresh') ||
      url.endsWith('/auth/login')
    ) {
      return Promise.reject(error)
    }

    original._retry = true

    try {
      // Singleton: if refresh is already in flight, await the same promise
      if (refreshPromise === null) {
        refreshPromise = performRefresh().finally(() => {
          refreshPromise = null
        })
      }
      const newAccess = await refreshPromise

      // Retry original request with new token
      original.headers = original.headers ?? {}
      ;(original.headers as Record<string, string>).Authorization = `Bearer ${newAccess}`
      return axiosClient(original)
    } catch (e) {
      return Promise.reject(e)
    }
  },
)
