---
import { Icon } from 'astro-icon/components'
import { VAPID_PUBLIC_KEY } from 'astro:env/server'

import { SUPPORT_EMAIL } from '../constants/project'
import { cn } from '../lib/cn'

import Button from './Button.astro'

import type { Prisma } from '@prisma/client'
import type { HTMLAttributes } from 'astro/types'

type Props = HTMLAttributes<'div'> & {
  dismissable?: boolean
  hideIfEnabled?: boolean
  pushSubscriptions: Prisma.PushSubscriptionGetPayload<{
    select: {
      endpoint: true
    }
  }>[]
}

const { class: className, dismissable = false, pushSubscriptions, hideIfEnabled, ...props } = Astro.props
---

<div
  data-push-notification-banner
  data-dismissed={undefined as true | undefined /* Updated by client script */}
  data-notification-supported={undefined as true | undefined /* Updated by client script */}
  data-push-subscriptions={JSON.stringify(pushSubscriptions)}
  data-is-enabled={undefined as true | undefined /* Updated by client script */}
  data-loaded={undefined as true | undefined /* Updated by client script */}
  data-notification-permissions={undefined as
    | NotificationPermission
    | undefined /* Updated by client script */}
  data-vapid-public-key={VAPID_PUBLIC_KEY}
  class={cn(
    'no-js:hidden xs:grid-cols-[auto_auto] xs:justify-between relative isolate grid items-center justify-stretch gap-4 overflow-hidden rounded-xl bg-gradient-to-r from-blue-950/80 to-blue-900/60 p-4 not-data-loaded:hidden',
    'data-dismissed:hidden',
    hideIfEnabled && 'data-is-enabled:hidden',
    'not-data-notification-supported:hidden',
    'data-is-enabled:**:data-show-if-disabled:hidden not-data-is-enabled:**:data-show-if-enabled:hidden',
    className
  )}
  {...props}
>
  <div aria-hidden="true" class="pointer-events-none absolute inset-0 -z-10 overflow-hidden">
    <div
      class="absolute top-0 -left-16 h-full w-1/3 bg-gradient-to-r from-blue-500/20 to-transparent opacity-50 blur-xl"
    >
    </div>
    <div
      class="absolute top-0 -right-16 h-full w-1/3 bg-gradient-to-l from-blue-500/20 to-transparent opacity-50 blur-xl"
    >
    </div>
  </div>

  <div class="flex items-center gap-x-3">
    <div class="rounded-md bg-blue-800/30 p-2">
      <Icon name="ri:notification-4-line" class="size-5 text-blue-300" />
    </div>
    <div>
      <h3 class="font-medium text-blue-100" data-banner-title>Turn on push notifications?</h3>
      <p class="text-sm text-blue-200/80" data-banner-description>Get notifications on this device.</p>
    </div>
  </div>

  <div class="xs:justify-end flex shrink flex-wrap items-center justify-center gap-2">
    {dismissable && <Button as="span" label="Skip" variant="faded" data-dismiss-button />}
    <Button
      as="span"
      label="Yes, notify me"
      color="white"
      data-push-action="subscribe"
      data-show-if-disabled
    />
    <Button
      as="span"
      label="Stop notifications"
      color="white"
      variant="faded"
      data-push-action="unsubscribe"
      data-show-if-enabled
    />
  </div>

  <div
    class="col-span-full flex items-center justify-center gap-2 leading-tight text-red-500 has-[[data-error-message]:empty]:hidden"
  >
    <Icon name="ri:error-warning-line" class="size-5 shrink-0" />
    <span>
      <span data-error-message></span>
      <a href={`mailto:${SUPPORT_EMAIL}`} class="text-red-300 underline hover:text-red-200">
        Contact support
      </a>
    </span>
  </div>
</div>

<script>
  /////////////////////////////////////////////////////////////
  // Script to handle push notification banner dismissal.    //
  /////////////////////////////////////////////////////////////

  import { typedLocalStorage } from '../lib/localstorage'

  document.addEventListener('astro:page-load', () => {
    let pushNotificationsBannerDismissedAt = typedLocalStorage.pushNotificationsBannerDismissedAt.get()

    if (
      pushNotificationsBannerDismissedAt &&
      pushNotificationsBannerDismissedAt < new Date(Date.now() - 1000 * 60 * 60 * 24 * 365) // 1 year
    ) {
      typedLocalStorage.pushNotificationsBannerDismissedAt.remove()
      pushNotificationsBannerDismissedAt = undefined
    }

    document.querySelectorAll<HTMLElement>('[data-push-notification-banner]').forEach((banner) => {
      const skipButton = banner.querySelector<HTMLElement>('[data-dismiss-button]')
      if (!skipButton) return

      if (pushNotificationsBannerDismissedAt) {
        banner.dataset.dismissed = ''
      }

      skipButton.addEventListener('click', (event) => {
        event.preventDefault()
        event.stopPropagation()

        banner.dataset.dismissed = ''

        const now = new Date()
        typedLocalStorage.pushNotificationsBannerDismissedAt.set(now)
        pushNotificationsBannerDismissedAt = now
      })
    })
  })
