// Thin wrapper around the Screen Wake Lock API. Held by the diashow page so a phone
// driving a projector doesn't sleep. No-op on unsupported browsers (Firefox, older
// Safari).
//
// Wake locks die when the document goes hidden; the page re-acquires on visible to
// keep the screen on across short interruptions.

interface SentinelLike {
	release: () => Promise<void>;
	// WakeLockSentinel is an EventTarget; it fires `release` when the lock ends — including
	// when the OS drops it because the tab was hidden.
	addEventListener?: (type: 'release', listener: () => void) => void;
}

type WakeLock = { request: (t: string) => Promise<SentinelLike> };

let sentinel: SentinelLike | null = null;
let visibilityHandler: (() => void) | null = null;

async function request(wakeLock: WakeLock): Promise<void> {
	try {
		sentinel = await wakeLock.request('screen');
		// The OS auto-releases the lock when the tab is hidden. Without clearing our handle
		// on that event, the visibility handler's `sentinel === null` guard would never be
		// true and the lock would never be re-acquired — the screen could then sleep after
		// the first time the tab lost focus. Null it on release so re-acquire can fire.
		sentinel.addEventListener?.('release', () => {
			sentinel = null;
		});
	} catch {
		// User denied, or already released — nothing useful to do.
		sentinel = null;
	}
}

export async function acquireWakeLock(): Promise<void> {
	const wakeLock = (navigator as Navigator & { wakeLock?: WakeLock }).wakeLock;
	if (!wakeLock) return;
	await request(wakeLock);

	// Re-acquire when the page becomes visible again (the OS releases the lock
	// while the tab is hidden).
	if (!visibilityHandler) {
		visibilityHandler = () => {
			if (document.visibilityState === 'visible' && sentinel === null) {
				void request(wakeLock);
			}
		};
		document.addEventListener('visibilitychange', visibilityHandler);
	}
}

export async function releaseWakeLock(): Promise<void> {
	if (sentinel) {
		try {
			await sentinel.release();
		} catch {
			// ignore — release after release is fine
		}
		sentinel = null;
	}
	if (visibilityHandler) {
		document.removeEventListener('visibilitychange', visibilityHandler);
		visibilityHandler = null;
	}
}
