import _Vue, { PluginFunction } from 'vue'

// Import vue components
import * as components from './lib-components/index'
import * as directives from './directives/index'
import humanizePrice from './filters/humanizePrice'
import humanizeDate from './filters/humanizeDate'
import userFullName from './filters/userFullName'
import { Store } from 'vuex'
import {
  HashNavigationModule,
  MessagesModules,
  TasksModules,
  NotificationsModules,
  messagesHashNavRoutes,
  hashNavigationHookFactory,
} from '@/widgets'
import VueRouter from 'vue-router'

// Define typescript interfaces for autoinstaller
// eslint-disable-next-line @typescript-eslint/no-explicit-any
interface InstallFunction extends PluginFunction<any> {
  installed?: boolean
}

// install function executed by Vue.use()
const install: InstallFunction = function installS25vueUi(
  Vue: typeof _Vue,
  {
    store,
    router,
    widgets: { messages, tasks, notifications } = {},
  }: {
    store?: Store<unknown>
    router?: VueRouter
    widgets: { messages?: boolean; tasks?: boolean; notifications?: boolean }
  } = { widgets: {} }
) {
  if ((messages || tasks || notifications) && (!store || !router)) {
    throw new Error(
      'Widgets require a Vuex store and a Vue router for installation'
    )
  }

  if (install.installed) return
  install.installed = true

  if (store && router && (messages || tasks || notifications)) {
    for (const [name, module] of Object.entries({
      ...(messages ? MessagesModules : {}),
      ...(tasks ? TasksModules : {}),
      ...(notifications ? NotificationsModules : {}),
      HashNavigationModule,
    })) {
      store.registerModule(name, module)
    }

    const hook = hashNavigationHookFactory(store, [
      ...(messages ? Object.values(messagesHashNavRoutes) : []),
    ])

    router.beforeEach(hook)
  }

  Object.entries(directives).forEach(([directiveName, directive]) => {
    Vue.directive(directiveName, directive)
  })

  Object.entries(components).forEach(([componentName, component]) => {
    Vue.component(componentName, component)
  })

  Vue.filter('humanizePrice', humanizePrice)
  Vue.filter('humanizeDate', humanizeDate)
  Vue.filter('userFullName', userFullName)
}

// Create module definition for Vue.use()
const plugin = {
  install,
}

// Default export is library as a whole, registered via Vue.use()
export default plugin

// To allow individual component use, export components
// each can be registered via Vue.component()
export * from './lib-components/index'
export * from './directives/index'
export * from './store/index'
export * from './services/index'
export * from './helpers/index'
export * from './widgets/index'
