import { ref } from 'vue'

const permission = ref(typeof Notification === 'undefined' ? 'unsupported' : Notification.permission)

const urlBase64ToUint8Array = (base64String) => {
  const clean = String(base64String || '').trim().replace(/^["']|["']$/g, '')
  const padding = '='.repeat((4 - (clean.length % 4)) % 4)
  const base64 = (clean + padding).replace(/-/g, '+').replace(/_/g, '/')
  const rawData = window.atob(base64)
  const key = new Uint8Array([...rawData].map((char) => char.charCodeAt(0)))
  if (key.length !== 65 || key[0] !== 4) throw new Error('VAPID public key is not valid.')
  return key
}

export const notificationPermission = permission

export const notificationSupport = () => ({
  supported: 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window,
  secure: window.isSecureContext || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1',
})

const saveSubscription = async (subscription) => {
  const response = await fetch('/api/notifications/subscribe', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ subscription: subscription.toJSON() }),
  })
  const data = await response.json().catch(() => ({}))
  if (!response.ok) throw new Error(data.error || 'Could not save notification subscription.')
  return data
}

const sameApplicationServerKey = (subscription, applicationServerKey) => {
  const existingKey = subscription?.options?.applicationServerKey
  if (!existingKey) return true
  const existingBytes = new Uint8Array(existingKey)
  if (existingBytes.length !== applicationServerKey.length) return false
  return existingBytes.every((byte, index) => byte === applicationServerKey[index])
}

export const subscribeToNotifications = async () => {
  const support = notificationSupport()
  if (!support.supported) throw new Error('Push notifications are not supported in this browser.')
  if (!support.secure) throw new Error('Push notifications require HTTPS.')

  const keyResponse = await fetch('/api/notifications/vapid-public-key', { cache: 'no-store' })
  const keyData = await keyResponse.json().catch(() => ({}))
  if (!keyResponse.ok || !keyData.publicKey) throw new Error('VAPID public key is not configured.')
  if (!keyData.configured) throw new Error('VAPID private key is not configured on the server.')
  const applicationServerKey = urlBase64ToUint8Array(keyData.publicKey)

  const requested = Notification.permission === 'granted' ? 'granted' : await Notification.requestPermission()
  permission.value = requested
  if (requested !== 'granted') throw new Error('Notification permission was not granted.')

  await navigator.serviceWorker.register('/sw.js', { scope: '/' })
  const registration = await navigator.serviceWorker.ready
  const existing = await registration.pushManager.getSubscription()
  if (existing) {
    if (sameApplicationServerKey(existing, applicationServerKey)) return saveSubscription(existing)
    await existing.unsubscribe().catch(() => false)
  }

  const subscription = await registration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey,
  })
  return saveSubscription(subscription)
}
