import { ref } from 'vue'

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

const urlBase64ToArrayBuffer = (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
}

const isBraveBrowser = async () => {
  try {
    return Boolean(navigator.brave && await navigator.brave.isBrave())
  } catch {
    return false
  }
}

const explainSubscribeError = async (error) => {
  const message = error instanceof Error ? error.message : 'push service error'
  const brave = await isBraveBrowser()
  if (brave && /push service|registration failed|not available|permission/i.test(message)) {
    return 'Brave is blocking Web Push. In Brave settings, enable "Use Google services for push messaging", then fully close and reopen the installed L484 app.'
  }
  if (/push service|registration failed|not available/i.test(message)) {
    return 'The browser push service is unavailable. In Brave, enable "Use Google services for push messaging"; otherwise fully close and reopen the installed app, then try again.'
  }
  return `Push registration failed: ${message}. Fully close and reopen the installed app, then try again.`
}

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 subscribeWithRetry = async (registration, applicationServerKey) => {
  try {
    return await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
  } catch (error) {
    await registration.update().catch(() => {})
    await new Promise((resolve) => window.setTimeout(resolve, 750))
    const activeRegistration = await navigator.serviceWorker.ready
    try {
      return await activeRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey })
    } catch (retryError) {
      throw new Error(await explainSubscribeError(retryError || error))
    }
  }
}

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')
  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 = urlBase64ToArrayBuffer(keyData.publicKey)

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

  const registered = await navigator.serviceWorker.register('/sw.js', { scope: '/', updateViaCache: 'none' })
  await registered.update().catch(() => {})
  const readyRegistration = await navigator.serviceWorker.ready
  const existing = await readyRegistration.pushManager.getSubscription()
  if (existing) return saveSubscription(existing)

  const subscription = await subscribeWithRetry(readyRegistration, applicationServerKey)
  return saveSubscription(subscription)
}
