export default function ({ $axios, store, $db }) {
  // Track if we're currently refreshing to prevent multiple refresh attempts
  let isRefreshing = false
  let failedQueue = []

  const processQueue = (error, token = null) => {
    failedQueue.forEach(({ resolve, reject }) => {
      if (error) {
        reject(error)
      } else {
        resolve(token)
      }
    })
    failedQueue = []
  }

  /**
   * Handles the case when token refresh fails
   * @param {string} [serverConnectionConfigId]
   * @returns {Promise} - Promise that resolves when logout is complete
   */
  const handleRefreshFailure = async (serverConnectionConfigId) => {
    try {
      console.log('[axios] Handling refresh failure - logging out user')

      // Clear store
      await store.dispatch('user/logout')

      if (serverConnectionConfigId) {
        // Clear refresh token for server connection config
        await $db.clearRefreshToken(serverConnectionConfigId)
      }

      if (window.location.pathname !== '/connect') {
        window.location.href = '/connect'
      }
    } catch (error) {
      console.error('[axios] Failed to handle refresh failure:', error)
    }
  }

  $axios.onRequest((config) => {
    console.log('[Axios] Making request to ' + config.url)
    if (config.url.startsWith('http:') || config.url.startsWith('https:') || config.url.startsWith('capacitor:')) {
      return
    }

    const bearerToken = store.getters['user/getToken']
    if (bearerToken) {
      config.headers.common['Authorization'] = `Bearer ${bearerToken}`
    } else {
      console.warn('[Axios] No Bearer Token for request')
    }

    const serverUrl = store.getters['user/getServerAddress']
    if (serverUrl) {
      config.url = `${serverUrl}${config.url}`
    }
    console.log('[Axios] Request out', config.url)
  })

  $axios.onError(async (error) => {
    const originalRequest = error.config
    const code = parseInt(error.response && error.response.status)
    const message = error.response ? error.response.data || 'Unknown Error' : 'Unknown Error'

    console.error('Axios error', code, message)

    // Handle 401 Unauthorized (token expired)
    if (code === 401 && !originalRequest._retry) {
      // Skip refresh for auth endpoints to prevent infinite loops
      if (originalRequest.url.endsWith('/auth/refresh') || originalRequest.url.endsWith('/login')) {
        await handleRefreshFailure(store.getters['user/getServerConnectionConfigId'])
        return Promise.reject(error)
      }

      if (isRefreshing) {
        // If already refreshing, queue this request
        return new Promise((resolve, reject) => {
          failedQueue.push({ resolve, reject })
        })
          .then((token) => {
            if (!originalRequest.headers) {
              originalRequest.headers = {}
            }
            originalRequest.headers['Authorization'] = `Bearer ${token}`
            return $axios(originalRequest)
          })
          .catch((err) => {
            return Promise.reject(err)
          })
      }

      originalRequest._retry = true
      isRefreshing = true

      try {
        // Attempt to refresh the token
        // Updates store if successful, otherwise clears store and throw error
        const newAccessToken = await store.dispatch('user/refreshToken')
        if (!newAccessToken) {
          console.error('No new access token received')
          return Promise.reject(error)
        }

        // Update the original request with new token
        if (!originalRequest.headers) {
          originalRequest.headers = {}
        }
        originalRequest.headers['Authorization'] = `Bearer ${newAccessToken}`

        // Process any queued requests
        processQueue(null, newAccessToken)

        // Retry the original request
        return $axios(originalRequest)
      } catch (refreshError) {
        console.error('Token refresh failed:', refreshError)

        // Process queued requests with error
        processQueue(refreshError, null)

        await handleRefreshFailure(store.getters['user/getServerConnectionConfigId'])

        return Promise.reject(refreshError)
      } finally {
        isRefreshing = false
      }
    }

    return Promise.reject(error)
  })
}
