/**
 * HTTP 请求封装模块
 * 基于 Axios 封装的 HTTP 请求工具，提供统一的请求/响应处理
 *
 * ## 主要功能
 *
 * - 请求/响应拦截器（自动添加 Token、统一错误处理）
 * - 401 未授权自动登出（带防抖机制）
 * - 请求失败自动重试（可配置）
 * - 统一的成功/错误消息提示
 * - 支持 GET/POST/PUT/DELETE 等常用方法
 *
 * @module utils/http
 * @author Art Design Pro Team
 */

import axios, { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import JSONBig from 'json-bigint'
import { useUserStore } from '@/store/modules/user'
import { ApiStatus } from './status'
import { ErrorResponse, HttpError, handleError, showSuccess } from './error'
import { handleHttpError } from '@/utils/errorHandler'
import { $t } from '@/locales'
import { BaseResponse } from '@/types'
import { StorageConfig } from '@/utils/storage'

/** 请求配置常量 */
const REQUEST_TIMEOUT = 15000
const LOGOUT_DELAY = 500
const MAX_RETRIES = 0
const RETRY_DELAY = 1000
const UNAUTHORIZED_DEBOUNCE_TIME = 3000

/** 401防抖状态 */
let isUnauthorizedErrorShown = false
let unauthorizedTimer: NodeJS.Timeout | null = null

/** 扩展 AxiosRequestConfig */
interface ExtendedAxiosRequestConfig extends AxiosRequestConfig {
  showErrorMessage?: boolean
  showSuccessMessage?: boolean
  skipTenantHeader?: boolean
}

const { VITE_API_URL, VITE_WITH_CREDENTIALS } = import.meta.env
const jsonBigParser = JSONBig({ storeAsString: true })

/** Axios实例 */
const axiosInstance = axios.create({
  timeout: REQUEST_TIMEOUT,
  baseURL: VITE_API_URL,
  withCredentials: VITE_WITH_CREDENTIALS === 'true',
  validateStatus: (status) => status >= 200 && status < 300,
  transformResponse: [
    (data, headers) => {
      const contentType = headers['content-type']
      if (contentType?.includes('application/json')) {
        try {
          // 1. 使用 json-bigint 解析，避免 Snowflake 等长整型精度丢失
          return jsonBigParser.parse(data)
        } catch {
          return data
        }
      }
      return data
    }
  ]
})

/** 请求拦截器 */
axiosInstance.interceptors.request.use(
  (request: InternalAxiosRequestConfig) => {
    const userStore = useUserStore()
    const { accessToken } = userStore

    // 1. 追加鉴权 Token
    if (accessToken) {
      const hasBearer = accessToken.toLowerCase().startsWith('bearer ')
      request.headers.set('Authorization', hasBearer ? accessToken : `Bearer ${accessToken}`)
    }

    // 2. 处理租户 Header（允许业务显式跳过）
    const { skipTenantHeader } = request as ExtendedAxiosRequestConfig
    if (skipTenantHeader) {
      request.headers.delete('X-Tenant-Id')
      request.headers.delete('x-tenant-id')
    } else {
      const headerTenantId =
        request.headers?.get?.('X-Tenant-Id') ??
        request.headers?.get?.('x-tenant-id') ??
        (request.headers as Record<string, string> | undefined)?.['X-Tenant-Id'] ??
        (request.headers as Record<string, string> | undefined)?.['x-tenant-id']
      if (!headerTenantId) {
        const tenantId =
          localStorage.getItem(StorageConfig.TENANT_ID_KEY) || userStore.info?.tenantId
        if (tenantId) {
          request.headers.set('X-Tenant-Id', String(tenantId))
        }
      }
    }

    // 3. 自动补齐 Content-Type 并序列化 JSON
    if (request.data && !(request.data instanceof FormData) && !request.headers['Content-Type']) {
      request.headers.set('Content-Type', 'application/json')
      request.data = JSON.stringify(request.data)
    }

    return request
  },
  (error) => {
    handleHttpError(createHttpError($t('httpMsg.requestConfigError'), ApiStatus.error), true)
    return Promise.reject(error)
  }
)

/** 响应拦截器 */
axiosInstance.interceptors.response.use(
  (response: AxiosResponse<BaseResponse>) => {
    const { success, code, message, msg, data, errors } = response.data || {}
    const bizCode = code ?? response.status ?? ApiStatus.error
    const isSuccess = typeof success === 'boolean' ? success : bizCode === ApiStatus.success

    if (isSuccess) return response
    if (bizCode === ApiStatus.unauthorized) handleUnauthorizedError(message || msg)

    throw createHttpError(message || msg || $t('httpMsg.requestFailed'), bizCode, {
      data: errors ?? data,
      url: response.config.url,
      method: response.config.method?.toUpperCase()
    })
  },
  (error) => {
    if (error.response?.status === ApiStatus.unauthorized) {
      const resData = error.response.data as ErrorResponse | undefined
      handleUnauthorizedError(resData?.message || resData?.msg)
    }
    return Promise.reject(handleError(error))
  }
)

/** 统一创建HttpError */
function createHttpError(
  message: string,
  code: number,
  options?: { data?: unknown; url?: string; method?: string }
) {
  return new HttpError(message, code, options)
}

/** 处理401错误（带防抖） */
function handleUnauthorizedError(message?: string): never {
  const error = createHttpError(message || $t('httpMsg.unauthorized'), ApiStatus.unauthorized)

  if (!isUnauthorizedErrorShown) {
    isUnauthorizedErrorShown = true
    logOut()

    unauthorizedTimer = setTimeout(resetUnauthorizedError, UNAUTHORIZED_DEBOUNCE_TIME)

    handleHttpError(error, true)
    throw error
  }

  throw error
}

/** 重置401防抖状态 */
function resetUnauthorizedError() {
  isUnauthorizedErrorShown = false
  if (unauthorizedTimer) clearTimeout(unauthorizedTimer)
  unauthorizedTimer = null
}

/** 退出登录函数 */
function logOut() {
  setTimeout(() => {
    useUserStore().logOut()
  }, LOGOUT_DELAY)
}

/** 是否需要重试 */
function shouldRetry(statusCode: number) {
  return [
    ApiStatus.requestTimeout,
    ApiStatus.internalServerError,
    ApiStatus.badGateway,
    ApiStatus.serviceUnavailable,
    ApiStatus.gatewayTimeout
  ].includes(statusCode)
}

/** 请求重试逻辑 */
async function retryRequest<T>(
  config: ExtendedAxiosRequestConfig,
  retries: number = MAX_RETRIES
): Promise<T> {
  try {
    return await request<T>(config)
  } catch (error) {
    if (retries > 0 && error instanceof HttpError && shouldRetry(error.code)) {
      await delay(RETRY_DELAY)
      return retryRequest<T>(config, retries - 1)
    }
    throw error
  }
}

/** 延迟函数 */
function delay(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

/** 请求函数 */
async function request<T = any>(config: ExtendedAxiosRequestConfig): Promise<T> {
  // POST | PUT 参数自动填充
  if (
    ['POST', 'PUT'].includes(config.method?.toUpperCase() || '') &&
    config.params &&
    !config.data
  ) {
    config.data = config.params
    config.params = undefined
  }

  try {
    const res = await axiosInstance.request<BaseResponse<T>>(config)

    // 显示成功消息
    if (config.showSuccessMessage && (res.data.message || res.data.msg)) {
      showSuccess((res.data.message || res.data.msg) as string)
    }

    // 非 JSON 响应（如文件流）直接返回原始数据
    if (config.responseType && config.responseType !== 'json') {
      return res.data as unknown as T
    }

    return res.data.data as T
  } catch (error) {
    if (error instanceof HttpError && error.code !== ApiStatus.unauthorized) {
      const showMsg = config.showErrorMessage !== false
      handleHttpError(error, showMsg)
    }
    return Promise.reject(error)
  }
}

/** API方法集合 */
const api = {
  get<T>(config: ExtendedAxiosRequestConfig) {
    return retryRequest<T>({ ...config, method: 'GET' })
  },
  post<T>(config: ExtendedAxiosRequestConfig) {
    return retryRequest<T>({ ...config, method: 'POST' })
  },
  put<T>(config: ExtendedAxiosRequestConfig) {
    return retryRequest<T>({ ...config, method: 'PUT' })
  },
  del<T>(config: ExtendedAxiosRequestConfig) {
    return retryRequest<T>({ ...config, method: 'DELETE' })
  },
  request<T>(config: ExtendedAxiosRequestConfig) {
    return retryRequest<T>(config)
  }
}

export default api
