/**
 * ScreenSharePreview — renders a local preview of the user's own
 * screen share inside the voice call view. Attaches the LiveKit
 * `screen_share` video publication to a `<video>` element and
 * detaches cleanly when the publication changes or unmounts.
 *
 * Pauses the preview (but keeps the publication running) whenever
 * the browser tab loses focus / becomes hidden, replacing the
 * frame with an overlay that reads "Your stream is still running!
 * We've paused this preview to save your resources." Mirrors the
 * new UI's local preview behaviour exactly.
 */
import { useEffect, useRef, useState } from 'react';
import { useVoice } from '../../contexts/VoiceContext';
import styles from './ScreenSharePreview.module.css';

export function ScreenSharePreview() {
	const voice = useVoice() as any;
	const videoRef = useRef<HTMLVideoElement>(null);
	const [hasTrack, setHasTrack] = useState(false);
	// `paused` is true whenever the tab is hidden or the window has
	// lost focus. We cover the video with an overlay in that state
	// so the user still understands their stream is live.
	const [paused, setPaused] = useState(false);

	// Attach the local screen-share track to our video element. The
	// publication is recreated every time `setScreenShareEnabled(true)`
	// fires, so re-poll after the room reference or the active-channel
	// flag changes.
	useEffect(() => {
		const room = voice?.room;
		const video = videoRef.current;
		if (!room || !video) {
			setHasTrack(false);
			return;
		}
		let attached = false;
		const attach = () => {
			const publications = Array.from(
				room.localParticipant.trackPublications.values(),
			);
			const pub = publications.find(
				(p: any) => p.source === 'screen_share' || p.source === 3,
			) as any;
			const track = pub?.videoTrack;
			if (track && !attached) {
				try {
					track.attach(video);
					attached = true;
					setHasTrack(true);
				} catch {
					setHasTrack(false);
				}
			}
		};
		// Initial attempt + one retry after the next microtask so a
		// freshly-published track has time to land in the map.
		attach();
		const t = window.setTimeout(attach, 250);

		const handleTrackPublished = () => attach();
		const handleTrackUnpublished = (pub: any) => {
			if (pub?.source === 'screen_share' || pub?.source === 3) {
				try {
					pub.videoTrack?.detach(video);
				} catch {
					/* ignore */
				}
				attached = false;
				setHasTrack(false);
			}
		};
		room.localParticipant.on?.('localTrackPublished', handleTrackPublished);
		room.localParticipant.on?.('localTrackUnpublished', handleTrackUnpublished);

		return () => {
			window.clearTimeout(t);
			room.localParticipant.off?.('localTrackPublished', handleTrackPublished);
			room.localParticipant.off?.(
				'localTrackUnpublished',
				handleTrackUnpublished,
			);
			if (attached) {
				const publications = Array.from(
					room.localParticipant.trackPublications.values(),
				);
				const pub = publications.find(
					(p: any) => p.source === 'screen_share' || p.source === 3,
				) as any;
				try {
					pub?.videoTrack?.detach(video);
				} catch {
					/* ignore */
				}
			}
			setHasTrack(false);
		};
	}, [voice?.room, voice?.isScreenSharing, voice?.activeChannelId]);

	// Pause the preview whenever the tab is hidden or the window
	// loses focus. The underlying LiveKit publication keeps running
	// — we just stop painting the video element and show an overlay.
	useEffect(() => {
		const update = () => {
			const hidden =
				document.hidden === true || document.visibilityState === 'hidden';
			const focused = document.hasFocus?.() ?? true;
			setPaused(hidden || !focused);
		};
		update();
		document.addEventListener('visibilitychange', update);
		window.addEventListener('focus', update);
		window.addEventListener('blur', update);
		return () => {
			document.removeEventListener('visibilitychange', update);
			window.removeEventListener('focus', update);
			window.removeEventListener('blur', update);
		};
	}, []);

	// Tell the video element to pause playback while paused so the
	// GPU isn't decoding frames the user isn't looking at.
	useEffect(() => {
		const video = videoRef.current;
		if (!video) return;
		if (paused) {
			try {
				video.pause();
			} catch {
				/* ignore */
			}
		} else {
			try {
				void video.play();
			} catch {
				/* ignore */
			}
		}
	}, [paused]);

	if (!voice?.isScreenSharing) return null;

	return (
		<div className={styles.wrap}>
			<div className={styles.videoFrame}>
				<video
					ref={videoRef}
					className={styles.video}
					autoPlay
					playsInline
					muted
				/>
				{!hasTrack && (
					<div className={styles.placeholder}>
						Starting your stream preview…
					</div>
				)}
				{paused && hasTrack && (
					<div className={styles.pauseOverlay}>
						<div className={styles.pauseTitle}>
							Your stream is still running!
						</div>
						<div className={styles.pauseBody}>
							We've paused this preview to save your resources.
						</div>
					</div>
				)}
			</div>
			<div className={styles.label}>You are live</div>
		</div>
	);
}
