import { VNode } from 'vue';
import { IBzTooltipUtil } from './ibz-tooltip-util';
import { off, on } from '@ibizstudio/runtime';
import { DirectiveBinding } from 'vue/types/options';

/**
 * 全局tip提示控制器
 *
 * @export
 * @class IBzTooltipController
 */
export class IBzTooltipController {
  /**
   * 提示工具
   *
   * @type {IBzTooltipUtil}
   * @memberof IBzTooltipController
   */
  private tipUtil: IBzTooltipUtil = new IBzTooltipUtil(this);

  /**
   * 是否悬浮于元素上
   *
   * @memberof IBzTooltipController
   */
  isHover: boolean = false;

  /**
   * 定制器
   *
   * @type {*}
   * @memberof IBzTooltipController
   */
  private timer: NodeJS.Timeout | null = null;

  /**
   * 绑定
   *
   * @param {HTMLDivElement} el
   * @param {DirectiveBinding} binding
   * @param {VNode} vNode
   * @param {VNode} oldVNode
   * @memberof IBzTooltipController
   */
  bind(el: HTMLDivElement, binding: DirectiveBinding, vNode: VNode) {
    el.onmouseenter = () => {
      if (this.timer) {
        clearTimeout(this.timer);
        this.timer = null;
      }
      this.isHover = true;
      const data: any = { placement: 'auto', delay: 300 };
      this.calcAttrs(vNode.data?.attrs, data);
      this.calcParams(el, data);
      if (!data.content) {
        data.content = binding.value;
      }
      this.timer = setTimeout(() => {
        this.tipUtil.openPopover(el, data.content, data.placement, data.mode);
      }, data.delay);
    };
    el.onmouseleave = () => {
      this.destroy();
    };
    on(el, 'click', this.click);
  }

  /**
   * 取消绑定
   *
   * @param {HTMLDivElement} el
   * @param {DirectiveBinding} binding
   * @param {VNode} vNode
   * @param {VNode} oldVNode
   * @memberof IBzTooltipController
   */
  unbind(el: HTMLDivElement, binding: DirectiveBinding, vNode: VNode) {
    el.onmouseenter = null;
    el.onmouseleave = null;
    off(el, 'click', this.click);
  }

  /**
   * 项单机
   *
   * @private
   * @param {MouseEvent} e
   * @memberof IBzTooltipController
   */
  private click = (e: MouseEvent) => {
    this.destroy();
  };

  /**
   * 销毁
   *
   * @private
   * @memberof IBzTooltipController
   */
  private destroy(): void {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
    this.isHover = false;
    this.timer = setTimeout(() => {
      if (!this.tipUtil.isHover) {
        this.tipUtil.popperDestroy();
      }
    }, 50);
  }

  /**
   * 计算输入属性
   *
   * @private
   * @param {*} attrs
   * @param {*} data
   * @memberof IBzTooltipController
   */
  private calcAttrs(attrs: any, data: any): void {
    if (!attrs) {
      return;
    }
    // 在异步模式下的参数
    if (attrs['ibz-tip-render']) {
      data.content = attrs['ibz-tip-render'];
    }
  }

  /**
   * 参数计算
   *
   * @private
   * @param {HTMLDivElement} el
   * @param {*} data
   * @memberof IBzTooltipController
   */
  private calcParams(el: HTMLDivElement, data: any) {
    const attrs = el.attributes;
    // tooltip呈现模式，默认为本地模式[local]，或者采用异步呈现[async]
    this.fillAttrItem(attrs, 'mode', data);
    // 提示框显示的方向
    this.fillAttrItem(attrs, 'placement', data);
    // 缓冲等待时间，单位：毫秒，默认300毫秒
    this.fillAttrItem(attrs, 'delay', data);
    // 计算参数
    const paramsStr = attrs.getNamedItem('ibz-tip-params');
    if (paramsStr) {
      try {
        data.params = JSON.parse(paramsStr.value);
      } catch (err) {
        console.log('动态tip提示参数解析错误', err);
      }
    }
    // 当提供render时，采用render绘制提示
    if (data.content) {
      return;
    }
    if (data.mode === 'async') {
      // 绘制异步tip
      data.content = (h: any) => {
        return <ibz-tooltip-async params={data.params}/>;
      };
    } else if (attrs.getNamedItem('ibz-tip-content')) {
      this.fillAttrItem(attrs, 'content', data);
    }
  }

  /**
   * 填充参数项
   *
   * @private
   * @param {NamedNodeMap} attrs
   * @param {string} name
   * @param {*} data
   * @memberof IBzTooltipController
   */
  private fillAttrItem(attrs: NamedNodeMap, name: string, data: any): void {
    const item = attrs.getNamedItem('ibz-tip-' + name);
    if (item) {
      data[name] = item.value;
    }
  }

  /**
   * 重新计算tip位置
   *
   * @memberof IBzTooltipController
   */
  tick(): void {
    this.tipUtil.popperTick();
  }
}
/**
 * tooltip控制器实例
 */
export const itc = new IBzTooltipController();
// 挂载在window上
window.itc = itc;
