// by: https://juejin.cn/post/6896101154371928077#heading-7
// EventCenter
function EventCenter() {
  // 通过事件类型作为属性来管理不通的事件回调
  this.eventStack = {};
  this.on = function (eventName, cb) {
    const { eventStack } = this;
    const eventValue = eventStack[eventName];
    eventValue ? eventValue.push(cb) : (eventStack[eventName] = [cb]);
  };
  this.once = function (eventName, cb) {
    const { eventStack } = this;
    const eventValue = eventStack[eventName];
    // 利用闭包的形式 来模拟一次性监听的功能函数
    const tempCb = () => {
      let isOutOfDate = false;

      return () => {
        if (isOutOfDate) return;
        cb();
        isOutOfDate = true;
      };
    };
    eventValue
      ? eventValue.push(tempCb())
      : (eventStack[eventName] = [tempCb()]);
  };
  this.off = function (eventName, cb) {
    const { eventStack } = this;
    const eventValue = eventStack[eventName];
    if (!eventValue) return;
    (eventValue || []).forEach((eventCb, index) => {
      if (eventCb === cb) {
        eventValue.splice(index, 1);
      }
    });
  };
  this.emit = function (eventName, data) {
    const { eventStack } = this;
    const eventValue = eventStack[eventName];

    if (!eventValue) return;

    (eventValue || []).forEach((eventCb) => {
      eventCb(data);
    });
  };
}

function Ws(url, protocols) {
  // 要连接的URL
  this.url = url;
  // 一个协议字符串或一个协议字符串数组。
  // 这些字符串用来指定子协议，这样一个服务器就可以实现多个WebSocket子协议
  this.protocols = protocols;
  // WebSocket 实例
  this.ws = null;
  // 是否在重连中
  this.isReconnectionLoading = false;
  // 延时重连的 id
  this.timeId = null;
  // 是否是用户手动关闭连接
  this.isCustomClose = false;
  // 错误消息队列
  this.errorStack = [];
  // 消息管理中心
  this.eventCenter = new EventCenter();
  this.createWs = function () {
    if ('WebSocket' in window) {
      console.log('this.url',this.url)
      // 实例化
      this.ws = new WebSocket(this.url, this.protocols);
      // 监听事件
      this.onopen();
      this.onerror();
      this.onclose();
      this.onmessage();
    } else {
      console.log('你的浏览器不支持 WebSocket');
    }
  };

  // 监听成功
  this.onopen = function () {
    this.ws.onopen = () => {
      console.log(this.ws, 'onopen');
      // 发送成功连接之前所发送失败的消息
      this.errorStack.forEach((message) => {
        this.send(message);
      });
      this.errorStack = [];
      this.isReconnectionLoading = false;
    };
  };

  // 监听错误
  this.onerror = function () {
    this.ws.onerror = (err) => {
      console.log(err, 'onerror');
      this.reconnection();
      this.isReconnectionLoading = false;
    };
  };

  // 监听关闭
  this.onclose = function () {
    this.ws.onclose = () => {
      console.log('onclose');

      // 用户手动关闭的不重连
      if (this.isCustomClose) return;

      this.reconnection();
      this.isReconnectionLoading = false;
    };
  };

  // 接收 WebSocket 消息
  this.onmessage = async function () {
    this.ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        this.eventCenter.emit(data.type, data.data);
      } catch (error) {
        console.log(error, 'error');
      }
    };
  };

  // 重连
  this.reconnection = function () {
    // 防止重复
    if (this.isReconnectionLoading) return;

    this.isReconnectionLoading = true;
    clearTimeout(this.timeId);
    this.timeId = setTimeout(() => {
      this.createWs();
    }, 3000);
  };

  // 发送消息
  this.send = function (message) {
    // 连接失败时的处理
    if (this.ws.readyState !== 1) {
      this.errorStack.push(message);
      return;
    }

    this.ws.send(message);
  };

  // 手动关闭
  this.close = function () {
    this.isCustomClose = true;
    this.ws.close();
  };

  // 手动开启
  this.start = function () {
    this.isCustomClose = false;
    this.reconnection();
  };

  // 订阅
  this.subscribe = function (eventName, cb) {
    this.eventCenter.on(eventName, cb);
  };

  // 取消订阅
  this.unsubscribe = function (eventName, cb) {
    this.eventCenter.off(eventName, cb);
  };

  // 销毁
  this.destroy = function () {
    this.close();
    this.ws = null;
    this.errorStack = null;
    this.eventCenter = null;
  };
  this.createWs()
}

export default Ws;
