import axios, { type AxiosError, type InternalAxiosRequestConfig } from 'axios'
import { useAuthStore } from '@/stores/auth-store'

export interface ApiResponse<T> {
  code: number
  message: string
  data: T
}

interface RefreshResult {
  access_token: string
  refresh_token: string
}

interface RetryableRequest extends InternalAxiosRequestConfig {
  _retry?: boolean
}

export const api = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '',
  timeout: 15_000,
})

api.interceptors.request.use((config) => {
  const token = useAuthStore.getState().auth.accessToken
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

let refreshRequest: Promise<RefreshResult> | null = null

api.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const request = error.config as RetryableRequest | undefined
    const auth = useAuthStore.getState().auth
    const isAuthRequest = request?.url?.startsWith('/auth/')

    if (
      error.response?.status !== 401 ||
      !request ||
      request._retry ||
      isAuthRequest ||
      !auth.refreshToken
    ) {
      return Promise.reject(error)
    }

    request._retry = true
    refreshRequest ??= axios
      .post<ApiResponse<RefreshResult>>(
        `${api.defaults.baseURL || ''}/auth/refresh`,
        { refresh_token: auth.refreshToken }
      )
      .then((response) => response.data.data)
      .finally(() => {
        refreshRequest = null
      })

    try {
      const tokens = await refreshRequest
      auth.setTokens(tokens.access_token, tokens.refresh_token)
      request.headers.Authorization = `Bearer ${tokens.access_token}`
      return api(request)
    } catch (refreshError) {
      auth.reset()
      return Promise.reject(refreshError)
    }
  }
)
