import { ICloudbasePlatformInfo } from '@cloudbase/types'
import adapterForWxMp, { WxRequest, WxMpWebSocket, wxMpStorage, parseQueryString } from '@cloudbase/adapter-wx_mp'
import { IUploadRequestOptions, StorageType } from '@cloudbase/adapter-interface'

declare const wx: any
declare const App: any
declare const getApp: any

export const Platform: ICloudbasePlatformInfo = {}

export const getWxDefaultAdapter = () => {
  WxRequest.prototype.upload = function (options: IUploadRequestOptions) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    const self = this
    return new Promise((resolve) => {
      const { url, file, data, headers } = options
      const fs = wx.getFileSystemManager() // 读取文件 二进制内容
      const task = wx.request({
        url,
        method: options.method,
        header: {
          'content-type': ' ', // 小程序 content-type 默认为 application/json， 这里一定要强制为 空， 否则签名错误
          ...headers,
        },
        data: fs.readFileSync(file), // 将二进制文件转为字符串直接赋值到 request payload， 不要以 form 的方式传输
        timeout: this._timeout,
        success(res: { statusCode: number; data: unknown }) {
          const result = {
            statusCode: res.statusCode,
            data: res.data || {},
          }
          if (res.statusCode === 200 && data?.success_action_status) {
            result.statusCode = parseInt(data.success_action_status, 10)
          }
          resolve(result)
        },
        fail(err: unknown) {
          resolve(err)
        },
        complete(err: { errMsg: string }) {
          if (!err?.errMsg) {
            return
          }
          if (!self._timeout || self._restrictedMethods.indexOf('upload') === -1) {
            return
          }
          const { errMsg } = err
          if (errMsg === 'request:fail timeout') {
            console.warn(self._timeoutMsg)
            try {
              task.abort()
            } catch (e) {}
          }
        },
      })
    })
  }

  function isPlugin() {
    return (
      typeof App === 'undefined'
      && typeof getApp === 'undefined'
      && !wx.onAppHide
      && !wx.offAppHide
      && !wx.onAppShow
      && !wx.offAppShow
    )
  }
  adapterForWxMp.genAdapter = function genAdapter(options) {
    const adapter = {
      root: { globalThis: {} },
      reqClass: WxRequest,
      wsClass: WxMpWebSocket,
      captchaOptions: {
        openURIWithCallback: (_url: string) => {
          // eslint-disable-next-line @typescript-eslint/naming-convention
          const { EventBus } = options
          let queryObj: Record<string, string> = {}
          let url = _url
          console.log('openURIWithCallback', _url)
          const matched = _url.match(/^(data:.*?)(\?[^#\s]*)?$/)
          if (matched) {
            // eslint-disable-next-line prefer-destructuring
            url = matched[1]
            console.log('openURIWithCallback url', url)
            const search = matched[2]
            if (search) {
              queryObj = parseQueryString(search)
            }
          }
          console.log('openURIWithCallback queryObj', queryObj)
          const { token, ...restQueryObj } = queryObj
          if (/^data:/.test(url) && !token) {
            // 如果是 data: 开头的 URL 且没有 token，则直接返回
            return Promise.reject({
              error: 'invalid_argument',
              error_description: `invalie captcha data: ${_url}`,
            })
          }
          if (!token) {
            return Promise.reject({
              error: 'unimplemented',
              error_description: 'need to impl captcha data',
            })
          }
          return new Promise((resolve) => {
            console.log('wait for captcha...')
            EventBus.$emit('CAPTCHA_DATA_CHANGE', { ...restQueryObj, token, url })

            // 监听事件总线，等待验证码数据变化
            EventBus.$once('RESOLVE_CAPTCHA_DATA', (res: { captcha_token: string; expires_in: number }) => {
              resolve(res)
            })
          })
        },
      },
      localStorage: wxMpStorage,
      primaryStorage: StorageType.local,
      getAppSign() {
        const info = wx.getAccountInfoSync()
        if (isPlugin()) {
          // 插件环境返回插件appid
          return info && info.plugin ? info.plugin.appId : ''
        }
        return info && info.miniProgram ? info.miniProgram.appId : ''
      },
    }
    return adapter
  }

  return adapterForWxMp
}
