/**
 * WordPress dependencies
 */
import { __experimentalText as WCText } from '@wordpress/components';
import { useContext, useEffect, useState, useRef } from '@wordpress/element';
import type { FontFamily, FontFace } from '@wordpress/core-data';

/**
 * Internal dependencies
 */
import { FontLibraryContext } from './context';
import {
	getFacePreviewStyle,
	getFamilyPreviewStyle,
} from './utils/preview-styles';
import type { FontDemoProps } from './types';

function getPreviewUrl( fontFace: FontFace ): string | undefined {
	if ( fontFace.preview ) {
		return fontFace.preview;
	}
	if ( fontFace.src ) {
		return Array.isArray( fontFace.src ) ? fontFace.src[ 0 ] : fontFace.src;
	}
	return undefined;
}

function getDisplayFontFace( font: FontFamily | FontFace ): FontFace {
	// if this IS a font face return it
	if (
		( 'fontStyle' in font && font.fontStyle ) ||
		( 'fontWeight' in font && font.fontWeight )
	) {
		return font;
	}
	// if this is a font family with a collection of font faces
	// return the first one that is normal and 400 OR just the first one
	if ( 'fontFace' in font && font.fontFace && font.fontFace.length ) {
		return (
			font.fontFace.find(
				( face ) =>
					face.fontStyle === 'normal' && face.fontWeight === '400'
			) || font.fontFace[ 0 ]
		);
	}
	// This must be a font family with no font faces
	// return a fake font face
	return {
		fontStyle: 'normal',
		fontWeight: '400',
		fontFamily: font.fontFamily,
	};
}

function FontDemo( { font, text }: FontDemoProps ) {
	const ref = useRef< HTMLDivElement >( null );

	const fontFace = getDisplayFontFace( font );
	const style = getFamilyPreviewStyle( font );
	text = text || ( 'name' in font ? font.name : '' );
	const customPreviewUrl = font.preview;

	const [ isIntersecting, setIsIntersecting ] = useState< boolean >( false );
	const [ isAssetLoaded, setIsAssetLoaded ] = useState< boolean >( false );
	const { loadFontFaceAsset } = useContext( FontLibraryContext );

	const previewUrl = customPreviewUrl ?? getPreviewUrl( fontFace );
	const isPreviewImage =
		previewUrl && previewUrl.match( /\.(png|jpg|jpeg|gif|svg)$/i );

	const faceStyles = getFacePreviewStyle( fontFace );
	const textDemoStyle = {
		fontSize: '18px',
		lineHeight: 1,
		opacity: isAssetLoaded ? '1' : '0',
		...style,
		...faceStyles,
	};

	useEffect( () => {
		const observer = new window.IntersectionObserver( ( [ entry ] ) => {
			setIsIntersecting( entry.isIntersecting );
		}, {} );
		if ( ref.current ) {
			observer.observe( ref.current );
		}
		return () => observer.disconnect();
	}, [ ref ] );

	useEffect( () => {
		const loadAsset = async () => {
			if ( isIntersecting ) {
				if ( ! isPreviewImage && fontFace.src ) {
					await loadFontFaceAsset( fontFace );
				}
				setIsAssetLoaded( true );
			}
		};
		loadAsset();
	}, [ fontFace, isIntersecting, loadFontFaceAsset, isPreviewImage ] );

	return (
		<div ref={ ref }>
			{ isPreviewImage ? (
				<img
					src={ previewUrl }
					loading="lazy"
					alt={ text }
					className="font-library__font-variant_demo-image"
				/>
			) : (
				<WCText
					style={ textDemoStyle }
					className="font-library__font-variant_demo-text"
				>
					{ text }
				</WCText>
			) }
		</div>
	);
}

export default FontDemo;
