import querystring from 'querystring';
import { silenceLogger } from '../../../common/logger';
import event, { EVENTS } from '../../../common/event';
import baseUtil from '../../../utils/base';

const mainQueue = [];
const logQueue = [];
const maxStrLen = 40 * 1024

/**
 * 处理向pc端发送消息，并管理消息序列
 */
export default {
  _running: false,

  /**
   * @typedef {Object} PostParams
   * @property {string} [hyaction] callpc
   * @property {string} [funcType] client
   * @property {string} [reqStr] reqstr
   * @property {string} [ui] ui
   * @property {string} funcName funcName
   * @property {string} [callbackName] callbackName
   */
  /**
   * 向pc端发送消息，序列化执行
   * @param {PostParams} params 传参
   * @param {boolean} silence 是否打印日志
   */
  post(params, silence) {
    const { funcType, funcName, reqStr, ui, callbackName } = params
    const queryStr = querystring.stringify({
      hyaction: "callpc",
      funcType: funcType || "client",
      funcName,
      req: reqStr || "",
      ui: ui || "",
      callbackName,
    });
    
    // 是否打印日志
    const debug = !silence && funcName !== 'log'
    debug && silenceLogger.debug('post', queryStr)

    // External 通信
    const external = window.external || {};
    // 必须先判断 $_hycallpc_，PC观众端旧的版本有bug，external.*** 都会返回function
    if (baseUtil.isFun(external.$_hycallpc_)) {
      debug && silenceLogger.debug('post $_hycallpc_')
      try {
        return external.$_hycallpc_(queryStr)
      } catch (err) {
        debug && silenceLogger.warn('post $_hycallpc_ fail', err.message)
      }
    }

    // 支持 hycallpc__ 则直接调用
    if (baseUtil.isFun(external.hycallpc__)) {
      debug && silenceLogger.debug('post hycallpc__')
      return external.hycallpc__(queryStr)
    }

    // 消息长度校验 - 只针对老的请求方式
    if (queryStr.length > maxStrLen) {
      throw new Error(`query more then ${maxStrLen}B`)
    }

    // 旧通讯方式
    debug && event.emit(EVENTS.WARN_INFO, { api: funcName, msg: "post iframe", params: [reqStr] })

    // 老的通讯方式
    const url = `https://www.huya.com?${queryStr}`;
    const onSend = () => {
      const iframe = document.createElement('iframe');
      iframe.style.display = 'none';
      iframe.src = url;
      document.body.appendChild(iframe);
      setTimeout(() => document.body.removeChild(iframe), 0);
    }

    // 执行日志序列
    if (funcName === 'log') {
      logQueue.push(onSend);
      return setTimeout(this._exec.bind(this), 1000); // 日志延后执
    }

    // 执行主序列
    mainQueue.push(onSend);
    return setTimeout(this._exec.bind(this), 0);
  },

  /**
   * 序列消耗
   */
  _exec() {
    // 锁
    if (this._running) return;

    // 优先执行 mainQueue 再执行 logQueue
    const queue = mainQueue.shift() || logQueue.shift();
    if (!queue) return;

    this._running = true;
    if (typeof queue === 'function') queue();

    // 执行下次循环
    setTimeout(() => {
      this._running = false;
      this._exec();
    }, 0);
  },
}
