import { http } from '@kit.NetworkKit'
import { promptAction } from '@kit.ArkUI'
import { Rsp } from '../api/rsp/Rsp'

// 传输参数token
export const TOKEN_KEY: string = 'token'

//请求网络的基底址
export const BASE_URL: string = 'http://120.27.232.27:9190'

interface EmptyInterface {}


//Next版本不支持在箭头函数上写纯泛型,
// function requestHttp(url: url地址, method: 请求方法类型,默认为get, data?: 参数类型) : 返回类型是: Promise里面的T类型的数据
async function requestHttp<T extends Rsp>(url: string = '', method: http.RequestMethod = http.RequestMethod.GET,
  data?: object): Promise<T> {
  // 创建一个网络请求
  const httpRequest = http.createHttp()
  // 拼接地址
  let reqUrl = BASE_URL + url
  // Get方法需要自己拼接
  if (method == http.RequestMethod.GET) {
    // 如果data里面有值并且里面有对象的时候
    if (data && Object.keys(data).length) {
      reqUrl += "?" + Object.keys(data).map(key => {
        if (data[key]) {
          return `${key}=${data[key]}` // a=1 =>
        }
        return ""
      }).join('&') //['a=1','b=2','c=3']
    }
  }
  //设置请求对象
  let config: http.HttpRequestOptions = {
    //method同名方法赋值，参数名和属性名相同时只需要写一个method等价于method:method
    method,
    //超时时间
    readTimeout: 10000,
    //get的extraData参数在上面处理过了 在这儿不需要再传一遍
    extraData: method === http.RequestMethod.GET ? '' : data || {} as EmptyInterface,
    //响应参数的类型,指定为对象后有BUG，当结果有问题时，项目会直接瘫痪
    // expectDataType: http.HttpDataType.OBJECT,
    //请求头
    header: {
      'Content-Type': 'application/json',
      "Authorization": AppStorage.get(TOKEN_KEY) as string || ''
    }
  }
  //发请求
  try {
    const res = await httpRequest.request(reqUrl, config)
    console.log(method, '--->', reqUrl, JSON.stringify(config.extraData))
    console.log(method, '<---', reqUrl, res.responseCode, res.result)
    //res.responseCode响应状态码，这里的401还会认为是请求成功
    if (res.responseCode === 401) {
      // 401 token超时
      // 删除持久化数据token
      AppStorage.set<string>(TOKEN_KEY, '')
      promptAction.openToast({ message: 'token timeout' })
      // 回登录
      // router.replaceUrl({ url: 'pages/Login/LoginPage' })
      // 返回错误 终止
      return Promise.reject(new Error('token timeout'))
    } else if (res.responseCode === 404) {
      promptAction.openToast({ message: 'not find' })
      return Promise.reject(new Error('not find'))
    } else {
      // 指定为字符串，然后再转成一个对象，类型是不明确的要使用泛型,返回第一层+泛型,泛型的定义是一个类和之前的有所差距
      const result = JSON.parse(res.result as string) as T
      // 再判断返回的状态码进行处理，不是200都是失败
      if (result.code === 200) {
        return result as T
      } else {
        promptAction.openToast({ message: result.msg })
        return Promise.reject(new Error(result.msg))
      }
    }
  } catch (error) {
    promptAction.openToast({ message: error })
    return Promise.reject(error)
  } finally {
    // 销毁请求请求结束
    httpRequest.destroy()
  }
}

/**
 * 静态封装使用
 */
export class Request {
  /**
   * Get请求封装
   * @param url   请求地址
   * @param data  携带数据
   * @returns
   */
  static get<T extends Rsp>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.GET, data)
  }

  /**
   * Post请求封装
   * @param url   请求地址
   * @param data  携带数据
   * @returns
   */
  static post<T extends Rsp>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.POST, data)
  }

  /**
   * Put请求封装
   * @param url   请求地址
   * @param data  携带数据
   * @returns
   */
  static put<T extends Rsp>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.PUT, data)
  }

  /**
   * Delete请求封装
   * @param url   请求地址
   * @param data  携带数据
   * @returns
   */
  static delete<T extends Rsp>(url: string, data?: object): Promise<T> {
    return requestHttp<T>(url, http.RequestMethod.DELETE, data)
  }
}
