import gql from 'graphql-tag'

import { notify } from '@operato/layout'
import { auth } from '@things-factory/auth-base/dist-client/auth.js'

import { i18next } from '@operato/i18n'
import { notificationStore, route, store } from '@operato/shell'
import { subscribe as graphqlSubscribe } from '@operato/graphql'

import { subscribe, unsubscribe, UPDATE_NOTIFICATION } from './actions/notification-fcm'
import notification from './reducers/notification'

var graphqlSubscription: any

export default async function bootstrap() {
  /* initialize reducers */
  store.addReducers({ notification })

  async function onnotification(notification?: any) {
    store.dispatch((async dispatch => {
      if (notification) {
        await notificationStore.add(notification)
        await notificationStore.limit()
      }

      const history = await notificationStore.getAll()

      dispatch({
        type: UPDATE_NOTIFICATION,
        history: [...history]
      })
    }) as any)
  }

  auth.on('presignout', async () => {
    try {
      await unsubscribe()
      /* await */ notificationStore.clear()
    } catch (err) {
      console.warn(err)
    }
  })

  auth.on('profile', async ({ credential }) => {
    try {
      await subscribe()
    } catch (err) {
      console.warn(err)
    }

    /*
     * subscription graphql notifications
     */
    var query = gql`
      subscription notification($subjects: [String!]) {
        notification(subjects: $subjects) {
          subject
          type
          title
          body
          url
          image
          timestamp
        }
      }
    `

    graphqlSubscription = await graphqlSubscribe(
      {
        query,
        variables: {
          subjects: ['info', 'warn', 'error', 'reload']
        }
      },
      {
        next({ data }) {
          const { notification } = data || {}
          onnotification({
            timestamp: Date.now(),
            ...notification
          })
        }
      }
    )
  })

  /* subscription web-push notification */
  const channel = new BroadcastChannel('notification')
  channel.addEventListener('message', async ({ data }) => {
    const { type } = data || {}

    switch (type) {
      case 'notificationclick':
        const { action, notification } = data

        // TODO how to follow action with notification.data
        notification.url && route(notification.url)
        break

      case 'show-reload-snackbar':
        notify({
          level: 'info',
          message: i18next.t('text.the application has been updated'),
          option: {
            action: {
              label: i18next.t('button.reload'),
              callback: () => window.location.reload()
            },
            timer: -1
          }
        })
        break

      case 'notification':
      default:
        onnotification()
    }
  })

  document.addEventListener('notify', (event: Event) => {
    let { message, level, ex = '', option = {} } = (event as CustomEvent).detail
    const title = message.split(' .\n')[0]

    if (level === 'error') {
      onnotification({
        timestamp: Date.now(),
        type: 'ERROR',
        title,
        body: ex ? ex.message : message
      })
    }
  })

  await onnotification()
}
