
import { useAuthStore } from '@/store';
import { env } from '@/env';
import { params, URLSearchParams } from '@/URLSearchParams'

// #ifdef MP-WEIXIN
function uniEventSource(params) {
  let uEventSource = {}
  let {
    url = '',
    method = "POST",
    header = {},
    data = {},
    sslVerify = false,
    onopen = () => { },
    onmessage = (message) => { },
    onclose = () => { },
    onerror = (error) => { },
  } = params
  if (!url) {
    console.error("URL属性不能为空，请添加 EventSource 地址")
    return;
  }

  const requestTask = uni.request({
    url,
    enableChunked: true,
    method,
    sslVerify,
    data,
    header,
    complete(res) {
      if (res.statusCode != 200) {
        onerror(res)
      }
      onclose()
    }
  })
  requestTask.onHeadersReceived((res) => {
    if (res.statusCode == 200) {
      onopen()
    } else {
      console.error("链接失败")
    }
  })
  requestTask.onChunkReceived(res => {
    const uint8Array = new Uint8Array(res.data);
    let text = String.fromCharCode.apply(null, uint8Array)
    text = decodeURIComponent(escape(text))
    onmessage(text)
  })
  uEventSource.abort = () => {
    requestTask.offChunkReceived()
    // requestTask.abort()
    onclose()
  }
  uEventSource.url = url
  uEventSource.method = method
  uEventSource.header = header
  uEventSource.data = data

  return uEventSource
}


/**
 * @description: 创建sse连接
 */
class ServerSentEvents {
  static defaultConfig = {
    base: env.baseApi, // 基础地址
    url: '/sse', // 地址
    data: undefined, // 请求正文
    params: undefined, // 请求参数
    method: 'get', // 提交方式
    auth: true, // 是否携带token
    json: true, // 是否返回json
    returnData: false, // json数据是否返回data属性
    reconnect: true, //是否重连
    headers: {
      'Content-Type': 'application/json'
    },
    onopen: () => { },
    onmessage: () => { },
    onerror: () => { },
    onclose: () => { }
  }

  constructor(config) {
    if (config) {
      this.setConfig(config)
      this.init()
    }
  }

  static get(url, onmessage, config = {}) {
    config.onmessage = onmessage
    config.url = url
    return new ServerSentEvents(config)
  }

  static post(url, data, onmessage, config = {}) {
    config.onmessage = onmessage
    config.url = url
    config.method = 'post'
    config.data = data
    return new ServerSentEvents(config)
  }

  setConfig(config) {
    this.config = {
      ...ServerSentEvents.defaultConfig,
      ...config
    }
  }
  init() {
    if (this.config.auth) {
      this.config.headers.Authorization = 'Bearer ' + useAuthStore().token
    }
    let url = this.config.url
    // 如果url不含协议
    if (url.indexOf("//") == -1) {
      url = this.config.base + url
    }

    if (this.config.params) {
      if (url.indexOf("?") > -1) {
        url += '&' + params(this.config.params).toString()
      } else {
        url += '?' + params(this.config.params).toString()
      }
    }

    let body = undefined

    if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
      if (this.config.data.constructor == URLSearchParams) {
        this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
        body = params(this.config.data).toString()
      } else {
        body = JSON.stringify(body)
      }
    }
    this.config._url = url
    this.config._body = body

    this.send()

  }

  send() {

    this.sse = uniEventSource({
      url: this.config._url,
      method: this.config.method,
      header: this.config.headers,
      data: this.config._body,
      onopen: this.config.onopen,
      onmessage: (msg) => {
        if (msg?.startsWith("data:")) {
          msg = msg.substring(5)
          if (!msg.trim()) {
            return;
          }
          if (this.config.json) {
            // console.debug("msg", msg)
            let data = JSON.parse(msg)
            if (this.config.returnData) {
              data = data.data
            }
            this.config.onmessage(data)
          } else {
            this.config.onmessage(msg)
          }
        }
      },
      onclose: () => {
        console.info('onclose')
        // this.abort()
        this.config.onclose()
        if (this.config.reconnect) {
          this.sse = undefined
          this.send()
        }
      },
      onerror: (err) => {
        console.error(err)
        this.config.onerror(err)
      }
    });
  }
  abort() {
    if (this.sse) {
      try {
        this.sse.abort();
      } catch (e) {
        console.error(e)
      }
      this.sse = undefined
    }
  }

  close() {
    this.config.reconnect = false;
    this.abort()
  }


}
// #endif

