import { useEffect, useRef, useState } from 'react';

import { assignInlineVars } from '@vanilla-extract/dynamic';
import { clsx } from 'clsx';

import { onVisibilityChange } from '#/lib/browser/visibility';
import type { GifEmbedParams } from '#/lib/media/gif-embed';

import { useAutoplayDisabled } from '#/state/preferences/autoplay';

import { PlayButtonIcon } from '#/components/PlayButtonIcon';
import * as Prompt from '#/components/Prompt';
import { Spinner } from '#/components/Spinner';
import { Text } from '#/components/Text';

import { m } from '#/paraglide/messages';

import * as styles from './GifEmbed.css';

export type GifEmbedProps = {
	params: GifEmbedParams;
	thumb: string | null;
	altText: string;
	isPreferredAltText: boolean;
	hideAlt?: boolean;
	className?: string;
};

/** Autoplaying GIF (tenor/klipy), rendered as a muted looping `<video>` with play/pause + GIF/ALT badges. */
export function GifEmbed({ params, thumb, altText, isPreferredAltText, hideAlt, className }: GifEmbedProps) {
	const autoplayDisabled = useAutoplayDisabled();
	const videoRef = useRef<HTMLVideoElement>(null);
	const [isPlaying, setIsPlaying] = useState(!autoplayDisabled);
	const [isLoaded, setIsLoaded] = useState(false);

	// resume playback when the tab returns to the foreground.
	useEffect(() => {
		return onVisibilityChange((visible) => {
			const video = videoRef.current;
			if (visible && !autoplayDisabled && video?.paused) {
				void video.play();
			}
		});
	}, [autoplayDisabled]);

	const onPress = () => {
		const video = videoRef.current;
		if (!video) {
			return;
		}
		if (video.paused) {
			void video.play();
		} else {
			video.pause();
		}
	};

	const aspectRatio = params.dimensions.width / params.dimensions.height;
	const resolvedAlt = !hideAlt && isPreferredAltText ? altText : undefined;

	return (
		<div className={clsx(styles.outer, className)}>
			<div className={styles.box} style={assignInlineVars({ [styles.ratioVar]: String(aspectRatio) })}>
				<div className={styles.inset}>
					{!isPlaying && <div aria-hidden className={styles.dimInner} />}
					<button
						type="button"
						className={styles.playButton}
						aria-label={isPlaying ? m['common.gif.a11y.pause']() : m['common.gif.a11y.play']()}
						onClick={onPress}
					>
						{!isLoaded ? (
							<Spinner label={m['common.gif.loading']()} />
						) : !isPlaying ? (
							<PlayButtonIcon />
						) : null}
					</button>
					<div className={styles.gifBadge}>
						<Text size="xs" weight="bold" className={styles.badgeText}>
							{m['common.gif.label']()}
						</Text>
					</div>
					{resolvedAlt ? <AltBadge text={resolvedAlt} /> : null}
					<video
						ref={videoRef}
						className={styles.video}
						poster={thumb ?? undefined}
						autoPlay={!autoplayDisabled ? true : undefined}
						preload={!autoplayDisabled ? 'auto' : undefined}
						playsInline
						loop
						muted
						aria-label={altText}
						onCanPlay={() => setIsLoaded(true)}
						onPlay={() => setIsPlaying(true)}
						onPause={() => setIsPlaying(false)}
					>
						{params.playerSources.map((source) => (
							<source key={source.src} src={source.src} type={source.type} />
						))}
					</video>
					{!isPlaying && <div aria-hidden className={styles.dimOuter} />}
				</div>
			</div>
		</div>
	);
}

function AltBadge({ text }: { text: string }) {
	const handle = Prompt.usePromptHandle();

	return (
		<>
			<button
				type="button"
				className={styles.altBadge}
				aria-label={m['common.altText.show']()}
				onClick={() => handle.open(null)}
			>
				<Text size="xs" weight="bold" className={styles.badgeText}>
					{m['common.altText.badge']()}
				</Text>
			</button>
			<Prompt.Outer handle={handle}>
				<Prompt.TitleText>{m['common.altText.title']()}</Prompt.TitleText>
				<Prompt.DescriptionText>{text}</Prompt.DescriptionText>
				<Prompt.Actions>
					<Prompt.Action onPress={() => {}} cta={m['common.action.close']()} color="secondary" />
				</Prompt.Actions>
			</Prompt.Outer>
		</>
	);
}
