import { injectable, Service } from './service'

/** api接口返回值类型 */
declare type NetResult = {
  success: boolean,
  data: Any
}

/**
 * API网络请求服务
 */
@injectable
export default class NetService extends Service {
  protected PROXY = '/api'

  /**
   * post方法请求接口
   * @param url 接口地址
   * @param params 接口参数
   */
  post(url: string, params: Any = {}, timeout = 6000): Promise<any> {
    return this.fetch(url, { method: 'POST', body: JSON.stringify(params) }, timeout)
  }

  /**
   * get请求api接口
   * @param url 接口地址
   */
  get(url: string, timeout = 6000): Promise<NetResult> {
    return this.fetch(url, { method: 'GET' }, timeout)
  }

  /**
   * del请求api接口
   * @param url 接口地址
   */
  del(url: string, timeout = 6000): Promise<NetResult> {
    return this.fetch(url, { method: 'DELETE' }, timeout)
  }

  /**
   * post方法请求接口
   * @param url 接口地址
   * @param params 接口参数
   */
  put(url: string, params: Any = {}, timeout = 6000): Promise<NetResult> {
    return this.fetch(url, { method: 'PUT', body: JSON.stringify(params) }, timeout)
  }

  /**
   * 下载文件
   * @param url url|blob
   * @param fileName
   */
  downloadFile(url: string | Blob, fileName: string) {
    const download = (blob: Blob, fileName: string) => {
      const a = document.createElement('a')
      document.body.appendChild(a)
      a.style.display = 'none'
      // 使用获取到的blob对象创建的url
      const url = window.URL.createObjectURL(blob)
      a.href = url
      // 指定下载的文件名
      a.download = fileName
      a.click()
      document.body.removeChild(a)
      // 移除blob对象的url
      window.URL.revokeObjectURL(url)
    }
    return new Promise<void>((resolve, reject) => {
      if (url instanceof Blob) {
        download(url, fileName)
        resolve()
      } else {
        fetch(url).then((res) => res.blob()).then((blob) => download(blob, fileName)).finally(() => resolve())
      }
    })
  }

  /** token 续期 */
  async refresh(token: string) {
    this.post('', { token }).then((res) => {
      console.log('刷新token', res)
    })
  }

  /**
   * fetch
   * @param url
   * @param opt
   * @param timeout 0 默认不超时
   * @returns
   */
  private fetch(url: string, opt: RequestInit, timeout = 0): Promise<NetResult> {
    return new Promise((resolve) => {
      const controller = new AbortController()
      const { signal } = controller
      if (timeout) {
        setTimeout(() => {
          controller.abort()
        }, timeout)
      }
      fetch(this.PROXY + url, {
        signal,
        ...opt,
        headers: opt.headers || { 'Content-Type': 'application/json' }
      }).then((res) => {
        if (res.status === 500) return { success: false, data: '请求错误' }
        return res.json()
      }).then((res) => {
        const obj = { data: res.data, success: res.data instanceof Object }
        if (!obj.success && obj.data.includes('need authrize')) {
          throw 401
        }
        resolve(obj)
      }).catch((er) => {
        throw er
      })
    })
  }
}