import { ref, computed, type Ref } from 'vue'

/**
 * Wraps the browser PWA-install lifecycle. Three reactive flags drive the
 * Settings UI:
 *
 *   isStandalone       — already installed (display-mode standalone or iOS
 *                        navigator.standalone). UI hides the install row
 *                        when true.
 *   isIOS              — iOS Safari, where there is no programmatic install.
 *                        UI shows a "show me how" button that opens an
 *                        instructions modal.
 *   canPromptInstall   — Android Chrome captured a beforeinstallprompt
 *                        event we can fire. UI shows a native "Install"
 *                        button that calls install().
 *
 * Module-level singleton: beforeinstallprompt fires once per page load and
 * may fire before the user navigates to Settings, so we register the
 * listener immediately on first import and cache the event.
 */

interface BeforeInstallPromptEvent extends Event {
  prompt: () => Promise<void>
  userChoice: Promise<{ outcome: 'accepted' | 'dismissed'; platform: string }>
}

const installEvent: Ref<BeforeInstallPromptEvent | null> = ref(null)
const isStandalone = ref(false)

function detectStandalone(): boolean {
  if (typeof window === 'undefined') return false
  if (window.matchMedia?.('(display-mode: standalone)').matches) return true
  // iOS Safari uses a non-standard navigator.standalone
  return (window.navigator as Navigator & { standalone?: boolean }).standalone === true
}

function detectIOS(): boolean {
  if (typeof navigator === 'undefined') return false
  const ua = navigator.userAgent
  // iPad on iOS 13+ reports as Macintosh; check for touch points.
  const iPadOS = ua.includes('Mac') && navigator.maxTouchPoints > 1
  return /iPhone|iPod/.test(ua) || iPadOS
}

let registered = false
function registerOnce() {
  if (registered || typeof window === 'undefined') return
  registered = true

  isStandalone.value = detectStandalone()

  window.addEventListener('beforeinstallprompt', (e: Event) => {
    // Stash the event so we can fire it later from the install button.
    // preventDefault stops Chrome's default mini-info bar so we control
    // the timing.
    e.preventDefault()
    installEvent.value = e as BeforeInstallPromptEvent
  })

  window.addEventListener('appinstalled', () => {
    installEvent.value = null
    isStandalone.value = true
  })

  window.matchMedia?.('(display-mode: standalone)').addEventListener('change', (e) => {
    isStandalone.value = e.matches
  })
}

registerOnce()

export function usePwaInstall() {
  const isIOS = detectIOS()
  const canPromptInstall = computed(() => installEvent.value !== null)

  /**
   * Trigger the native install prompt (Android Chrome). Resolves to true if
   * the user accepted, false if they dismissed or no prompt was available.
   * The event is one-shot; canPromptInstall flips false after a call.
   */
  async function install(): Promise<boolean> {
    const e = installEvent.value
    if (!e) return false
    await e.prompt()
    const choice = await e.userChoice
    installEvent.value = null
    return choice.outcome === 'accepted'
  }

  return {
    isStandalone,
    isIOS,
    canPromptInstall,
    install,
  }
}

// Test-only — reset the singleton state so each test starts clean.
export function __resetPwaInstallForTests() {
  installEvent.value = null
  isStandalone.value = false
  registered = false
}
