/* Service Worker for Chorly push notifications */

/* Activate immediately — no waiting for old tabs to close */
self.addEventListener('install', function (event) {
  event.waitUntil(self.skipWaiting())
})

self.addEventListener('activate', function (event) {
  event.waitUntil(self.clients.claim())
})

self.addEventListener('push', function (event) {
  if (!event.data) return

  let payload
  try {
    payload = event.data.json()
  } catch (e) {
    payload = { title: 'Chorly', body: event.data.text() }
  }

  const title = payload.title || 'Chorly'
  // Android Chrome has a bug where event.action is unreliable — only show Approve
  // so tapping it always executes the correct action.
  const isAndroidChrome =
    /Android/.test(self.navigator.userAgent) && /Chrome\//.test(self.navigator.userAgent)
  // Expiry-warning notifications are informational only — no action buttons
  const actions =
    payload.type === 'chore_expiring_soon'
      ? []
      : isAndroidChrome
        ? [{ action: 'approve', title: 'Approve' }]
        : [
            { action: 'approve', title: 'Approve' },
            { action: 'deny', title: 'Reject' },
          ]
  const options = {
    body: payload.body || '',
    icon: '/icons/icon-192x192.png',
    data: payload,
    actions,
  }

  event.waitUntil(self.registration.showNotification(title, options))
})

self.addEventListener('notificationclick', function (event) {
  event.notification.close()

  const payload = event.notification.data || {}
  const approveToken = payload.approve_token
  const denyToken = payload.deny_token
  const childId = payload.child_id
  const entityId = payload.entity_id
  const entityType = payload.entity_type

  function navigateOrOpen(url) {
    return clients
      .matchAll({ type: 'window', includeUncontrolled: true })
      .then(function (clientList) {
        const sameOriginClients = clientList.filter(function (c) {
          return new URL(c.url).origin === self.location.origin
        })
        if (sameOriginClients.length > 0) {
          const client = sameOriginClients[0]
          return client.focus().then(function () {
            return client.navigate(url)
          })
        }
        return clients.openWindow(url)
      })
  }

  function executeDigestAction(token) {
    return fetch('/api/digest-action/' + token, {
      method: 'POST',
      credentials: 'include',
    })
      .then(function (res) {
        if (res.ok) {
          // Action executed — navigate to parent view to show the result
          var successUrl =
            childId && entityId && entityType
              ? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType
              : '/parent'
          return navigateOrOpen(successUrl)
        }
        if (res.status === 401) {
          // Not authenticated — navigate with digestToken so the PIN flow executes the action
          var authUrl =
            childId && entityId && entityType
              ? '/parent/' +
                childId +
                '?digestToken=' +
                token +
                '&scrollTo=' +
                entityId +
                '&entityType=' +
                entityType
              : '/parent'
          return navigateOrOpen(authUrl)
        }
        // Token invalid/used/expired — navigate to parent
        return navigateOrOpen(childId ? '/parent/' + childId : '/parent')
      })
      .catch(function () {
        return navigateOrOpen('/parent')
      })
  }

  if (event.action === 'approve' && approveToken) {
    event.waitUntil(executeDigestAction(approveToken))
    return
  }

  if (event.action === 'deny' && denyToken) {
    event.waitUntil(executeDigestAction(denyToken))
    return
  }

  // Body tap — open or focus the app then navigate to the deep link
  const deepLinkUrl =
    childId && entityId && entityType
      ? '/parent/' + childId + '?scrollTo=' + entityId + '&entityType=' + entityType
      : '/parent'

  event.waitUntil(navigateOrOpen(deepLinkUrl))
})