// #ifdef H5
import { fetchEventSource } from '@microsoft/fetch-event-source'
// pnpm add @microsoft/fetch-event-source@2.0.1

class ServerSentEvents {
  static defaultConfig = {
    base: env.baseApi, // 基础地址
    url: '/sse', // 地址
    data: undefined, // 请求正文
    params: undefined, // 请求参数
    method: 'get', // 提交方式
    auth: true, // 是否携带token
    json: true, // 是否返回json
    returnData: false, // json数据是否返回data属性
    reconnect: true, //是否重连
    headers: {
      'Content-Type': 'application/json'
    },
    onopen: () => { },
    onmessage: () => { },
    onerror: () => { },
    onclose: () => { }
  }

  constructor(config) {
    if (config) {
      this.setConfig(config)
      this.init()
    }
  }

  static get(url, onmessage, config = {}) {
    config.onmessage = onmessage
    config.url = url
    return new ServerSentEvents(config)
  }

  static post(url, data, onmessage, config = {}) {
    config.onmessage = onmessage
    config.url = url
    config.method = 'post'
    config.data = data
    return new ServerSentEvents(config)
  }

  setConfig(config) {
    this.config = {
      ctrl: new AbortController(),
      ...ServerSentEvents.defaultConfig,
      ...config
    }
  }
  init() {
    if (this.config.auth) {
      this.config.headers.Authorization = 'Bearer ' + useAuthStore().token
    }
    let url = this.config.url
    // 如果url不含协议
    if (url.indexOf("//") == -1) {
      url = this.config.base + url
    }

    if (this.config.params) {
      if (url.indexOf("?") > -1) {
        url += '&' + this.params(this.config.params)
      } else {
        url += '?' + this.params(this.config.params)
      }
    }

    let body = undefined

    if (this.config.data && (this.config.method === 'post' || this.config.method === 'put')) {
      if (this.config.data.constructor == URLSearchParams) {
        this.config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
        body = this.params(this.config.data).toString()
      } else if (this.config.data.constructor == FormData) {
        this.config.headers['Content-Type'] = 'multipart/form-data'
        body = this.config.data
      } else {
        body = JSON.stringify(body)
      }
    }
    this.config._url = url
    this.config._body = body
    console.debug(this.config)

    this.send()

  }

  send() {
    fetchEventSource(this.config._url, {
      method: this.config.method,
      headers: this.config.headers,
      body: this.config._body,
      signal: this.config.ctrl.signal,
      onopen: this.config.onopen,
      onmessage: (msg) => {
        if (this.config.json) {
          let data = JSON.parse(msg.data)
          if (this.config.returnData) {
            data = data.data
          }
          this.config.onmessage(data)
        } else {
          this.config.onmessage(msg)
        }
      },
      onclose: () => {
        console.info('onclose')
        this.abort()
        this.config.onclose()
        if (this.config.reconnect) {
          this.send()
        }
      },
      onerror: (err) => {
        console.error(err)
        this.abort()
        this.config.onerror(err)
      }
    })
  }

  abort() {
    if (this.config.ctrl && !this.config.reconnect) {
      try {
        this.config.ctrl.abort()
      } catch (e) {
        console.error(e)
      }
    }
  }

  close() {
    this.config.reconnect = false;
    this.abort()
  }

}

// #endif

export {
  params, ServerSentEvents as SSE
}

export default ServerSentEvents