import type { Component } from 'solid-js'
import type { DivProps } from '../ui/utils-ui'
import { Logger } from 'besonders-logger'
import { createEffect, createSignal, Match, Show, Switch } from 'solid-js'
import { useRegisterSW } from 'virtual:pwa-register/solid'
import { createAsyncButtonHandler } from '../ui/utils-ui'
import { Iconify } from './mini-components'

const { WARN, LOG, DEBUG, VERBOSE, ERROR } = Logger.setup(Logger.INFO, { prefix: '[SW]' })

const [pwaReloadFuncSignal, setPwaReloadFunc] = createSignal<(reload: boolean) => Promise<void>>(null)
const [pwaUpdateFuncSignal, setPwaUpdateFunc] = createSignal<() => Promise<void>>(null)
const [pwaUnregisterFuncSignal, setPwaUnregisterFunc] = createSignal<() => Promise<boolean>>(null)
export { pwaReloadFuncSignal, pwaUnregisterFuncSignal, pwaUpdateFuncSignal }

async function registerPeriodicWovinSync(swReg: ServiceWorkerRegistration & { periodicSync?: any }) {
	if (!swReg.periodicSync) return WARN('//TODO firefox friendly way')
	// @ ts-expect-error periodicSync is still experimental *and chromium only
	const registeredSyncTags = await swReg.periodicSync.getTags()
	try {
		await swReg.periodicSync.register('wovin-do-sync', {
			minInterval: 24 * 60 * 60 * 1000,
		})
	} catch (e) {
		console.log('Periodic Sync could not be registered!', e)
	}
}
export const PwaReloadPrompt: Component<DivProps> = (restProps) => {
	// const offlineReady = () => false // (i) for UI testing
	// const needRefresh = () => true
	const [reloadStartTime, setReloadStartTime] = createSignal(null)
	const {
		offlineReady: [offlineReady, setOfflineReady],
		needRefresh: [needRefresh, setNeedRefresh],
		updateServiceWorker,
	} = useRegisterSW({
		onRegisteredSW(swUrl, swReg) {
			LOG('ServiceWorker registered:', swReg)

			// @ts-expect-error
			window.sw = swReg
			// TODO consider https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/updatefound_event
			if (swReg) {
				registerPeriodicWovinSync(swReg)
				setPwaUnregisterFunc(() => () => swReg.unregister())
				setPwaReloadFunc(() => () => swReg.update())
				// FROM: https://vite-pwa-org.netlify.app/guide/periodic-sw-updates.html#handling-edge-cases
				setInterval(async () => {
					VERBOSE('ServiceWorker update check:', { swReg, installing: swReg.installing, onLine: navigator.onLine })
					if (!(!swReg.installing && navigator)) {
						return
					}

					if (('connection' in navigator) && !navigator.onLine) {
						return
					}

					const resp = await fetch(swUrl, {
						cache: 'no-store',
						headers: {
							'cache': 'no-store',
							'cache-control': 'no-cache',
						},
					})
					DEBUG('ServiceWorker update check response:', resp)

					if (resp?.status === 200) {
						LOG('ServiceWorker 200 response:', resp)
						await swReg.update()
					}
				}, (import.meta.env.DEV ? 1 : 5) * 60 * 1000 /* HACK: 5 minute SW update interval during development */)
			}
		},
		onRegisterError(error) {
			ERROR('ServiceWorker registration error', error)
		},
	})
	createEffect(() => {
		setPwaReloadFunc(() => flag => updateServiceWorker(flag))
	})

	const close = () => {
		setOfflineReady(false)
		setNeedRefresh(false)
	}

	const reloadButtonProps = createAsyncButtonHandler(async () => {
		setReloadStartTime(new Date())
		// @ts-expect-error
		const swReg = window.sw
		LOG('Reloading ServiceWorker:', swReg, updateServiceWorker)
		await updateServiceWorker(true)
		LOG('Reloaded ServiceWorker:', swReg)
	})
	DEBUG('ReloadButtonProps:', { reloadButtonProps })
	return (
		<Show when={offlineReady() || needRefresh()}>
			<sl-alert variant='primary' open mt-2 {...restProps}>
				<div flex='~ items-center justify-between gap-2 wrap'>
					<Switch>
						<Match when={offlineReady()}>
							<div flex='~ items-center gap-4'>
								<div flex='shrink-0' w-6 h-6 class='i-ph:download-fill' />
								<strong flex-shrink-0>
									App ready to work offline
								</strong>
							</div>
						</Match>
						<Match when={true}>
							<div flex='~ items-center gap-4'>
								<Iconify flex='shrink-0' size={6} name='shooting-star-fill' />
								<strong flex-shrink-0>
									New app version available
								</strong>
							</div>
						</Match>
					</Switch>

					<div flex='~ items-center' mt-2 text-xs gap-4>
						<Show when={needRefresh()}>
							<sl-button
								size='small'
								variant='primary'
								{...{ ...reloadButtonProps(), loading: reloadButtonProps().loading || reloadStartTime() }}
							>
								<Iconify name='download-fill' slot='prefix' />
								Reload
							</sl-button>
						</Show>
						<sl-button size='small' onClick={() => close()}>
							Close
						</sl-button>
					</div>
				</div>
			</sl-alert>
			{
				/* <div class=''>
					<div class=''>
						<Show
							fallback={<span>New content available, click on reload button to update.</span>}
							when={offlineReady()}
						>
							<span>App ready to work offline</span>
						</Show>
					</div>
					<Show when={needRefresh()}>
						<button class='' onClick={() => updateServiceWorker(true)}>Reload</button>
					</Show>
					<button class='' onClick={() => close()}>Close</button>
				</div> */
			}
		</Show>
	)
}
