import { redirectToLogin } from "./auth"

const DEFAULT_TIMEOUT = 12000

function appendParams(url, params = {}) {
  const search = new URLSearchParams()
  Object.entries(params).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== "") {
      search.append(key, value)
    }
  })
  const query = search.toString()
  if (!query) return url
  return `${url}${url.includes("?") ? "&" : "?"}${query}`
}

export async function requestJson(url, options = {}) {
  const { params, timeout = DEFAULT_TIMEOUT, ...fetchOptions } = options
  const controller = new AbortController()
  let timedOut = false
  const timer = window.setTimeout(() => {
    timedOut = true
    controller.abort()
  }, timeout)
  try {
    const response = await fetch(appendParams(url, params), {
      credentials: "include",
      ...fetchOptions,
      signal: controller.signal,
      headers: {
        Accept: "application/json",
        ...(fetchOptions.headers || {}),
      },
    })
    if (!response.ok) {
      const friendlyError = new Error(response.status === 401 ? "用户未登录或授权已过期。" : `HTTP ${response.status}`)
      friendlyError.code = `HTTP_${response.status}`
      friendlyError.status = response.status
      if (response.status === 401) {
        redirectToLogin()
      }
      throw friendlyError
    }
    const data = await response.json()
    if (data?.code === 401 || data?.code === "401") {
      const friendlyError = new Error(data?.msg || "用户未登录或授权已过期。")
      friendlyError.code = "HTTP_401"
      friendlyError.status = 401
      redirectToLogin()
      throw friendlyError
    }
    return data
  } catch (error) {
    const aborted = controller.signal.aborted || error?.name === "AbortError" || /aborted/i.test(error?.message || "")
    if (aborted) {
      const friendlyError = new Error(timedOut ? "服务响应超时，请稍后再试。" : "请求已取消，请重新发送。")
      friendlyError.code = timedOut ? "REQUEST_TIMEOUT" : "REQUEST_ABORTED"
      throw friendlyError
    }
    throw error
  } finally {
    window.clearTimeout(timer)
  }
}

export function normalizeResponseData(response) {
  if (response?.data !== undefined) return response.data
  if (response?.result !== undefined) return response.result
  return response
}
