export const UPDATE_NOTIFICATION = 'UPDATE_NOTIFICATION'
export const CONFIRM_NOTIFICATION = 'CONFIRM_NOTIFICATION'

import { initializeApp } from 'firebase/app'
import { getMessaging, getToken, deleteToken } from 'firebase/messaging'

import { synchronize } from '@things-factory/utils'

var vapidKey
var appConfig
var messaging

async function _getVapidKey() {
  if (!vapidKey || !appConfig) {
    if (Notification.permission === 'denied') {
      console.warn('Notification permission denied')
      return
    }

    const response = await fetch('/notification/config', {
      headers: {
        Accept: 'application/json'
      }
    })
    if (!response.ok) {
      throw new Error(`fail to get notification configuration: ${response.status}`)
    }
    const conf = await response.json()

    if (!conf || !conf.vapidPublicKey || !conf.appConfig) {
      throw new Error('correct notification configuration required.')
    }

    try {
      const app = await initializeApp(conf.appConfig)
      messaging = getMessaging(app)

      // messaging = _messaging.isSupported() ? _messaging() : null
      if (!messaging) {
        console.warn('###################################################')
        console.warn('push notification is not supported in this browser.')
        console.warn('###################################################')
      }

      vapidKey = conf.vapidPublicKey
      appConfig = conf.appConfig
    } catch (err) {
      throw new Error(`failed to initialize firebase app.`)
    }
  }

  return { vapidKey, messaging }
}

// to avoid race condition
const getVapidKey = synchronize(_getVapidKey) as any

export async function isSupportingMessaging() {
  const { messaging } = (await getVapidKey()) || {}
  return !!messaging
}

export async function getSubscriptionToken(force = false) {
  // const registration = await navigator.serviceWorker.getRegistration('/')
  const registration = await navigator.serviceWorker?.ready

  if (!registration) {
    console.warn('service worker not registered.')
    return
  }

  if (!registration.pushManager || (!force && !(await registration.pushManager.getSubscription()))) {
    return
  }

  const { vapidKey, messaging } = (await getVapidKey()) || {}

  try {
    return (
      vapidKey &&
      (await getToken(messaging, {
        vapidKey,
        serviceWorkerRegistration: registration
      }))
    )
  } catch (err) {
    console.error(err)
  }
}

export async function subscribe() {
  const token = await getSubscriptionToken(true)

  if (!token) {
    return
  }

  await fetch('/notification/register', {
    method: 'post',
    headers: {
      'Content-type': 'application/json',
      Accept: 'application/json'
    },
    body: JSON.stringify({
      subscription: token
    })
  })

  return token
}

export async function unsubscribe() {
  const token = await getSubscriptionToken()
  if (!token) {
    return
  }

  try {
    const { vapidKey, messaging } = (await getVapidKey()) || {}
    vapidKey && (await deleteToken(messaging))
  } catch (err) {
    console.error(err)
  }

  await fetch('/notification/unregister', {
    method: 'post',
    headers: {
      'Content-type': 'application/json',
      Accept: 'application/json'
    },
    body: JSON.stringify({
      subscription: token
    })
  })
}

export async function notify(options) {
  const response = await fetch('/notification/notify', {
    method: 'post',
    headers: {
      'Content-type': 'application/json',
      Accept: 'application/json'
    },
    body: JSON.stringify(options)
  })

  return response.ok
}
