/**
 * Client Axios base con interceptor per refresh token silenzioso.
 * 
 * Flusso:
 * 1. Ogni richiesta include il Bearer token dall'auth store
 * 2. Se la risposta è 401, tenta il refresh silenzioso
 * 3. Se il refresh fallisce, fa logout e redirige a /login
 */

import axios, { AxiosError, InternalAxiosRequestConfig } from 'axios'

const BASE_URL = '/api/v1'

// Flag per evitare loop infiniti di refresh
let isRefreshing = false
let pendingRequests: Array<(token: string) => void> = []

function processPendingRequests(token: string) {
  pendingRequests.forEach((cb) => cb(token))
  pendingRequests = []
}

export const apiClient = axios.create({
  baseURL: BASE_URL,
  headers: {
    'Content-Type': 'application/json',
  },
  timeout: 30000,
})

// ─── Request Interceptor: inietta access token ────────────────────────────────
apiClient.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // Legge il token dallo storage (evita dipendenza circolare con lo store)
    const token = localStorage.getItem('access_token')
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => Promise.reject(error),
)

// ─── Response Interceptor: gestisce 401 con refresh silenzioso ───────────────
apiClient.interceptors.response.use(
  (response) => response,
  async (error: AxiosError) => {
    const originalRequest = error.config as InternalAxiosRequestConfig & {
      _retry?: boolean
    }

    // Salta il refresh per l'endpoint di login e refresh stesso
    const skipRefresh = ['/auth/login', '/auth/refresh'].some((path) =>
      originalRequest.url?.includes(path),
    )

    if (error.response?.status === 401 && !originalRequest._retry && !skipRefresh) {
      originalRequest._retry = true

      if (isRefreshing) {
        // Accoda la richiesta in attesa del nuovo token
        return new Promise((resolve) => {
          pendingRequests.push((token: string) => {
            if (originalRequest.headers) {
              originalRequest.headers.Authorization = `Bearer ${token}`
            }
            resolve(apiClient(originalRequest))
          })
        })
      }

      isRefreshing = true
      const refreshToken = localStorage.getItem('refresh_token')

      if (!refreshToken) {
        // Nessun refresh token: logout
        handleLogout()
        return Promise.reject(error)
      }

      try {
        const { data } = await axios.post(`${BASE_URL}/auth/refresh`, {
          refresh_token: refreshToken,
        })

        const newAccessToken = data.access_token
        const newRefreshToken = data.refresh_token

        localStorage.setItem('access_token', newAccessToken)
        localStorage.setItem('refresh_token', newRefreshToken)

        processPendingRequests(newAccessToken)

        if (originalRequest.headers) {
          originalRequest.headers.Authorization = `Bearer ${newAccessToken}`
        }
        return apiClient(originalRequest)
      } catch {
        handleLogout()
        return Promise.reject(error)
      } finally {
        isRefreshing = false
      }
    }

    return Promise.reject(error)
  },
)

function handleLogout() {
  localStorage.removeItem('access_token')
  localStorage.removeItem('refresh_token')
  localStorage.removeItem('user')
  // Redirect alla pagina di login
  window.location.href = '/login'
}

/**
 * Estrae il messaggio di errore leggibile da un AxiosError.
 */
export function getErrorMessage(error: unknown): string {
  if (axios.isAxiosError(error)) {
    const detail = error.response?.data?.detail
    if (typeof detail === 'string') return detail
    if (Array.isArray(detail)) {
      return detail.map((d) => d.msg || d).join(', ')
    }
    if (error.response?.status === 404) return 'Risorsa non trovata'
    if (error.response?.status === 403) return 'Accesso non autorizzato'
    if (error.response?.status === 500) return 'Errore interno del server'
    return error.message || 'Errore di rete'
  }
  if (error instanceof Error) return error.message
  return 'Errore sconosciuto'
}

export default apiClient
