import { Platform, DeviceEventEmitter, NativeEventEmitter } from 'react-native';
import EventManager from '../../../manager/eventManager';
import baseUtil from '../../../utils/base';
import errUtil from '../../../utils/error';
import logger from '../../../common/logger';
import { EVENT_NAME_NULL, EVENT_CALLBACK_INVALID, EVENT_UNSUPPORT } from '../../../common/consts';

/**
 * 消息管理
 * 原生事件管理
 */
export default class NativeEventer {
  /**
   * @param {Object} ExtNative 要管理事件的 NativeModules 名, 非安卓设备要通过 NativeModules 绑定监听事件
   * @param {string} ExtEventName 统一触发模块事件的事件名, 非安卓设备要通过监听 NativeModules 的指定事件统一处理
   */
  constructor(ExtEventName, ExtNative) {
    this._extEventName = ExtEventName;
    this._extNative = ExtNative;
    this._eventer = new EventManager();
    this._emitter = null;
    this._opt = {};
  }
  /**
   * 注入回调
   * @callback InjectCallback
   * @param {string} eventName 
   * @param {Function} callback 
   * @param {Object} [options]
   */
  /**
   * 注册拦截器
   * @param {Object} opt 传入参数
   * @param {Array<string>} [opt.supportEvents] 支持的事件
   * @param {Function} [opt.resReducer] 事件触发返回参数处理， 必须返回 { name: string, params: Object }
   * @param {InjectCallback} [opt.beforeOn] 注册事件前触发
   * @param {InjectCallback} [opt.afterOn] 注册事件后触发
   * @param {InjectCallback} [opt.beforeOff] 取消注册事件前触发
   * @param {InjectCallback} [opt.afterOff] 取消注册事件后触发
   * TODO: 
   * 1. 支持 afterClear
   * 2. 注入配置支持 prommise
   */
  setIntercept(opt) {
    this._opt = Object.assign(this._opt, opt || {});
  }

  /**
   * 是否是安卓环境
   * @returns {boolean}
   */
  isAndroid() {
    const { OS } = Platform || {};
    return OS === 'android';
  }

  /**
   * 实例化事件监听
   * @param string eventName 
   * @private
   */
  _tryInit(eventName) {
    this.isAndroid() ? this._initByAndroid(eventName) : this._initByIOS(eventName);
  }

  /**
   * 初始化 Device 事件监听，安卓
   * @param {string} eventName 
   * @private
   */
  _initByAndroid(eventName) {
    this._emitter = this._emitter || {};
    const { resReducer } = this._opt;
    if (!this._emitter[eventName]) {
      this._emitter[eventName] = DeviceEventEmitter.addListener(eventName, data => {
        const res = { name: eventName, params: data };
        const { name, params } = (baseUtil.isFun(resReducer) ? resReducer(res) : res) || {};
        this._eventer.emit(name, params);
      });
    }
  }

  /**
   * 初始化 Native 事件监听，非安卓
   * @param {string} eventName 
   * @private
   */
  _initByIOS(eventName) {
    if (this._emitter) return;
    const { resReducer } = this._opt;
    const nativeExt = new NativeEventEmitter(this._extNative);
    this._emitter = nativeExt.addListener(this._extEventName, res => {
      const { name, params } = (baseUtil.isFun(resReducer) ? resReducer(res) : res) || {};
      if (!name) logger.warn(`${this._extEventName} name is undefined`);
      this._eventer.emit(name, params);
    });
  }

  /**
   * 清除事件
   * @param {*} eventName 
   * @private
   */
  _tryClear(eventName) {
    this.isAndroid() ? this._clearByDevice(eventName) : this._clearByNative(eventName);
  }

  /**
   * 事件监听清除 Device
   * @param {*} eventName 
   * @private
   */
  _clearByDevice(eventName) {
    if (!this._emitter) return;
    const emitter = this._emitter[eventName];
    if (!emitter) return;
    emitter.remove();
    this._emitter[eventName] = null;
  }

  /**
   * 事件监听清除 Native
   * @param {*} eventName 
   * @private
   */
  _clearByNative(eventName) {
    return true;
  }

  /**
   * 监听回调，可多次绑定
   * @param {string} eventName 
   * @param {Function} callback 
   * @param {Object} [options]
   */
  on(eventName, callback, options = null, tp) {
    if (baseUtil.isEmpty(eventName)) throw errUtil.pkgErr(EVENT_NAME_NULL);
    if (!baseUtil.isFun(callback)) throw errUtil.pkgErr(EVENT_CALLBACK_INVALID);
    const { supportEvents } = this._opt;
    if (supportEvents && supportEvents.indexOf(eventName) < 0) {
      throw errUtil.pkgErr(EVENT_UNSUPPORT, `${EVENT_UNSUPPORT.msg}: ${eventName}`);
    }

    this._tryInit(eventName);

    const { beforeOn, afterOn } = this._opt;
    let beforeRes = baseUtil.isFun(beforeOn) && beforeOn(eventName, callback, options);
    let res = this._eventer.on(eventName, callback, tp);
    let afterRes = baseUtil.isFun(afterOn) && afterOn(eventName, callback, options);
    return afterRes || beforeRes;
  }

  /**
   * 取消监听回调，不传 callBack 清除 eventName的所有监听事件 
   * @param {string} eventName 
   * @param {Function} callback 
   * @param {Object} [options]
   */
  off(eventName, callback, options = null, tp) {
    if (this.isClean(eventName, tp)) return

    const { beforeOff, afterOff } = this._opt;
    let beforeRes = baseUtil.isFun(beforeOff) && beforeOff(eventName, callback, options, tp);
    let res = tp ? this._eventer.off('', callback, tp) : this._eventer.off(eventName, callback);
    if (this.isClean(eventName)) this._tryClear(eventName);
    let afterRes = baseUtil.isFun(afterOff) && afterOff(eventName, callback, options, tp);
    return afterRes || beforeRes;
  }

  /**
   * 事件仅触发一次
   * @param {string} eventName 
   * @param {Function} callback 
   * @param {Object} [options]
   */
  once(eventName, callback, options = null, tp) {
    const cb = (...params) => {
      try { callback && callback(...params) } catch (err) {
        //
      }
      this.off(eventName, cb, options, tp)
    }
    return this.on(eventName, cb, options, tp)
  }

  /**
   * 重置事件监听，每次都覆盖
   * @param {string} eventName 
   * @param {Function} callback 
   * @param {Object} [options]
   */
  reset(eventName, callback, options = null, tp) {
    this.off(eventName, null, options, tp);
    return this.on(eventName, callback, options, tp);
  }

  /**
   * 事件是否清除干净
   * @param {string} eventName 
   */
  isClean(eventName, tp) {
    return this._eventer.isClean(eventName, tp);
  }
}
