/**
 * PausedGif — inline GIF preview that stays paused by default and
 * only animates while the mouse is over it. Clicking opens a
 * fullscreen viewer (handled by the parent via `onOpen`) where the
 * browser plays the GIF normally.
 *
 * Trick: the browser decodes GIFs natively whenever an <img> is
 * visible, and there's no way to "pause" a decoded GIF. So we load
 * the GIF into a HTMLImageElement, snapshot frame 0 onto a
 * <canvas>, and show the canvas in the idle state. On hover we
 * swap to the live <img> and the GIF plays. On mouse-leave we flip
 * back to the canvas so it resets to the first frame.
 */
import { useEffect, useRef, useState } from 'react';
import styles from './PausedGif.module.css';

interface PausedGifProps {
	url: string;
	className?: string;
	onOpen?: (url: string) => void;
}

export function PausedGif({ url, className, onOpen }: PausedGifProps) {
	const canvasRef = useRef<HTMLCanvasElement>(null);
	const [loaded, setLoaded] = useState(false);
	const [dims, setDims] = useState<{ w: number; h: number } | null>(null);
	const [hovered, setHovered] = useState(false);
	// `imgKey` is bumped every time we need to re-mount the live
	// <img> so the GIF starts over from frame 0 on each hover.
	// Without this, rapid hover-in / hover-out cycles would pick up
	// wherever the decoder left off.
	const [imgKey, setImgKey] = useState(0);

	useEffect(() => {
		let cancelled = false;
		setLoaded(false);
		setDims(null);
		const img = new Image();
		img.crossOrigin = 'anonymous';
		img.onload = () => {
			if (cancelled) return;
			const w = img.naturalWidth || 400;
			const h = img.naturalHeight || 300;
			setDims({ w, h });
			const canvas = canvasRef.current;
			if (canvas) {
				canvas.width = w;
				canvas.height = h;
				const ctx = canvas.getContext('2d');
				if (ctx) {
					try {
						ctx.drawImage(img, 0, 0, w, h);
					} catch {
						// Cross-origin canvas taint — fall through to
						// the img-only path below. The user still sees
						// the GIF, it just won't be paused-by-default.
					}
				}
			}
			setLoaded(true);
		};
		img.onerror = () => {
			if (cancelled) return;
			setLoaded(true); // Let the <img> path show a broken image
		};
		img.src = url;
		return () => {
			cancelled = true;
		};
	}, [url]);

	const handleClick = (e: React.MouseEvent) => {
		if (onOpen) {
			e.preventDefault();
			e.stopPropagation();
			onOpen(url);
		}
	};

	const handleMouseEnter = () => {
		setHovered(true);
		setImgKey((k) => k + 1);
	};
	const handleMouseLeave = () => setHovered(false);

	return (
		<div
			className={`${styles.wrapper} ${className || ''}`}
			onClick={handleClick}
			onMouseEnter={handleMouseEnter}
			onMouseLeave={handleMouseLeave}
			role={onOpen ? 'button' : undefined}
			tabIndex={onOpen ? 0 : undefined}
			onKeyDown={(e) => {
				if (onOpen && (e.key === 'Enter' || e.key === ' ')) {
					e.preventDefault();
					onOpen(url);
				}
			}}
			style={
				dims
					? { aspectRatio: `${dims.w} / ${dims.h}`, maxWidth: Math.min(dims.w, 400) }
					: undefined
			}
		>
			<canvas
				ref={canvasRef}
				className={styles.canvas}
				style={{ opacity: !hovered && loaded ? 1 : 0 }}
			/>
			{hovered && (
				<img
					key={imgKey}
					src={url}
					alt=""
					className={styles.img}
					draggable={false}
				/>
			)}
			<span className={styles.badge}>GIF</span>
		</div>
	);
}