</script>

<script>
  ///////////////////////////////////////////
  // Script to handle push notifications.  //
  ///////////////////////////////////////////

  import {
    subscribeToPushNotifications,
    unsubscribeFromPushNotifications,
    parsePushSubscriptions,
    isCurrentDeviceSubscribed,
    supportsPushNotifications,
    type SafeResult,
  } from '../lib/client/clientPushNotifications'

  import {
    enableBrowserNotifications,
    disableBrowserNotifications,
    isBrowserNotificationsEnabled,
    supportsBrowserNotifications,
  } from '../lib/client/browserNotifications'

  async function setDataAttributes(banner: HTMLElement) {
    if (!supportsPushNotifications() && !supportsBrowserNotifications()) {
      return
    }

    banner.dataset.notificationSupported = ''
    banner.dataset.notificationPermissions = Notification.permission

    const serverSubscriptions = parsePushSubscriptions(banner.dataset.pushSubscriptions)
    const titleElement = banner.querySelector<HTMLElement>('[data-banner-title]')
    const descriptionElement = banner.querySelector<HTMLElement>('[data-banner-description]')

    if (await isCurrentDeviceSubscribed(serverSubscriptions)) {
      if (titleElement) titleElement.textContent = 'Push notifications enabled'
      if (descriptionElement) descriptionElement.textContent = 'Turn push notifications off for this device?'
      banner.dataset.isEnabled = ''
      banner.dataset.loaded = ''
      return
    }

    if (isBrowserNotificationsEnabled()) {
      if (titleElement) titleElement.textContent = 'Browser notifications enabled'
      if (descriptionElement)
        descriptionElement.textContent = 'Turn off notifications? (They only work while the tab is open.)'
      banner.dataset.isEnabled = ''
      banner.dataset.loaded = ''
      return
    }

    // Default state (disabled)
    if (titleElement) titleElement.textContent = 'Turn on push notifications?'
    if (descriptionElement) descriptionElement.textContent = 'Get notifications on this device.'
    banner.dataset.loaded = ''
  }

  document.addEventListener('astro:page-load', async () => {
    document.querySelectorAll<HTMLElement>('[data-push-notification-banner]').forEach(async (banner) => {
      await setDataAttributes(banner)

      const vapidPublicKey = banner.dataset.vapidPublicKey

      banner.querySelectorAll<HTMLElement>('[data-push-action]').forEach((button) => {
        button.addEventListener('click', async (event) => {
          event.preventDefault()
          event.stopPropagation()

          const action = button.dataset.pushAction
          if (action !== 'subscribe' && action !== 'unsubscribe') {
            console.error('Invalid push action:', action)
            return
          }

          let result: SafeResult

          if (action === 'subscribe') {
            const pushResult = vapidPublicKey
              ? await subscribeToPushNotifications(vapidPublicKey)
              : { success: false as const, error: 'VAPID public key not found' }

            if (pushResult.success) {
              result = pushResult
            } else {
              console.error(
                "Can't enable push notifications, trying browser notifications.",
                pushResult.error
              )
              const browserResult = await enableBrowserNotifications()

              if (browserResult.success) {
                result = browserResult
              } else {
                console.error("Can't enable browser notifications:", browserResult.error)
                result = {
                  success: false,
                  error: `Can't enable either push or browser notifications. Push: ${pushResult.error}. Browser: ${browserResult.error}`,
                }
              }
            }
          } else {
            const pushResult = await unsubscribeFromPushNotifications()
            const browserResult = disableBrowserNotifications()

            const success = pushResult.success || browserResult.success

            result = success
              ? { success: true }
              : { success: false, error: `${pushResult.error} | ${browserResult.error}` }
          }

          if (!result.success) {
            console.error(result.error)

            const errorMessageElement = banner.querySelector<HTMLElement>('[data-error-message]')
            if (errorMessageElement) {
              errorMessageElement.textContent = `Failed to ${action === 'subscribe' ? 'enable' : 'disable'} notifications.`
            }

            return
          }

          window.location.reload()
        })
      })
    })
  })
</script>
