/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-unused-vars */
import Vue, { CreateElement, VNode } from 'vue';
import { QXEvent } from 'qx-util';
import { IOverlayContainer } from '@ibiz-template/runtime';
import router from '@/router';
import { piniaInstance } from '@/store';

/**
 * 全局弹出承载组件
 *
 * @author chitanda
 * @date 2022-11-09 12:11:09
 * @export
 * @class OverlayContainer
 */
export class OverlayContainer<O> implements IOverlayContainer {
  /**
   * vue 飘窗呈现实例
   *
   * @author chitanda
   * @date 2022-11-09 12:11:09
   * @protected
   * @type {Vue}
   */
  protected vm?: Vue;

  /**
   * 具体模态组件
   *
   * @author chitanda
   * @date 2022-11-09 12:11:34
   * @protected
   * @type {*}
   */
  protected modal: any;

  /**
   * 外面调用dismiss时传的result结果
   *
   * @author lxm
   * @date 2022-11-09 20:11:06
   * @protected
   * @type {unknown}
   */
  protected result?: unknown;

  /**
   * 内部事件
   *
   * @author chitanda
   * @date 2022-11-09 12:11:42
   * @protected
   */
  protected evt: QXEvent<{ dismiss: (data?: unknown) => void }> = new QXEvent();

  /**
   * 创建全局呈现
   *
   * @author chitanda
   * @date 2022-11-09 14:11:52
   * @param {unknown} component
   * @param {(h: CreateElement) => VNode} render
   * @param {IPopoverOptions} [opts]
   */
  constructor(
    protected component: unknown,
    protected render: (h: CreateElement) => VNode,
    protected opts?: O,
  ) {
    this.init();
  }

  /**
   * 初始化飘窗
   *
   * @author chitanda
   * @date 2022-11-09 12:11:55
   * @protected
   * @return {*}  {void}
   */
  protected init(): void {
    const self = this;
    const { render, opts } = this;
    const container = document.createElement('div');
    document.body.appendChild(container);
    const vm = new Vue({
      el: container,
      pinia: piniaInstance,
      router,
      beforeDestroy() {
        vm!.$el.remove();
      },
      mounted() {
        self.modal = this.$refs.root;
      },
      destroyed() {
        self.evt.emit('dismiss', self.result);
      },
      render(h) {
        return h(
          self.component as string,
          {
            ref: 'root',
            props: { opts },
            on: {
              dismiss() {
                vm!.$destroy();
              },
            },
          },
          [render(h)],
        );
      },
    });
    this.vm = vm;
  }

  /**
   * 打开飘窗
   *
   * @author chitanda
   * @date 2022-11-09 12:11:52
   * @param {HTMLElement} target
   * @return {*}  {Promise<void>}
   */
  async present(): Promise<void> {
    return this.modal.present();
  }

  /**
   * 手动调用关闭飘窗
   *
   * @author chitanda
   * @date 2022-11-09 12:11:39
   * @param {unknown} [data]
   * @return {*}  {Promise<void>}
   */
  async dismiss(data?: unknown): Promise<void> {
    this.result = data;
    this.modal.dismiss();
  }

  /**
   * 订阅窗口关闭
   *
   * @author chitanda
   * @date 2022-11-09 12:11:20
   * @template T
   * @return {*}  {Promise<T>}
   */
  async onWillDismiss<T = unknown>(): Promise<T> {
    return new Promise<T>(resolve => {
      const callback = (data: unknown) => {
        resolve(data as T);
        this.evt.off('dismiss', callback);
      };
      this.evt.on('dismiss', callback);
    });
  }
}
