import ERRORS from '../const/error';
import { ERR_TIMEOUT } from '../../../common/consts';
import errUtil from '../../../utils/error';
import baseUtil from '../../../utils/base';
import { silenceLogger } from '../../../common/logger';
// import HOSTS from '../const/hosts';
// import system from '../../../common/system';

const { NOT_FRAME, ERR_MESSAGE } = ERRORS;
// const { ORIGIN } = HOSTS;

/**
 * 消息管理
 */
class MsgManager {
  constructor() {
    this.origin = '*';
    this.isFrame = window !== window.parent;
    // this.callTimeout = !system.isProd() ? 1000 * 1000 : 60 * 1000;
    this.callTimeout = 60 * 1000;
    this.nowReqId = Date.now(); // 请求唯一标识

    this.events = [];
    window.addEventListener('message', this._listener.bind(this));
  }

  /**
   * 消息监听
   * @param {*} event 
   */
  _listener(event) {
    const { source, data, origin } = event || {};
    // 域名检测
    // if (system.isProd() && ORIGIN.indexOf(origin) === -1) {
    //   return;
    // }

    // 非法源
    if (source !== window.parent) {
      return;
    }

    // 静默日志
    silenceLogger.debug('on message', event);

    // 执行
    this.events.map(env => env(data || {}));
  }

  /**
   * 监听回调
   * @param {Function} fun 
   */
  on(fun) {
    if (baseUtil.isFun(fun)) {
      this.events.push(fun);
    }
  }

  /**
   * 取消监听回调
   * @param {Function} fun 
   */
  off(fun) {
    if (!fun) {
      this.events = [];
      return true;
    }
    this.events = this.events.filter(e => e !== fun);
    return true;
  }

  /**
   * 触发外部方法，不等待回调
   * @param {string} topic 
   * @param {any} message 
   * @param {string} reqId 唯一ID
   */
  emit(topic, message, reqId) {
    const data = { topic };
    if (message) {
      data.message = message;
    }
    if (reqId) {
      data.reqId = reqId;
    }
    try {
      window.parent.postMessage(data, this.origin);
    } catch (err) {
      throw errUtil.pkgErr(ERR_MESSAGE, err && err.message);
    }
  }

  /**
   * 外部方法调用，等待回调
   * 固定规则: 
   *  1. 请求唯一ID: reqId = reqTopic_nowReqId++
   *  2. 发起请求: reqTopic.req, 请求成功: reqTopic.rsp, 请求失败: reqTopic.err
   * @param {string} reqTopic 
   * @param {any} message 
   */
  dispatch(reqTopic, message) {
    return new Promise((resolve, reject) => {
      if (!this.isFrame) {
        return reject(NOT_FRAME);
      }
      const reqId = `${reqTopic}_${this.nowReqId++}`;
      const topic = `${reqTopic}.req`;
      const successTopic = `${reqTopic}.rsp`;
      const errorTopic = `${reqTopic}.err`;

      const onMessage = data => {
        const { topic: rspTopic, message: rspMsg } = data;
        const { reqId: rspReqId, rsp, err } = rspMsg || {};
        if (rspReqId !== reqId) {
          return false;
        }
        if (rspTopic === successTopic) {
          terminate();
          return resolve(rsp);
        }
        if (rspTopic === errorTopic) {
          terminate();
          return reject(errUtil.pkgErr(err));
        }
      };

      // 回调超时检测
      const timer = setTimeout(() => {
        terminate();
        reject(errUtil.pkgErr(ERR_TIMEOUT, `WEB端调用[${reqTopic}]超时`));
      }, this.callTimeout);

      const terminate = () => {
        clearTimeout(timer);
        this.off(onMessage);
      };
      this.on(onMessage);
      this.emit(topic, message, reqId);
    });
  }
}

export default new MsgManager();
