import Vue from 'vue';
import { Route, NavigationGuardNext } from 'vue-router';

type AsyncHandler<A, R> = (args: A) => Promise<R>;

interface EventHandlers {
  [key: string]: AsyncHandler<any, any>;
}

type MfeWrapperOptions = {
  mountHandle: Function;
  wrapperRef: string;
  containerBaseUrl: string;
  componentBaseUrl: string;
  startUrl?: string;
  useShadowDom?: boolean;
  eventHandlers: EventHandlers;
}

function mfeWrapper({
  mountHandle,
  wrapperRef,
  containerBaseUrl,
  componentBaseUrl,
  startUrl,
  useShadowDom,
  eventHandlers,
}: MfeWrapperOptions) {
  const _mfe_wrapper_callbacks_to_unsubscribe: Array<Function> = [];
  let _mfe_wrapper_callback_to_unmount: Function = () => { };

  return Vue.extend({
    mounted() {
      const { parentEventHandler, unmount } = mountHandle(this.$refs[wrapperRef], {
        useShadowDom,
        containerBaseUrl: containerBaseUrl,
        componentBaseUrl: componentBaseUrl,
        startUrl: startUrl || this.$route.fullPath,
        childEventHandler: (eventType: string, eventData: any) => {
          // console.log(`|${_mfe_wrapper_id}|> microws: childEventHandler`, eventType, eventData);
          if (eventType === "navigate") {
            if (this.$route.fullPath !== eventData) {
              this.$router.push(eventData);
            }
          }
          if (eventHandlers && eventType in eventHandlers) {
            return eventHandlers[eventType](eventData);
          }
        }
      });
      if (typeof (unmount) === 'function') _mfe_wrapper_callback_to_unmount = unmount;
      _mfe_wrapper_callbacks_to_unsubscribe.push(
        this.$router.beforeEach((to: Route, from: Route, next: NavigationGuardNext) => {
          if (parentEventHandler) {
            const handlerResult = parentEventHandler('navigate', to.fullPath);
            if (handlerResult == null) {
              next();
            } else {
              handlerResult.then((result: any) => {
                if (result !== false) {
                  next();
                }
              });
            }
          }
        })
      );
    },

    destroyed() {
      for (const unsubscribe_callback of _mfe_wrapper_callbacks_to_unsubscribe) {
        unsubscribe_callback();
      }
      _mfe_wrapper_callback_to_unmount();
    }
  });
}

export default mfeWrapper;
