import { ref } from 'vue'
import { useRegisterSW } from 'virtual:pwa-register/vue'

// Singleton: one service-worker registration and one shared update state for
// the whole app. With `registerType: 'prompt'` (vite.config.js) the new SW
// precaches in the background and waits; activation is a user decision.
let registration = null

const { needRefresh, updateServiceWorker } = useRegisterSW({
  onRegisteredSW(_swScriptUrl, reg) {
    registration = reg
  },
})

const updating = ref(false)
const dismissed = ref(false)
const checkingForUpdate = ref(false)

async function applyUpdate() {
  updating.value = true
  // The page reloads when the new service worker takes control; `updating`
  // is intentionally never reset — the spinner covers the wait until reload.
  const update =
    (import.meta.env.DEV && window.__appUpdateTest?.mockUpdateFn) || updateServiceWorker
  await update(true)
}

function dismiss() {
  dismissed.value = true
}

async function checkForUpdate() {
  checkingForUpdate.value = true
  try {
    // Forces the browser to re-fetch the SW script now instead of waiting for
    // its own schedule. If it changed, Workbox flips `needRefresh` and the
    // existing modal appears with its usual Update now / Later choice.
    const check =
      (import.meta.env.DEV && window.__appUpdateTest?.mockCheckFn) || (() => registration?.update())
    await check()
  } finally {
    checkingForUpdate.value = false
  }
}

if (import.meta.env.DEV) {
  // Test hook: simulating a real SW update in Playwright would require two
  // production builds, so tests force the prompt and mock the update instead.
  window.__appUpdateTest = {
    trigger: () => {
      needRefresh.value = true
    },
    mockUpdateFn: null,
    mockCheckFn: null,
  }
}

export function useAppUpdate() {
  return {
    needRefresh,
    updating,
    dismissed,
    checkingForUpdate,
    applyUpdate,
    dismiss,
    checkForUpdate,
  }
}
