import { Config, RequestHead, ResponseData, ResponseError, RequestParams } from '@/utils/request/types/index.ts'
import { message } from "ant-design-vue";

// 默认配置
const createDefaultConfig = (): {
  headers: RequestHead
} => {
  const defaultConfig = {
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      authorization: `Bearer ${localStorage.token}`
    },
  }
  return defaultConfig
}

// 构造数据
const genData = (data: any, dataRaw: boolean) => {
  if (dataRaw) {
    return data instanceof FormData || data instanceof URLSearchParams
      ? data
      : new URLSearchParams(data);
  }
  return JSON.stringify(data);
};

// 构造返回
const genResult = (result: ExtraObj, status: 'success' | 'error'): ResponseData | ResponseError => {
  if (result.code) {
    return {
      ...result,
      code: result.code,
      data: result.data
    }
  } else {
    if (status == 'success') {
      return {
        code: 200,
        data: result
      }
    } else {
      let error
      if ('detail' in result) {
        error = result.detail
      } else {
        error = result
      }
      return {
        code: 500,
        message: error,
        _raw: result
      }
    }

  }
}

// 构造请求参数
const createRuestParams = (config: Config) => {
  const { method, data, dataRaw, headers, controller } = config;
  const requetParams: RequestParams = {
    method,
    headers: headers as HeadersInit ?? createDefaultConfig().headers,
    body: data instanceof URLSearchParams ? data : genData(data, dataRaw || false),
    signal: controller?.signal
  };
  return requetParams
}

// 请求
export const request = async (config: Config): Promise<ResponseData | ResponseError> => {
  const { url, base, params, getRaw } = config;
  // 路径参数格式化
  const urlParams = params ? new URLSearchParams(params) : null
  const extra = `${urlParams ? '?' + urlParams.toString() : ''}`
  const requestUrl = `${base || import.meta.env.VITE_BASE_API}${url}${extra}`
  const requestParams = createRuestParams(config)

  // 请求逻辑封装
  const res = await fetch(requestUrl, requestParams).then(async (res) => {
    // 是否需要返回原始数据
    const result = getRaw ? res : await res.json();
    if (!res.ok) throw result
    if (result?.code && result?.code !== 200) {
      throw result
    }
    return getRaw ? result : genResult(result, 'success')
  }).catch((err) => {
    if (err.name == 'AbortError') {
      return Promise.reject(err)
    }
    let error
    if ('code' in err) {
      error = err
    } else {
      error = genResult(err, 'error')
    }
    if (error.message) {
      message.error(error.message)
    }
    return Promise.reject(error)
  });

  return res;
}
