/* eslint-disable import/prefer-default-export */
import axios, { AxiosRequestConfig, AxiosResponse, Method, ResponseType } from 'axios'

interface CallAxiosAPI {
  url: string
  method: Method
  data?: any
  headers?: any
  params?: string
  useV2?: boolean
  contentType?: string
  responseType?: ResponseType
  onUploadProgress?: (progressEvent: any) => void
}

const baseUrl = import.meta.env.VITE_APP_API_URL

// Prevent multiple refresh calls
let refreshPromise: Promise<any> | null = null

const refreshTokenRequest = async () => {
  if (!refreshPromise) {
    refreshPromise = axios
      .post(`${baseUrl}auth/refresh`, {}, { withCredentials: true })
      .catch((err) => {
        const msg = err.response?.data?.message
        if (
          err.response?.status === 401 &&
          (msg === 'refresh_token_expired' || msg === 'invalid_refresh_token' || msg === 'refresh_token_not_found')
        ) {
          window.location.href = '/login'
        }
        throw err
      })
      .finally(() => {
        refreshPromise = null
      })
  }

  return refreshPromise
}

export const useAxios = async ({
  url,
  method,
  data,
  headers,
  contentType,
  useV2,
  params,
  responseType,
  onUploadProgress,
}: CallAxiosAPI): Promise<AxiosResponse<any>> => {
  let hasRetried = false
  const config: AxiosRequestConfig = {
    method: method || 'GET',
    url: `${baseUrl}${useV2 ? 'v2/' : ''}${url}`,
    headers: {
      'Content-Type': contentType || 'application/json',
      ...headers,
    },
    withCredentials: true,
    data,
    params,
    responseType,
    onUploadProgress,
  }

  try {
    return await axios(config)
  } catch (error: any) {
    const isUnauthenticated = error?.response?.status === 401
    const responseData = error?.response?.data

    // For "download/export" endpoints Axios often receives error payloads as a Blob.
    // We only normalize when it's a Blob; for non-Blob responses we keep existing behavior.
    let serverMessage: string | undefined = responseData?.message

    if (typeof Blob !== 'undefined' && responseData instanceof Blob) {
      try {
        const text = await responseData.text()
        const parsed = JSON.parse(text)
        serverMessage = parsed?.message ?? parsed?.data?.message
      } catch {
        // If it's not valid JSON, fall back to the default error message below.
      }
    }

    const shouldRefresh = isUnauthenticated && serverMessage === 'access_token_expired'
    const shouldLogout = serverMessage === 'Session expired. Please login again.'

    const NO_LOGOUT_APIS = ['user-info', 'discount-count', 'translations']
    const skipLogout = NO_LOGOUT_APIS.some((api) => url.includes(api))

    if (isUnauthenticated && shouldRefresh) {
      try {
        hasRetried = true
        await refreshTokenRequest()
        return await axios(config)
      } catch {
        throw new Error('Session expired. Please log in again.')
      }
    }

    if (isUnauthenticated && shouldLogout && !skipLogout) {
      window.location.href = '/login'
    }

    throw new Error(serverMessage || error.response?.data?.message || error.message || 'Request failed')
  }
}
