import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, Canceler } from 'axios'

const pendingRequests = new Map<string, Canceler>()

function buildRequestKey(config: AxiosRequestConfig) {
  const { method, url, params, data } = config
  const paramsString = params ? JSON.stringify(params) : ''
  const dataString = data ? JSON.stringify(data) : ''
  return [method, url, paramsString, dataString].join('&')
}

function addPendingRequest(config: AxiosRequestConfig) {
  const requestKey = buildRequestKey(config)
  if (pendingRequests.has(requestKey)) {
    const cancel = pendingRequests.get(requestKey)
    cancel?.(`取消重复请求：${requestKey}`)
  }
  config.cancelToken = new axios.CancelToken((cancel) => {
    pendingRequests.set(requestKey, cancel)
  })
}

function removePendingRequest(config: AxiosRequestConfig) {
  const requestKey = buildRequestKey(config)
  if (pendingRequests.has(requestKey)) {
    pendingRequests.delete(requestKey)
  }
}

const http: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
  withCredentials: true,
})

http.interceptors.request.use(
  (config) => {
    if (config) {
      removePendingRequest(config)
      addPendingRequest(config)
    }

    const token = localStorage.getItem('auth_token')
    if (token && config.headers) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

http.interceptors.response.use(
  (response: AxiosResponse) => {
    removePendingRequest(response.config)

    const { status, data } = response
    if (status === 200) {
      return data
    }

    if (status === 204) {
      return data || null
    }

    if (status === 401) {
      localStorage.removeItem('auth_token')
      localStorage.removeItem('auth_user')
      return Promise.reject(new Error('未授权，请重新登录'))
    }

    if (status === 403) {
      return Promise.reject(new Error('无权访问，权限不足'))
    }

    const message = data?.message || response.statusText || '请求失败'
    return Promise.reject(new Error(`HTTP ${status}：${message}`))
  },
  (error: AxiosError) => {
    if (axios.isCancel(error)) {
      return Promise.reject(new Error(error.message || '请求已取消'))
    }

    if (error.response) {
      const { status, data } = error.response
      const statusMessageMap: Record<number, string> = {
        400: '请求参数错误',
        401: '未授权，请重新登录',
        403: '无权访问，权限不足',
        404: '请求地址不存在',
        500: '服务器内部错误',
        502: '网关错误',
        503: '服务不可用',
        504: '网关超时',
      }
      const message = (data as any)?.message || statusMessageMap[status] || error.message || '请求失败'
      return Promise.reject(new Error(`HTTP ${status}：${message}`))
    }

    return Promise.reject(new Error(error.message || '网络错误'))
  }
)

export interface HttpRequestConfig<T = any> extends AxiosRequestConfig<T> {
  showLoading?: boolean
}

export function get<T = any>(url: string, config?: HttpRequestConfig) {
  return http.get<T, T>(url, config)
}

export function post<T = any>(url: string, data?: unknown, config?: HttpRequestConfig) {
  return http.post<T, T>(url, data, config)
}

export function put<T = any>(url: string, data?: unknown, config?: HttpRequestConfig) {
  return http.put<T, T>(url, data, config)
}

export function del<T = any>(url: string, config?: HttpRequestConfig) {
  return http.delete<T, T>(url, config)
}

export function request<T = any>(config: HttpRequestConfig): Promise<T>
export function request<T = any>(url: string, config?: HttpRequestConfig): Promise<T>
export function request<T = any>(urlOrConfig: string | HttpRequestConfig, config?: HttpRequestConfig) {
  if (typeof urlOrConfig === 'string') {
    const cfg = Object.assign({}, config || {}, { url: urlOrConfig }) as AxiosRequestConfig
    return http.request<T, T>(cfg)
  }
  return http.request<T, T>(urlOrConfig)
}

export default http
