import type VueType from 'vue'
import { PluginFunction } from 'vue'
import { handleRouteConfig } from './utils'
import { version } from './package.json'
import { install } from './install'

export interface MonitorElement extends HTMLElement {
  __monitor_actions?: string[]
  __monitor?: Monitor
}

export interface MonitorReportData {
  operation: string
  module: string
  params?: any
  remark?: string
}

export interface MonitorElementData {
  [event: string]: MonitorReportData
}

type ReportRequest = (data: unknown) => any
interface Options {
  report: ReportRequest
}

export default class Monitor {
  static install: PluginFunction<undefined>
  static version: string

  private _report!: ReportRequest
  private _app!: VueType
  private _apps: VueType[] = []

  constructor(options: Options) {
    this.setReportRequest(options.report)
  }

  init(app: VueType) {
    this._apps.push(app)

    if (this._app) return
    this._app = app

    this.routeGuard()
  }

  setReportRequest(report: ReportRequest) {
    this._report = report
  }

  routeGuard() {
    const router = this._app.$options?.router

    if (!router) return
    router.beforeEach((to, from, next) => {
      this._report?.({
        operation: '页面跳转',
        module: '',
        remark: '页面跳转',
        params: JSON.stringify({ to: handleRouteConfig(to), from: handleRouteConfig(from) }),
      })
      next()
    })
  }

  private _request(data: MonitorReportData, withPageInfo: boolean) {
    const { params = {}, ...rest } = data
    if (withPageInfo) {
      const { fullPath, path, query } = this._app.$options.router.app._route
      Object.assign(params, { fullPath, path, query })
    }

    return this._report({ ...rest, params: JSON.stringify(params) })
  }

  request(data: MonitorReportData) {
    return this._request(data, false)
  }

  requestWithPage(data: MonitorReportData) {
    return this._request(data, true)
  }
}

Monitor.install = install
Monitor.version = version

if (typeof window !== undefined && window.Vue) {
  window.Vue.use(Monitor)
}

export { directive } from './directive'
export { MonitorComponent } from './component'

export { Monitor }

/**
 * @param {MonitorReportData} data
 * @param {string | string []} event default `click`
 */
export const createEventMonitorData = (
  data: MonitorReportData,
  event: string | string[] = 'click'
): MonitorElementData => {
  const events = ([] as string[]).concat(event)
  return events.reduce((map, key) => {
    map[key] = data

    return map
  }, {})
}

export const defineMonitorData = (data: MonitorReportData): MonitorReportData => data
