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

export const TOKEN_KEY = 'solution-erp-user-token'
export const REFRESH_KEY = 'solution-erp-user-refresh'
export const USER_KEY = 'solution-erp-user-user'

// Dev: Vite proxy /api → :5443 (vite.config.ts)
// Prod: VITE_API_BASE_URL = https://api.solutions.com.vn (env.production)
const BASE_URL = (import.meta.env.VITE_API_BASE_URL ?? '') + '/api'

export const api = axios.create({
  baseURL: BASE_URL,
  timeout: 30000,
})

api.interceptors.request.use(config => {
  const token = localStorage.getItem(TOKEN_KEY)
  if (token) config.headers.Authorization = `Bearer ${token}`
  return config
})

type QueueItem = {
  resolve: (value: unknown) => void
  reject: (reason?: unknown) => void
  config: InternalAxiosRequestConfig
}

let isRefreshing = false
let queue: QueueItem[] = []

function processQueue(error: unknown, token: string | null) {
  queue.forEach(({ resolve, reject, config }) => {
    if (error || !token) {
      reject(error)
    } else {
      config.headers.Authorization = `Bearer ${token}`
      resolve(api(config))
    }
  })
  queue = []
}

function redirectLogin() {
  localStorage.removeItem(TOKEN_KEY)
  localStorage.removeItem(REFRESH_KEY)
  localStorage.removeItem(USER_KEY)
  if (!window.location.pathname.startsWith('/login')) {
    window.location.href = '/login'
  }
}

api.interceptors.response.use(
  response => response,
  async (error: AxiosError) => {
    const original = error.config as InternalAxiosRequestConfig & { _retry?: boolean }

    if (error.response?.status !== 401 || !original || original._retry) {
      return Promise.reject(error)
    }

    if (original.url?.includes('/auth/login') || original.url?.includes('/auth/refresh')) {
      redirectLogin()
      return Promise.reject(error)
    }

    original._retry = true
    const refreshToken = localStorage.getItem(REFRESH_KEY)
    if (!refreshToken) {
      redirectLogin()
      return Promise.reject(error)
    }

    if (isRefreshing) {
      return new Promise((resolve, reject) => {
        queue.push({ resolve, reject, config: original })
      })
    }

    isRefreshing = true
    try {
      const res = await axios.post<{ accessToken: string; refreshToken: string }>(
        '/api/auth/refresh',
        { refreshToken },
      )
      const newToken = res.data.accessToken
      localStorage.setItem(TOKEN_KEY, newToken)
      localStorage.setItem(REFRESH_KEY, res.data.refreshToken)
      processQueue(null, newToken)
      original.headers.Authorization = `Bearer ${newToken}`
      return api(original)
    } catch (refreshErr) {
      processQueue(refreshErr, null)
      redirectLogin()
      return Promise.reject(refreshErr)
    } finally {
      isRefreshing = false
    }
  },
)
