/**
 * 自定义 WebSocket 扩展对象
 */
class Socket extends WebSocket {
  /**
   * 要连接的URL;这应该是WebSocket服务器将响应的URL。
   */
  url;
  /**
   *  可选
   * 一个协议字符串或者一个包含协议字符串的数组。这些字符串用于指定子协议,这样单个服务器可以实现多个WebSocket子协议
   * (例如,您可能希望一台服务器能够根据指定的协议(protocol)处理不同类型的交互)。如果不指定协议字符串,则假定为空字符串。
   */
  protocols;
  /**
   *  令牌(作为身份识别)
   */
  tokenSN;
  /**
   * 密码(验证是否合法)
   */
  password;
  /**
   * 心跳周期(单位:秒)
   */
  heartRate;
  /**
   * 心跳状态
   * 0:没有心跳
   * 1:存在心跳
   */
  lifeState;

  /**
   * 有心跳的
   * @type {number}
   */
  ALIVE = 1;
  /**
   * 无心跳的
   * @type {number}
   */
  DIE = 0;

  constructor(options) {

    super(options.url, options.protocols);
    this.url = options.url;
    this.protocols = options.protocols;

    const tokenSN = options.tokenSN;

    if (!tokenSN || typeof tokenSN !== 'string') {
      throw new TypeError('参数 tokenSN 错误!tokenSN 必须是一个有效字符串');
    }

    this.tokenSN = tokenSN;

    const password = options.password;

    if (!password) {
      throw new TypeError('参数 password 错误!参数 password 不存在');
    }

    this.password = password;

    const heartRate = options.heartRate;

    if (isNaN(heartRate)) {
      throw new TypeError('参数 heartRate 错误!参数 heartRate 必须是数字');
    }

    this.heartRate = heartRate;

  }

  /**
   * 心跳
   */
  heartbeat() {

    if (this.lifeState === this.ALIVE) {
      return;
    }

    const engine = setInterval(() => {

      // 如果连接处于连接状态则发送心跳
      if (this.readyState === this.OPEN) {

        try {
          this.send(JSON.stringify({
            method : 'heartbeat'
          }));
          this.lifeState = this.ALIVE;
        }catch (e) {}
      }

      // 连接关闭状态时,关闭心跳
      if (this.readyState === this.CLOSED) {
        clearInterval(engine);
        this.lifeState = this.DIE;
      }

    }, this.heartRate * 1000 * 0.8);

  }

  /**
   * 登录认证
   */
  login() {

    if (this.readyState !== this.OPEN) {
      return;
    }

    let loginInfo = {
      method : 'login',
      params : {
        tokenSN : this.tokenSN,
        password : this.password
      }

    };
    this.send(JSON.stringify(loginInfo));
  }

  /**
   * 初始化
   * @param options
   */
  static initialize(options) {

    Socket.instance = new Socket(options);

    // 连接打开时事件
    Socket.instance.addEventListener('open', (event) => {

      const onopen = Socket.onopen;

      if (typeof onopen === 'function') {
        onopen(event);
      }

      // 登录认证
      Socket.instance.login();
      // 心跳保活
      Socket.instance.heartbeat();

    });

    Socket.instance.addEventListener('close', (event) => {

      const onclose = Socket.onclose;

      if (typeof onclose === 'function') {
        onclose(event);
      }

      // 10 秒尝试重连
      setTimeout(() => {
        console.warn('websocket 已断开连接,尝试再次连接');
        Socket.initialize(options);
      }, 10 * 1000)

    });

    Socket.instance.addEventListener('error', (event) => {

      const onerror = Socket.onerror;

      if (typeof onerror === 'function') {
        onerror(event);
      }
    });

    Socket.instance.addEventListener('message', (event) => {

      const onmessage = Socket.onmessage;

      const data = event.data;

      if (typeof onmessage === 'function') {
        onmessage(data);
      }

      const msg = JSON.parse(data) || {};
      let params = msg.params || {};
      let subEvent = params.subEvent;

      if (subEvent === 'sub') {
        let content = params.content;
        content = JSON.parse(content);
        const requestId = content.requestId;

        if (requestId) {

          const socket = Socket.instance;

          const subEvent = socket.subEvent[requestId];

          if (subEvent) {
            const callback = subEvent.callback;

            if (typeof callback === 'function') {
              callback(content);
            }
          }
        }
      }

    });

  }

  /**
   * 订阅事件
   * @type {{}}
   */
  subEvent = {}

  static send(data) {

    let subCallback = {
      callback: undefined,
      then(callback) {
        if (typeof callback === 'function') {
          this.callback = callback;
        }
      }
    }

    const socket = Socket.instance

    if (socket === null) return subCallback;

    socket.send(JSON.stringify(data));

    const params = data.params || {};
    const subEvent = params.subEvent || '';
    const content = params.content || {};
    const id = content.id;

    if (id) {
      if (subEvent === 'sub') {
        socket.subEvent[id] = subCallback;
      }else if (subEvent === 'unsub') {
        delete socket.subEvent[id];
      }
    }

    return subCallback;

  }

}

/**
 * socket 实例对象
 * @type {null}
 */
Socket.instance = null;

/**
 * 用于指定连接关闭后的回调函数。
 * @type {null}
 */
Socket.onclose = null;
/**
 * 用于指定连接失败后的回调函数。
 * @type {null}
 */
Socket.onerror = null;
/**
 * 用于指定当从服务器接受到信息时的回调函数。
 * @type {null}
 */
Socket.onmessage = null;
/**
 * 用于指定当从服务器接受到信息时的回调函数。
 * @type {null}
 */
Socket.onopen = null;

export { Socket };