<template>
  <div class="text-sm">
    <div class="flex items-center gap-2">
      <div v-if="isPending" class="w-5 h-5">
        <ProgressSpinner style="width: 100%; height: 100%" strokeWidth="8" fill="transparent" />
      </div>
      <Checkbox v-else v-model="enabled" inputId="webPush" name="delivery" binary />

      <label for="webPush">Прислать уведомление, когда придет ответ</label>
    </div>

    <!-- Инструкции для iOS -->
    <div
      v-if="showRequireStandaloneInstructionsForIOS"
      class="bg-yellow-100 text-yellow-800 p-4 rounded my-4"
    >
      <p class="mb-2">Чтобы включить уведомления, добавьте это приложение на главный экран:</p>
      <ul class="list-disc pl-5">
        <li class="mb-1">
          Нажмите
          <strong class="font-semibold">
            "<img
              src="@/assets/icons/apple-share.svg?url"
              alt="Поделиться"
              class="h-7 -mt-2 inline-block"
            />"
          </strong>
          внизу экрана
        </li>
        <li class="mb-1">
          Выберите
          <strong class="inline-flex items-baseline font-semibold">
            <span class="me-1">"На экран «Домой»</span>
            <img
              src="@/assets/icons/apple-system-plus.svg?url"
              alt=""
              class="h-4 inline-block self-center"
            />"
          </strong>
        </li>
        <li>Откройте приложение с главного экрана и повторите попытку.</li>
      </ul>
    </div>

    <!-- Ошибка разрешений -->
    <p v-else-if="isError" class="text-red-500 mb-2">{{ error?.message || error }}<br /></p>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useMutation } from '@tanstack/vue-query'
import {
  getVapidPublicKey,
  getWebPushSubscriptionDocument,
  saveWebPushSubscription,
} from '@/api/webPush'
import { getUserChatSettingsDocument } from '@/api/userChatSettings'
import type { UserChatSettingsDocument } from '@hereconnect/types'
import { isNotFoundError } from '@/api/PouchDB'
import { saveUserChatSettings } from '@/api/userChatSettings'
import { getQrCodeDocument } from '@/api/qrCode'

// Проверки iOS и запуска из главного экрана
const isIOS = computed(
  () => /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window && window.MSStream),
)
const isStandalone = computed(() => 'standalone' in window.navigator && window.navigator.standalone)

const { qr_code_uri, chat, user_chat_role } = defineProps<{
  qr_code_uri: UserChatSettingsDocument['qr_code_uri']
  chat: UserChatSettingsDocument['chat']
  user_chat_role: UserChatSettingsDocument['user_chat_role']
}>()

const enabled = ref<boolean>(false)

const subscribeOptionsPromise = getVapidPublicKey().then((applicationServerKey) => ({
  userVisibleOnly: true,
  applicationServerKey,
}))

// Функция запроса разрешений и подписки
async function requestNotificationPermission() {
  if (!('Notification' in window)) {
    throw new Error(
      isIOS.value && !isStandalone.value
        ? 'Добавьте приложение на главный экран, чтобы использовать уведомления.'
        : 'Уведомления не поддерживаются этим браузером.',
    )
  }

  const permission = await Notification.requestPermission()
  if (permission !== 'granted') {
    throw new Error(`Разрешение на уведомления не предоставлено: ${permission}`)
  }

  const registration = await navigator.serviceWorker.ready
  const subscription = await registration.pushManager
    .subscribe(await subscribeOptionsPromise)
    .catch(async (error) => {
      console.debug('subscribe error', error)
      const oldSubscription = await registration.pushManager.getSubscription()
      if (!oldSubscription) {
        throw error
      }
      await oldSubscription.unsubscribe()
      return registration.pushManager.subscribe(await subscribeOptionsPromise)
    })

  return saveWebPushSubscription(subscription)
}

const getPushSubscription = async () => {
  try {
    if ('serviceWorker' in navigator && 'PushManager' in window) {
      const registration = await navigator.serviceWorker.ready

      const permission = await registration.pushManager.permissionState(
        await subscribeOptionsPromise,
      )
      console.debug('permission', permission)
      if (permission === 'prompt') {
        return
      }
      if (permission !== 'granted') {
        throw new Error(`Разрешение на уведомления не предоставлено: ${permission}`)
      }

      const subscription = await registration.pushManager.getSubscription()
      if (subscription) {
        console.debug('Уже есть активная подписка:', subscription)
        return subscription
      } else {
        console.debug('Нет активной подписки на Push-уведомления.')
      }
    } else {
      console.warn('Push уведомления или Service Worker не поддерживаются в этом браузере.')
    }
  } catch (error) {
    console.error('Произошла ошибка при получении подписки:', error)
    throw error
  }
}

const stage = ref<'receivePushSubscription' | 'createPushSubscription' | 'removePushSubscription'>(
  'receivePushSubscription',
)

// Хуки для состояния запроса
const { isPending, isError, error, mutate } = useMutation({
  mutationKey: [stage],
  mutationFn: async () => {
    console.debug('stage', stage.value)
    try {
      if (stage.value === 'receivePushSubscription') {
        const chatSettingsDocument = await getUserChatSettingsDocument({
          qr_code_uri,
          chat,
          user_chat_role,
        }).catch((error) => {
          if (!isNotFoundError(error)) {
            console.debug('chatSettingsDocument error not found - its ok', error)
            throw error
          }
          console.debug('chatSettingsDocument error', error)
        })
        if (chatSettingsDocument) {
          console.debug('chatSettingsDocument', chatSettingsDocument)
        }
        if (
          (chatSettingsDocument && chatSettingsDocument.is_push_notification_enabled) ||
          (!chatSettingsDocument &&
            user_chat_role === 'owner' &&
            (await getQrCodeDocument(qr_code_uri)).messageDeliveryMethod === 'webPush')
        ) {
          const [subscription, subscriptionDocument] = await Promise.all([
            getPushSubscription(),
            getWebPushSubscriptionDocument().catch((error) => {
              if (!isNotFoundError(error)) throw error
            }),
          ])
          if (subscription) {
            if (!subscriptionDocument) {
              await saveWebPushSubscription(subscription)
            }
            enabled.value = true
            stage.value = 'removePushSubscription'
          } else {
            stage.value = 'createPushSubscription'
            enabled.value = false
          }
        } else {
          stage.value = 'createPushSubscription'
        }
      } else if (stage.value === 'createPushSubscription') {
        await requestNotificationPermission()
        await saveUserChatSettings({
          qr_code_uri,
          chat,
          user_chat_role,
          is_push_notification_enabled: true,
        })
      } else if (stage.value === 'removePushSubscription') {
        await saveUserChatSettings({
          qr_code_uri,
          chat,
          user_chat_role,
          is_push_notification_enabled: false,
        })
      }
    } catch (error) {
      enabled.value = false
      console.debug('unknown error at stage ', stage.value, error)
      throw error
    }
    return null
  },
  retry: false,
})

watch(
  [() => stage.value, () => enabled.value],
  () => {
    if (stage.value === 'removePushSubscription') {
      if (!enabled.value) mutate()
    } else if (stage.value === 'createPushSubscription') {
      if (enabled.value) mutate()
    } else {
      mutate()
    }
  },
  { immediate: true },
)

const showRequireStandaloneInstructionsForIOS = computed(
  () => isError.value && isIOS.value && !isStandalone.value && enabled.value,
)
</script>
